1 /* nautilus-file-undo-operations.c - Manages undo/redo of file operations
2  *
3  * Copyright (C) 2007-2011 Amos Brocco
4  * Copyright (C) 2010, 2012 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Amos Brocco <amos.brocco@gmail.com>
20  *          Cosimo Cecchi <cosimoc@redhat.com>
21  *
22  */
23 
24 #include <stdlib.h>
25 
26 #include "nautilus-file-undo-operations.h"
27 
28 #include <glib/gi18n.h>
29 
30 #include "nautilus-file-operations.h"
31 #include "nautilus-file.h"
32 #include "nautilus-file-undo-manager.h"
33 #include "nautilus-batch-rename-dialog.h"
34 #include "nautilus-batch-rename-utilities.h"
35 #include "nautilus-tag-manager.h"
36 
37 
38 /* Since we use g_get_current_time for setting "orig_trash_time" in the undo
39  * info, there are situations where the difference between this value and the
40  * real deletion time can differ enough to make the rounding a difference of 1
41  * second, failing the equality check. To make sure we avoid this, and to be
42  * preventive, use 2 seconds epsilon.
43  */
44 #define TRASH_TIME_EPSILON 2
45 
46 typedef struct
47 {
48     NautilusFileUndoOp op_type;
49     guint count;                /* Number of items */
50 
51     GTask *apply_async_task;
52 
53     gchar *undo_label;
54     gchar *redo_label;
55     gchar *undo_description;
56     gchar *redo_description;
57 } NautilusFileUndoInfoPrivate;
58 
59 G_DEFINE_TYPE_WITH_PRIVATE (NautilusFileUndoInfo, nautilus_file_undo_info, G_TYPE_OBJECT)
60 
61 enum
62 {
63     PROP_OP_TYPE = 1,
64     PROP_ITEM_COUNT,
65     N_PROPERTIES
66 };
67 
68 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
69 
70 /* description helpers */
71 static void
nautilus_file_undo_info_init(NautilusFileUndoInfo * self)72 nautilus_file_undo_info_init (NautilusFileUndoInfo *self)
73 {
74     NautilusFileUndoInfoPrivate *priv;
75 
76     priv = nautilus_file_undo_info_get_instance_private (self);
77 
78     priv->apply_async_task = NULL;
79 }
80 
81 static void
nautilus_file_undo_info_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)82 nautilus_file_undo_info_get_property (GObject    *object,
83                                       guint       property_id,
84                                       GValue     *value,
85                                       GParamSpec *pspec)
86 {
87     NautilusFileUndoInfo *self;
88     NautilusFileUndoInfoPrivate *priv;
89 
90     self = NAUTILUS_FILE_UNDO_INFO (object);
91     priv = nautilus_file_undo_info_get_instance_private (self);
92 
93     switch (property_id)
94     {
95         case PROP_OP_TYPE:
96         {
97             g_value_set_int (value, priv->op_type);
98         }
99         break;
100 
101         case PROP_ITEM_COUNT:
102         {
103             g_value_set_int (value, priv->count);
104         }
105         break;
106 
107         default:
108         {
109             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
110         }
111         break;
112     }
113 }
114 
115 static void
nautilus_file_undo_info_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)116 nautilus_file_undo_info_set_property (GObject      *object,
117                                       guint         property_id,
118                                       const GValue *value,
119                                       GParamSpec   *pspec)
120 {
121     NautilusFileUndoInfo *self;
122     NautilusFileUndoInfoPrivate *priv;
123 
124     self = NAUTILUS_FILE_UNDO_INFO (object);
125     priv = nautilus_file_undo_info_get_instance_private (self);
126 
127     switch (property_id)
128     {
129         case PROP_OP_TYPE:
130         {
131             priv->op_type = g_value_get_int (value);
132         }
133         break;
134 
135         case PROP_ITEM_COUNT:
136         {
137             priv->count = g_value_get_int (value);
138         }
139         break;
140 
141         default:
142         {
143             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144         }
145         break;
146     }
147 }
148 
149 static void
nautilus_file_redo_info_warn_redo(NautilusFileUndoInfo * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)150 nautilus_file_redo_info_warn_redo (NautilusFileUndoInfo           *self,
151                                    GtkWindow                      *parent_window,
152                                    NautilusFileOperationsDBusData *dbus_data)
153 {
154     g_critical ("Object %p of type %s does not implement redo_func!!",
155                 self, G_OBJECT_TYPE_NAME (self));
156 }
157 
158 static void
nautilus_file_undo_info_warn_undo(NautilusFileUndoInfo * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)159 nautilus_file_undo_info_warn_undo (NautilusFileUndoInfo           *self,
160                                    GtkWindow                      *parent_window,
161                                    NautilusFileOperationsDBusData *dbus_data)
162 {
163     g_critical ("Object %p of type %s does not implement undo_func!!",
164                 self, G_OBJECT_TYPE_NAME (self));
165 }
166 
167 static void
nautilus_file_undo_info_strings_func(NautilusFileUndoInfo * self,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)168 nautilus_file_undo_info_strings_func (NautilusFileUndoInfo  *self,
169                                       gchar                **undo_label,
170                                       gchar                **undo_description,
171                                       gchar                **redo_label,
172                                       gchar                **redo_description)
173 {
174     if (undo_label != NULL)
175     {
176         *undo_label = g_strdup (_("Undo"));
177     }
178     if (undo_description != NULL)
179     {
180         *undo_description = g_strdup (_("Undo last action"));
181     }
182 
183     if (redo_label != NULL)
184     {
185         *redo_label = g_strdup (_("Redo"));
186     }
187     if (redo_description != NULL)
188     {
189         *redo_description = g_strdup (_("Redo last undone action"));
190     }
191 }
192 
193 static void
nautilus_file_undo_info_finalize(GObject * object)194 nautilus_file_undo_info_finalize (GObject *object)
195 {
196     NautilusFileUndoInfo *self;
197     NautilusFileUndoInfoPrivate *priv;
198 
199     self = NAUTILUS_FILE_UNDO_INFO (object);
200     priv = nautilus_file_undo_info_get_instance_private (self);
201 
202     g_clear_object (&priv->apply_async_task);
203 
204     G_OBJECT_CLASS (nautilus_file_undo_info_parent_class)->finalize (object);
205 }
206 
207 static void
nautilus_file_undo_info_class_init(NautilusFileUndoInfoClass * klass)208 nautilus_file_undo_info_class_init (NautilusFileUndoInfoClass *klass)
209 {
210     GObjectClass *oclass = G_OBJECT_CLASS (klass);
211 
212     oclass->finalize = nautilus_file_undo_info_finalize;
213     oclass->get_property = nautilus_file_undo_info_get_property;
214     oclass->set_property = nautilus_file_undo_info_set_property;
215 
216     klass->undo_func = nautilus_file_undo_info_warn_undo;
217     klass->redo_func = nautilus_file_redo_info_warn_redo;
218     klass->strings_func = nautilus_file_undo_info_strings_func;
219 
220     properties[PROP_OP_TYPE] =
221         g_param_spec_int ("op-type",
222                           "Undo info op type",
223                           "Type of undo operation",
224                           0, NAUTILUS_FILE_UNDO_OP_NUM_TYPES - 1, 0,
225                           G_PARAM_READWRITE |
226                           G_PARAM_CONSTRUCT_ONLY);
227     properties[PROP_ITEM_COUNT] =
228         g_param_spec_int ("item-count",
229                           "Number of items",
230                           "Number of items",
231                           0, G_MAXINT, 0,
232                           G_PARAM_READWRITE |
233                           G_PARAM_CONSTRUCT_ONLY);
234 
235     g_object_class_install_properties (oclass, N_PROPERTIES, properties);
236 }
237 
238 NautilusFileUndoOp
nautilus_file_undo_info_get_op_type(NautilusFileUndoInfo * self)239 nautilus_file_undo_info_get_op_type (NautilusFileUndoInfo *self)
240 {
241     NautilusFileUndoInfoPrivate *priv;
242 
243     g_return_val_if_fail (NAUTILUS_IS_FILE_UNDO_INFO (self), NAUTILUS_FILE_UNDO_OP_INVALID);
244 
245     priv = nautilus_file_undo_info_get_instance_private (self);
246 
247     return priv->op_type;
248 }
249 
250 static gint
nautilus_file_undo_info_get_item_count(NautilusFileUndoInfo * self)251 nautilus_file_undo_info_get_item_count (NautilusFileUndoInfo *self)
252 {
253     NautilusFileUndoInfoPrivate *priv;
254 
255     priv = nautilus_file_undo_info_get_instance_private (self);
256 
257     return priv->count;
258 }
259 
260 void
nautilus_file_undo_info_apply_async(NautilusFileUndoInfo * self,gboolean undo,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data,GAsyncReadyCallback callback,gpointer user_data)261 nautilus_file_undo_info_apply_async (NautilusFileUndoInfo           *self,
262                                      gboolean                        undo,
263                                      GtkWindow                      *parent_window,
264                                      NautilusFileOperationsDBusData *dbus_data,
265                                      GAsyncReadyCallback             callback,
266                                      gpointer                        user_data)
267 {
268     NautilusFileUndoInfoPrivate *priv;
269 
270     g_return_if_fail (NAUTILUS_IS_FILE_UNDO_INFO (self));
271 
272     priv = nautilus_file_undo_info_get_instance_private (self);
273 
274     g_assert (priv->apply_async_task == NULL);
275 
276     priv->apply_async_task = g_task_new (G_OBJECT (self),
277                                          NULL,
278                                          callback,
279                                          user_data);
280 
281     if (undo)
282     {
283         NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->undo_func (self,
284                                                                               parent_window,
285                                                                               dbus_data);
286     }
287     else
288     {
289         NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->redo_func (self,
290                                                                               parent_window,
291                                                                               dbus_data);
292     }
293 }
294 
295 typedef struct
296 {
297     gboolean success;
298     gboolean user_cancel;
299 } FileUndoInfoOpRes;
300 
301 static void
file_undo_info_op_res_free(gpointer data)302 file_undo_info_op_res_free (gpointer data)
303 {
304     g_slice_free (FileUndoInfoOpRes, data);
305 }
306 
307 gboolean
nautilus_file_undo_info_apply_finish(NautilusFileUndoInfo * self,GAsyncResult * res,gboolean * user_cancel,GError ** error)308 nautilus_file_undo_info_apply_finish (NautilusFileUndoInfo  *self,
309                                       GAsyncResult          *res,
310                                       gboolean              *user_cancel,
311                                       GError               **error)
312 {
313     FileUndoInfoOpRes *op_res;
314     gboolean success = FALSE;
315 
316     op_res = g_task_propagate_pointer (G_TASK (res), error);
317 
318     if (op_res != NULL)
319     {
320         *user_cancel = op_res->user_cancel;
321         success = op_res->success;
322 
323         file_undo_info_op_res_free (op_res);
324     }
325 
326     return success;
327 }
328 
329 void
nautilus_file_undo_info_get_strings(NautilusFileUndoInfo * self,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)330 nautilus_file_undo_info_get_strings (NautilusFileUndoInfo  *self,
331                                      gchar                **undo_label,
332                                      gchar                **undo_description,
333                                      gchar                **redo_label,
334                                      gchar                **redo_description)
335 {
336     NAUTILUS_FILE_UNDO_INFO_CLASS (G_OBJECT_GET_CLASS (self))->strings_func (self,
337                                                                              undo_label, undo_description,
338                                                                              redo_label, redo_description);
339 }
340 
341 static void
file_undo_info_complete_apply(NautilusFileUndoInfo * self,gboolean success,gboolean user_cancel)342 file_undo_info_complete_apply (NautilusFileUndoInfo *self,
343                                gboolean              success,
344                                gboolean              user_cancel)
345 {
346     NautilusFileUndoInfoPrivate *priv;
347     FileUndoInfoOpRes *op_res;
348 
349     priv = nautilus_file_undo_info_get_instance_private (self);
350     op_res = g_slice_new0 (FileUndoInfoOpRes);
351 
352     op_res->user_cancel = user_cancel;
353     op_res->success = success;
354 
355     g_task_return_pointer (priv->apply_async_task, op_res,
356                            file_undo_info_op_res_free);
357 
358     g_clear_object (&priv->apply_async_task);
359 }
360 
361 static void
file_undo_info_transfer_callback(GHashTable * debuting_uris,gboolean success,gpointer user_data)362 file_undo_info_transfer_callback (GHashTable *debuting_uris,
363                                   gboolean    success,
364                                   gpointer    user_data)
365 {
366     NautilusFileUndoInfo *self = user_data;
367 
368     /* TODO: we need to forward the cancelled state from
369      * the file operation to the file undo info object.
370      */
371     file_undo_info_complete_apply (self, success, FALSE);
372 }
373 
374 static void
file_undo_info_operation_callback(NautilusFile * file,GFile * result_location,GError * error,gpointer user_data)375 file_undo_info_operation_callback (NautilusFile *file,
376                                    GFile        *result_location,
377                                    GError       *error,
378                                    gpointer      user_data)
379 {
380     NautilusFileUndoInfo *self = user_data;
381 
382     file_undo_info_complete_apply (self, (error == NULL),
383                                    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED));
384 }
385 
386 static void
file_undo_info_delete_callback(GHashTable * debuting_uris,gboolean user_cancel,gpointer user_data)387 file_undo_info_delete_callback (GHashTable *debuting_uris,
388                                 gboolean    user_cancel,
389                                 gpointer    user_data)
390 {
391     NautilusFileUndoInfo *self = user_data;
392 
393     file_undo_info_complete_apply (self,
394                                    !user_cancel,
395                                    user_cancel);
396 }
397 
398 /* copy/move/duplicate/link/restore from trash */
399 struct _NautilusFileUndoInfoExt
400 {
401     NautilusFileUndoInfo parent_instance;
402 
403     GFile *src_dir;
404     GFile *dest_dir;
405     GQueue *sources;          /* Relative to src_dir */
406     GQueue *destinations;     /* Relative to dest_dir */
407 };
408 
G_DEFINE_TYPE(NautilusFileUndoInfoExt,nautilus_file_undo_info_ext,NAUTILUS_TYPE_FILE_UNDO_INFO)409 G_DEFINE_TYPE (NautilusFileUndoInfoExt, nautilus_file_undo_info_ext, NAUTILUS_TYPE_FILE_UNDO_INFO)
410 
411 static char *
412 ext_get_first_target_short_name (NautilusFileUndoInfoExt *self)
413 {
414     GList *targets_first;
415     char *file_name = NULL;
416 
417     targets_first = g_queue_peek_head_link (self->destinations);
418 
419     if (targets_first != NULL &&
420         targets_first->data != NULL)
421     {
422         file_name = g_file_get_basename (targets_first->data);
423     }
424 
425     return file_name;
426 }
427 
428 static void
ext_strings_func(NautilusFileUndoInfo * info,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)429 ext_strings_func (NautilusFileUndoInfo  *info,
430                   gchar                **undo_label,
431                   gchar                **undo_description,
432                   gchar                **redo_label,
433                   gchar                **redo_description)
434 {
435     NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
436     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
437     gint count = nautilus_file_undo_info_get_item_count (info);
438     gchar *name = NULL, *source, *destination;
439 
440     source = g_file_get_path (self->src_dir);
441     destination = g_file_get_path (self->dest_dir);
442 
443     if (count <= 1)
444     {
445         name = ext_get_first_target_short_name (self);
446     }
447 
448     if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE)
449     {
450         if (count > 1)
451         {
452             *undo_description = g_strdup_printf (ngettext ("Move %d item back to “%s”",
453                                                            "Move %d items back to “%s”", count),
454                                                  count, source);
455             *redo_description = g_strdup_printf (ngettext ("Move %d item to “%s”",
456                                                            "Move %d items to “%s”", count),
457                                                  count, destination);
458 
459             *undo_label = g_strdup_printf (ngettext ("_Undo Move %d item",
460                                                      "_Undo Move %d items", count),
461                                            count);
462             *redo_label = g_strdup_printf (ngettext ("_Redo Move %d item",
463                                                      "_Redo Move %d items", count),
464                                            count);
465         }
466         else
467         {
468             *undo_description = g_strdup_printf (_("Move “%s” back to “%s”"), name, source);
469             *redo_description = g_strdup_printf (_("Move “%s” to “%s”"), name, destination);
470 
471             *undo_label = g_strdup (_("_Undo Move"));
472             *redo_label = g_strdup (_("_Redo Move"));
473         }
474     }
475     else if (op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
476     {
477         *undo_label = g_strdup (_("_Undo Restore from Trash"));
478         *redo_label = g_strdup (_("_Redo Restore from Trash"));
479 
480         if (count > 1)
481         {
482             *undo_description = g_strdup_printf (ngettext ("Move %d item back to trash",
483                                                            "Move %d items back to trash", count),
484                                                  count);
485             *redo_description = g_strdup_printf (ngettext ("Restore %d item from trash",
486                                                            "Restore %d items from trash", count),
487                                                  count);
488         }
489         else
490         {
491             *undo_description = g_strdup_printf (_("Move “%s” back to trash"), name);
492             *redo_description = g_strdup_printf (_("Restore “%s” from trash"), name);
493         }
494     }
495     else if (op_type == NAUTILUS_FILE_UNDO_OP_COPY)
496     {
497         if (count > 1)
498         {
499             *undo_description = g_strdup_printf (ngettext ("Delete %d copied item",
500                                                            "Delete %d copied items", count),
501                                                  count);
502             *redo_description = g_strdup_printf (ngettext ("Copy %d item to “%s”",
503                                                            "Copy %d items to “%s”", count),
504                                                  count, destination);
505 
506             *undo_label = g_strdup_printf (ngettext ("_Undo Copy %d item",
507                                                      "_Undo Copy %d items", count),
508                                            count);
509             *redo_label = g_strdup_printf (ngettext ("_Redo Copy %d item",
510                                                      "_Redo Copy %d items", count),
511                                            count);
512         }
513         else
514         {
515             *undo_description = g_strdup_printf (_("Delete “%s”"), name);
516             *redo_description = g_strdup_printf (_("Copy “%s” to “%s”"), name, destination);
517 
518             *undo_label = g_strdup (_("_Undo Copy"));
519             *redo_label = g_strdup (_("_Redo Copy"));
520         }
521     }
522     else if (op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE)
523     {
524         if (count > 1)
525         {
526             *undo_description = g_strdup_printf (ngettext ("Delete %d duplicated item",
527                                                            "Delete %d duplicated items", count),
528                                                  count);
529             *redo_description = g_strdup_printf (ngettext ("Duplicate %d item in “%s”",
530                                                            "Duplicate %d items in “%s”", count),
531                                                  count, destination);
532 
533             *undo_label = g_strdup_printf (ngettext ("_Undo Duplicate %d item",
534                                                      "_Undo Duplicate %d items", count),
535                                            count);
536             *redo_label = g_strdup_printf (ngettext ("_Redo Duplicate %d item",
537                                                      "_Redo Duplicate %d items", count),
538                                            count);
539         }
540         else
541         {
542             *undo_description = g_strdup_printf (_("Delete “%s”"), name);
543             *redo_description = g_strdup_printf (_("Duplicate “%s” in “%s”"),
544                                                  name, destination);
545 
546             *undo_label = g_strdup (_("_Undo Duplicate"));
547             *redo_label = g_strdup (_("_Redo Duplicate"));
548         }
549     }
550     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
551     {
552         if (count > 1)
553         {
554             *undo_description = g_strdup_printf (ngettext ("Delete links to %d item",
555                                                            "Delete links to %d items", count),
556                                                  count);
557             *redo_description = g_strdup_printf (ngettext ("Create links to %d item",
558                                                            "Create links to %d items", count),
559                                                  count);
560         }
561         else
562         {
563             *undo_description = g_strdup_printf (_("Delete link to “%s”"), name);
564             *redo_description = g_strdup_printf (_("Create link to “%s”"), name);
565 
566             *undo_label = g_strdup (_("_Undo Create Link"));
567             *redo_label = g_strdup (_("_Redo Create Link"));
568         }
569     }
570     else
571     {
572         g_assert_not_reached ();
573     }
574 
575     g_free (name);
576     g_free (source);
577     g_free (destination);
578 }
579 
580 static void
ext_create_link_redo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)581 ext_create_link_redo_func (NautilusFileUndoInfoExt        *self,
582                            GtkWindow                      *parent_window,
583                            NautilusFileOperationsDBusData *dbus_data)
584 {
585     nautilus_file_operations_link (g_queue_peek_head_link (self->sources),
586                                    self->dest_dir,
587                                    parent_window,
588                                    dbus_data,
589                                    file_undo_info_transfer_callback,
590                                    self);
591 }
592 
593 static void
ext_duplicate_redo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)594 ext_duplicate_redo_func (NautilusFileUndoInfoExt        *self,
595                          GtkWindow                      *parent_window,
596                          NautilusFileOperationsDBusData *dbus_data)
597 {
598     nautilus_file_operations_duplicate (g_queue_peek_head_link (self->sources),
599                                         parent_window,
600                                         dbus_data,
601                                         file_undo_info_transfer_callback,
602                                         self);
603 }
604 
605 static void
ext_copy_redo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)606 ext_copy_redo_func (NautilusFileUndoInfoExt        *self,
607                     GtkWindow                      *parent_window,
608                     NautilusFileOperationsDBusData *dbus_data)
609 {
610     nautilus_file_operations_copy_async (g_queue_peek_head_link (self->sources),
611                                          self->dest_dir,
612                                          parent_window,
613                                          dbus_data,
614                                          file_undo_info_transfer_callback,
615                                          self);
616 }
617 
618 static void
ext_move_restore_redo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)619 ext_move_restore_redo_func (NautilusFileUndoInfoExt        *self,
620                             GtkWindow                      *parent_window,
621                             NautilusFileOperationsDBusData *dbus_data)
622 {
623     nautilus_file_operations_move_async (g_queue_peek_head_link (self->sources),
624                                          self->dest_dir,
625                                          parent_window,
626                                          dbus_data,
627                                          file_undo_info_transfer_callback,
628                                          self);
629 }
630 
631 static void
ext_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)632 ext_redo_func (NautilusFileUndoInfo           *info,
633                GtkWindow                      *parent_window,
634                NautilusFileOperationsDBusData *dbus_data)
635 {
636     NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
637     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
638 
639     if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE ||
640         op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
641     {
642         ext_move_restore_redo_func (self, parent_window, dbus_data);
643     }
644     else if (op_type == NAUTILUS_FILE_UNDO_OP_COPY)
645     {
646         ext_copy_redo_func (self, parent_window, dbus_data);
647     }
648     else if (op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE)
649     {
650         ext_duplicate_redo_func (self, parent_window, dbus_data);
651     }
652     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
653     {
654         ext_create_link_redo_func (self, parent_window, dbus_data);
655     }
656     else
657     {
658         g_assert_not_reached ();
659     }
660 }
661 
662 static void
ext_restore_undo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)663 ext_restore_undo_func (NautilusFileUndoInfoExt        *self,
664                        GtkWindow                      *parent_window,
665                        NautilusFileOperationsDBusData *dbus_data)
666 {
667     nautilus_file_operations_trash_or_delete_async (g_queue_peek_head_link (self->destinations),
668                                                     parent_window,
669                                                     dbus_data,
670                                                     file_undo_info_delete_callback,
671                                                     self);
672 }
673 
674 
675 static void
ext_move_undo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)676 ext_move_undo_func (NautilusFileUndoInfoExt        *self,
677                     GtkWindow                      *parent_window,
678                     NautilusFileOperationsDBusData *dbus_data)
679 {
680     nautilus_file_operations_move_async (g_queue_peek_head_link (self->destinations),
681                                          self->src_dir,
682                                          parent_window,
683                                          dbus_data,
684                                          file_undo_info_transfer_callback,
685                                          self);
686 }
687 
688 static void
ext_copy_duplicate_undo_func(NautilusFileUndoInfoExt * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)689 ext_copy_duplicate_undo_func (NautilusFileUndoInfoExt        *self,
690                               GtkWindow                      *parent_window,
691                               NautilusFileOperationsDBusData *dbus_data)
692 {
693     GList *files;
694 
695     files = g_list_copy (g_queue_peek_head_link (self->destinations));
696     files = g_list_reverse (files);     /* Deleting must be done in reverse */
697 
698     nautilus_file_operations_delete_async (files, parent_window,
699                                            dbus_data,
700                                            file_undo_info_delete_callback, self);
701 
702     g_list_free (files);
703 }
704 
705 static void
ext_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)706 ext_undo_func (NautilusFileUndoInfo           *info,
707                GtkWindow                      *parent_window,
708                NautilusFileOperationsDBusData *dbus_data)
709 {
710     NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (info);
711     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
712 
713     if (op_type == NAUTILUS_FILE_UNDO_OP_COPY ||
714         op_type == NAUTILUS_FILE_UNDO_OP_DUPLICATE ||
715         op_type == NAUTILUS_FILE_UNDO_OP_CREATE_LINK)
716     {
717         ext_copy_duplicate_undo_func (self, parent_window, dbus_data);
718     }
719     else if (op_type == NAUTILUS_FILE_UNDO_OP_MOVE)
720     {
721         ext_move_undo_func (self, parent_window, dbus_data);
722     }
723     else if (op_type == NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH)
724     {
725         ext_restore_undo_func (self, parent_window, dbus_data);
726     }
727     else
728     {
729         g_assert_not_reached ();
730     }
731 }
732 
733 static void
nautilus_file_undo_info_ext_init(NautilusFileUndoInfoExt * self)734 nautilus_file_undo_info_ext_init (NautilusFileUndoInfoExt *self)
735 {
736 }
737 
738 static void
nautilus_file_undo_info_ext_finalize(GObject * obj)739 nautilus_file_undo_info_ext_finalize (GObject *obj)
740 {
741     NautilusFileUndoInfoExt *self = NAUTILUS_FILE_UNDO_INFO_EXT (obj);
742 
743     if (self->sources)
744     {
745         g_queue_free_full (self->sources, g_object_unref);
746     }
747 
748     if (self->destinations)
749     {
750         g_queue_free_full (self->destinations, g_object_unref);
751     }
752 
753     g_clear_object (&self->src_dir);
754     g_clear_object (&self->dest_dir);
755 
756     G_OBJECT_CLASS (nautilus_file_undo_info_ext_parent_class)->finalize (obj);
757 }
758 
759 static void
nautilus_file_undo_info_ext_class_init(NautilusFileUndoInfoExtClass * klass)760 nautilus_file_undo_info_ext_class_init (NautilusFileUndoInfoExtClass *klass)
761 {
762     GObjectClass *oclass = G_OBJECT_CLASS (klass);
763     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
764 
765     oclass->finalize = nautilus_file_undo_info_ext_finalize;
766 
767     iclass->undo_func = ext_undo_func;
768     iclass->redo_func = ext_redo_func;
769     iclass->strings_func = ext_strings_func;
770 }
771 
772 NautilusFileUndoInfo *
nautilus_file_undo_info_ext_new(NautilusFileUndoOp op_type,gint item_count,GFile * src_dir,GFile * target_dir)773 nautilus_file_undo_info_ext_new (NautilusFileUndoOp  op_type,
774                                  gint                item_count,
775                                  GFile              *src_dir,
776                                  GFile              *target_dir)
777 {
778     NautilusFileUndoInfoExt *self;
779 
780     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_EXT,
781                          "op-type", op_type,
782                          "item-count", item_count,
783                          NULL);
784 
785     self->src_dir = g_object_ref (src_dir);
786     self->dest_dir = g_object_ref (target_dir);
787     self->sources = g_queue_new ();
788     self->destinations = g_queue_new ();
789 
790     return NAUTILUS_FILE_UNDO_INFO (self);
791 }
792 
793 void
nautilus_file_undo_info_ext_add_origin_target_pair(NautilusFileUndoInfoExt * self,GFile * origin,GFile * target)794 nautilus_file_undo_info_ext_add_origin_target_pair (NautilusFileUndoInfoExt *self,
795                                                     GFile                   *origin,
796                                                     GFile                   *target)
797 {
798     g_queue_push_tail (self->sources, g_object_ref (origin));
799     g_queue_push_tail (self->destinations, g_object_ref (target));
800 }
801 
802 /* create new file/folder */
803 struct _NautilusFileUndoInfoCreate
804 {
805     NautilusFileUndoInfo parent_instance;
806 
807     char *template;
808     GFile *target_file;
809     gint length;
810 };
811 
G_DEFINE_TYPE(NautilusFileUndoInfoCreate,nautilus_file_undo_info_create,NAUTILUS_TYPE_FILE_UNDO_INFO)812 G_DEFINE_TYPE (NautilusFileUndoInfoCreate, nautilus_file_undo_info_create, NAUTILUS_TYPE_FILE_UNDO_INFO)
813 
814 static void
815 create_strings_func (NautilusFileUndoInfo  *info,
816                      gchar                **undo_label,
817                      gchar                **undo_description,
818                      gchar                **redo_label,
819                      gchar                **redo_description)
820 {
821     NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
822     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
823     char *name;
824 
825     name = g_file_get_parse_name (self->target_file);
826     *undo_description = g_strdup_printf (_("Delete “%s”"), name);
827 
828     if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE)
829     {
830         *redo_description = g_strdup_printf (_("Create an empty file “%s”"), name);
831 
832         *undo_label = g_strdup (_("_Undo Create Empty File"));
833         *redo_label = g_strdup (_("_Redo Create Empty File"));
834     }
835     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER)
836     {
837         *redo_description = g_strdup_printf (_("Create a new folder “%s”"), name);
838 
839         *undo_label = g_strdup (_("_Undo Create Folder"));
840         *redo_label = g_strdup (_("_Redo Create Folder"));
841     }
842     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE)
843     {
844         *redo_description = g_strdup_printf (_("Create new file “%s” from template "), name);
845 
846         *undo_label = g_strdup (_("_Undo Create from Template"));
847         *redo_label = g_strdup (_("_Redo Create from Template"));
848     }
849     else
850     {
851         g_assert_not_reached ();
852     }
853 
854     g_free (name);
855 }
856 
857 static void
create_callback(GFile * new_file,gboolean success,gpointer callback_data)858 create_callback (GFile    *new_file,
859                  gboolean  success,
860                  gpointer  callback_data)
861 {
862     file_undo_info_transfer_callback (NULL, success, callback_data);
863 }
864 
865 static void
create_from_template_redo_func(NautilusFileUndoInfoCreate * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)866 create_from_template_redo_func (NautilusFileUndoInfoCreate     *self,
867                                 GtkWindow                      *parent_window,
868                                 NautilusFileOperationsDBusData *dbus_data)
869 {
870     GFile *parent;
871     gchar *parent_uri, *new_name;
872 
873     parent = g_file_get_parent (self->target_file);
874     parent_uri = g_file_get_uri (parent);
875     new_name = g_file_get_parse_name (self->target_file);
876     nautilus_file_operations_new_file_from_template (NULL,
877                                                      parent_uri, new_name,
878                                                      self->template,
879                                                      create_callback, self);
880 
881     g_free (parent_uri);
882     g_free (new_name);
883     g_object_unref (parent);
884 }
885 
886 static void
create_folder_redo_func(NautilusFileUndoInfoCreate * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)887 create_folder_redo_func (NautilusFileUndoInfoCreate     *self,
888                          GtkWindow                      *parent_window,
889                          NautilusFileOperationsDBusData *dbus_data)
890 {
891     GFile *parent;
892     gchar *parent_uri;
893     gchar *name;
894 
895     name = g_file_get_basename (self->target_file);
896     parent = g_file_get_parent (self->target_file);
897     parent_uri = g_file_get_uri (parent);
898     nautilus_file_operations_new_folder (NULL,
899                                          dbus_data,
900                                          parent_uri, name,
901                                          create_callback, self);
902 
903     g_free (name);
904     g_free (parent_uri);
905     g_object_unref (parent);
906 }
907 
908 static void
create_empty_redo_func(NautilusFileUndoInfoCreate * self,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)909 create_empty_redo_func (NautilusFileUndoInfoCreate     *self,
910                         GtkWindow                      *parent_window,
911                         NautilusFileOperationsDBusData *dbus_data)
912 {
913     GFile *parent;
914     gchar *parent_uri;
915     gchar *new_name;
916 
917     parent = g_file_get_parent (self->target_file);
918     parent_uri = g_file_get_uri (parent);
919     new_name = g_file_get_parse_name (self->target_file);
920     nautilus_file_operations_new_file (NULL, parent_uri,
921                                        new_name,
922                                        self->template,
923                                        self->length,
924                                        create_callback, self);
925 
926     g_free (parent_uri);
927     g_free (new_name);
928     g_object_unref (parent);
929 }
930 
931 static void
create_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)932 create_redo_func (NautilusFileUndoInfo           *info,
933                   GtkWindow                      *parent_window,
934                   NautilusFileOperationsDBusData *dbus_data)
935 {
936     NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
937     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
938 
939     if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE)
940     {
941         create_empty_redo_func (self, parent_window, dbus_data);
942     }
943     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER)
944     {
945         create_folder_redo_func (self, parent_window, dbus_data);
946     }
947     else if (op_type == NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE)
948     {
949         create_from_template_redo_func (self, parent_window, dbus_data);
950     }
951     else
952     {
953         g_assert_not_reached ();
954     }
955 }
956 
957 static void
create_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)958 create_undo_func (NautilusFileUndoInfo           *info,
959                   GtkWindow                      *parent_window,
960                   NautilusFileOperationsDBusData *dbus_data)
961 {
962     NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (info);
963     GList *files = NULL;
964 
965     files = g_list_append (files, g_object_ref (self->target_file));
966     nautilus_file_operations_delete_async (files, parent_window,
967                                            dbus_data,
968                                            file_undo_info_delete_callback, self);
969 
970     g_list_free_full (files, g_object_unref);
971 }
972 
973 static void
nautilus_file_undo_info_create_init(NautilusFileUndoInfoCreate * self)974 nautilus_file_undo_info_create_init (NautilusFileUndoInfoCreate *self)
975 {
976 }
977 
978 static void
nautilus_file_undo_info_create_finalize(GObject * obj)979 nautilus_file_undo_info_create_finalize (GObject *obj)
980 {
981     NautilusFileUndoInfoCreate *self = NAUTILUS_FILE_UNDO_INFO_CREATE (obj);
982     g_clear_object (&self->target_file);
983     g_free (self->template);
984 
985     G_OBJECT_CLASS (nautilus_file_undo_info_create_parent_class)->finalize (obj);
986 }
987 
988 static void
nautilus_file_undo_info_create_class_init(NautilusFileUndoInfoCreateClass * klass)989 nautilus_file_undo_info_create_class_init (NautilusFileUndoInfoCreateClass *klass)
990 {
991     GObjectClass *oclass = G_OBJECT_CLASS (klass);
992     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
993 
994     oclass->finalize = nautilus_file_undo_info_create_finalize;
995 
996     iclass->undo_func = create_undo_func;
997     iclass->redo_func = create_redo_func;
998     iclass->strings_func = create_strings_func;
999 }
1000 
1001 NautilusFileUndoInfo *
nautilus_file_undo_info_create_new(NautilusFileUndoOp op_type)1002 nautilus_file_undo_info_create_new (NautilusFileUndoOp op_type)
1003 {
1004     return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_CREATE,
1005                          "op-type", op_type,
1006                          "item-count", 1,
1007                          NULL);
1008 }
1009 
1010 void
nautilus_file_undo_info_create_set_data(NautilusFileUndoInfoCreate * self,GFile * file,const char * template,gint length)1011 nautilus_file_undo_info_create_set_data (NautilusFileUndoInfoCreate *self,
1012                                          GFile                      *file,
1013                                          const char                 *template,
1014                                          gint                        length)
1015 {
1016     self->target_file = g_object_ref (file);
1017     self->template = g_strdup (template);
1018     self->length = length;
1019 }
1020 
1021 /* rename */
1022 struct _NautilusFileUndoInfoRename
1023 {
1024     NautilusFileUndoInfo parent_instance;
1025 
1026     GFile *old_file;
1027     GFile *new_file;
1028     gchar *old_display_name;
1029     gchar *new_display_name;
1030 };
1031 
G_DEFINE_TYPE(NautilusFileUndoInfoRename,nautilus_file_undo_info_rename,NAUTILUS_TYPE_FILE_UNDO_INFO)1032 G_DEFINE_TYPE (NautilusFileUndoInfoRename, nautilus_file_undo_info_rename, NAUTILUS_TYPE_FILE_UNDO_INFO)
1033 
1034 static void
1035 rename_strings_func (NautilusFileUndoInfo  *info,
1036                      gchar                **undo_label,
1037                      gchar                **undo_description,
1038                      gchar                **redo_label,
1039                      gchar                **redo_description)
1040 {
1041     NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
1042     gchar *new_name, *old_name;
1043 
1044     new_name = g_file_get_parse_name (self->new_file);
1045     old_name = g_file_get_parse_name (self->old_file);
1046 
1047     *undo_description = g_strdup_printf (_("Rename “%s” as “%s”"), new_name, old_name);
1048     *redo_description = g_strdup_printf (_("Rename “%s” as “%s”"), old_name, new_name);
1049 
1050     *undo_label = g_strdup (_("_Undo Rename"));
1051     *redo_label = g_strdup (_("_Redo Rename"));
1052 
1053     g_free (old_name);
1054     g_free (new_name);
1055 }
1056 
1057 static void
rename_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1058 rename_redo_func (NautilusFileUndoInfo           *info,
1059                   GtkWindow                      *parent_window,
1060                   NautilusFileOperationsDBusData *dbus_data)
1061 {
1062     NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
1063     NautilusFile *file;
1064 
1065     file = nautilus_file_get (self->old_file);
1066     nautilus_file_rename (file, self->new_display_name,
1067                           file_undo_info_operation_callback, self);
1068 
1069     nautilus_file_unref (file);
1070 }
1071 
1072 static void
rename_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1073 rename_undo_func (NautilusFileUndoInfo           *info,
1074                   GtkWindow                      *parent_window,
1075                   NautilusFileOperationsDBusData *dbus_data)
1076 {
1077     NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (info);
1078     NautilusFile *file;
1079 
1080     file = nautilus_file_get (self->new_file);
1081     nautilus_file_rename (file, self->old_display_name,
1082                           file_undo_info_operation_callback, self);
1083 
1084     nautilus_file_unref (file);
1085 }
1086 
1087 static void
nautilus_file_undo_info_rename_init(NautilusFileUndoInfoRename * self)1088 nautilus_file_undo_info_rename_init (NautilusFileUndoInfoRename *self)
1089 {
1090 }
1091 
1092 static void
nautilus_file_undo_info_rename_finalize(GObject * obj)1093 nautilus_file_undo_info_rename_finalize (GObject *obj)
1094 {
1095     NautilusFileUndoInfoRename *self = NAUTILUS_FILE_UNDO_INFO_RENAME (obj);
1096     g_clear_object (&self->old_file);
1097     g_clear_object (&self->new_file);
1098     g_free (self->old_display_name);
1099     g_free (self->new_display_name);
1100 
1101     G_OBJECT_CLASS (nautilus_file_undo_info_rename_parent_class)->finalize (obj);
1102 }
1103 
1104 static void
nautilus_file_undo_info_rename_class_init(NautilusFileUndoInfoRenameClass * klass)1105 nautilus_file_undo_info_rename_class_init (NautilusFileUndoInfoRenameClass *klass)
1106 {
1107     GObjectClass *oclass = G_OBJECT_CLASS (klass);
1108     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
1109 
1110     oclass->finalize = nautilus_file_undo_info_rename_finalize;
1111 
1112     iclass->undo_func = rename_undo_func;
1113     iclass->redo_func = rename_redo_func;
1114     iclass->strings_func = rename_strings_func;
1115 }
1116 
1117 NautilusFileUndoInfo *
nautilus_file_undo_info_rename_new(void)1118 nautilus_file_undo_info_rename_new (void)
1119 {
1120     return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_RENAME,
1121                          "op-type", NAUTILUS_FILE_UNDO_OP_RENAME,
1122                          "item-count", 1,
1123                          NULL);
1124 }
1125 
1126 void
nautilus_file_undo_info_rename_set_data_pre(NautilusFileUndoInfoRename * self,GFile * old_file,gchar * old_display_name,gchar * new_display_name)1127 nautilus_file_undo_info_rename_set_data_pre (NautilusFileUndoInfoRename *self,
1128                                              GFile                      *old_file,
1129                                              gchar                      *old_display_name,
1130                                              gchar                      *new_display_name)
1131 {
1132     self->old_file = g_object_ref (old_file);
1133     self->old_display_name = g_strdup (old_display_name);
1134     self->new_display_name = g_strdup (new_display_name);
1135 }
1136 
1137 void
nautilus_file_undo_info_rename_set_data_post(NautilusFileUndoInfoRename * self,GFile * new_file)1138 nautilus_file_undo_info_rename_set_data_post (NautilusFileUndoInfoRename *self,
1139                                               GFile                      *new_file)
1140 {
1141     self->new_file = g_object_ref (new_file);
1142 }
1143 
1144 /* batch rename */
1145 struct _NautilusFileUndoInfoBatchRename
1146 {
1147     NautilusFileUndoInfo parent_instance;
1148 
1149     GList *old_files;
1150     GList *new_files;
1151     GList *old_display_names;
1152     GList *new_display_names;
1153 };
1154 
1155 G_DEFINE_TYPE (NautilusFileUndoInfoBatchRename, nautilus_file_undo_info_batch_rename, NAUTILUS_TYPE_FILE_UNDO_INFO);
1156 
1157 static void
batch_rename_strings_func(NautilusFileUndoInfo * info,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)1158 batch_rename_strings_func (NautilusFileUndoInfo  *info,
1159                            gchar                **undo_label,
1160                            gchar                **undo_description,
1161                            gchar                **redo_label,
1162                            gchar                **redo_description)
1163 {
1164     NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
1165 
1166     *undo_description = g_strdup_printf (ngettext ("Batch rename %d file",
1167                                                    "Batch rename %d files",
1168                                                    g_list_length (self->new_files)),
1169                                          g_list_length (self->new_files));
1170     *redo_description = g_strdup_printf (ngettext ("Batch rename %d file",
1171                                                    "Batch rename %d files",
1172                                                    g_list_length (self->new_files)),
1173                                          g_list_length (self->new_files));
1174 
1175     *undo_label = g_strdup (_("_Undo Batch Rename"));
1176     *redo_label = g_strdup (_("_Redo Batch Rename"));
1177 }
1178 
1179 static void
batch_rename_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1180 batch_rename_redo_func (NautilusFileUndoInfo           *info,
1181                         GtkWindow                      *parent_window,
1182                         NautilusFileOperationsDBusData *dbus_data)
1183 {
1184     NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
1185 
1186     GList *l, *files;
1187     NautilusFile *file;
1188     GFile *old_file;
1189 
1190     files = NULL;
1191 
1192     for (l = self->old_files; l != NULL; l = l->next)
1193     {
1194         old_file = l->data;
1195 
1196         file = nautilus_file_get (old_file);
1197         files = g_list_prepend (files, file);
1198     }
1199 
1200     files = g_list_reverse (files);
1201 
1202     batch_rename_sort_lists_for_rename (&files,
1203                                         &self->new_display_names,
1204                                         &self->old_display_names,
1205                                         &self->new_files,
1206                                         &self->old_files,
1207                                         TRUE);
1208 
1209     nautilus_file_batch_rename (files, self->new_display_names, file_undo_info_operation_callback, self);
1210 }
1211 
1212 static void
batch_rename_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1213 batch_rename_undo_func (NautilusFileUndoInfo           *info,
1214                         GtkWindow                      *parent_window,
1215                         NautilusFileOperationsDBusData *dbus_data)
1216 {
1217     NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
1218 
1219     GList *l, *files;
1220     NautilusFile *file;
1221     GFile *new_file;
1222 
1223     files = NULL;
1224 
1225     for (l = self->new_files; l != NULL; l = l->next)
1226     {
1227         new_file = l->data;
1228 
1229         file = nautilus_file_get (new_file);
1230         files = g_list_prepend (files, file);
1231     }
1232 
1233     files = g_list_reverse (files);
1234 
1235     batch_rename_sort_lists_for_rename (&files,
1236                                         &self->old_display_names,
1237                                         &self->new_display_names,
1238                                         &self->old_files,
1239                                         &self->new_files,
1240                                         TRUE);
1241 
1242     nautilus_file_batch_rename (files, self->old_display_names, file_undo_info_operation_callback, self);
1243 }
1244 
1245 static void
nautilus_file_undo_info_batch_rename_init(NautilusFileUndoInfoBatchRename * self)1246 nautilus_file_undo_info_batch_rename_init (NautilusFileUndoInfoBatchRename *self)
1247 {
1248 }
1249 
1250 static void
nautilus_file_undo_info_batch_rename_finalize(GObject * obj)1251 nautilus_file_undo_info_batch_rename_finalize (GObject *obj)
1252 {
1253     GList *l;
1254     GFile *file;
1255     GString *string;
1256     NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (obj);
1257 
1258     for (l = self->new_files; l != NULL; l = l->next)
1259     {
1260         file = l->data;
1261 
1262         g_clear_object (&file);
1263     }
1264 
1265     for (l = self->old_files; l != NULL; l = l->next)
1266     {
1267         file = l->data;
1268 
1269         g_clear_object (&file);
1270     }
1271 
1272     for (l = self->new_display_names; l != NULL; l = l->next)
1273     {
1274         string = l->data;
1275 
1276         g_string_free (string, TRUE);
1277     }
1278 
1279     for (l = self->old_display_names; l != NULL; l = l->next)
1280     {
1281         string = l->data;
1282 
1283         g_string_free (string, TRUE);
1284     }
1285 
1286     g_list_free (self->new_files);
1287     g_list_free (self->old_files);
1288     g_list_free (self->new_display_names);
1289     g_list_free (self->old_display_names);
1290 
1291     G_OBJECT_CLASS (nautilus_file_undo_info_batch_rename_parent_class)->finalize (obj);
1292 }
1293 
1294 static void
nautilus_file_undo_info_batch_rename_class_init(NautilusFileUndoInfoBatchRenameClass * klass)1295 nautilus_file_undo_info_batch_rename_class_init (NautilusFileUndoInfoBatchRenameClass *klass)
1296 {
1297     GObjectClass *oclass = G_OBJECT_CLASS (klass);
1298     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
1299 
1300     oclass->finalize = nautilus_file_undo_info_batch_rename_finalize;
1301 
1302     iclass->undo_func = batch_rename_undo_func;
1303     iclass->redo_func = batch_rename_redo_func;
1304     iclass->strings_func = batch_rename_strings_func;
1305 }
1306 
1307 NautilusFileUndoInfo *
nautilus_file_undo_info_batch_rename_new(gint item_count)1308 nautilus_file_undo_info_batch_rename_new (gint item_count)
1309 {
1310     return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME,
1311                          "op-type", NAUTILUS_FILE_UNDO_OP_BATCH_RENAME,
1312                          "item-count", item_count,
1313                          NULL);
1314 }
1315 
1316 void
nautilus_file_undo_info_batch_rename_set_data_pre(NautilusFileUndoInfoBatchRename * self,GList * old_files)1317 nautilus_file_undo_info_batch_rename_set_data_pre (NautilusFileUndoInfoBatchRename *self,
1318                                                    GList                           *old_files)
1319 {
1320     GList *l;
1321     GString *old_name;
1322     GFile *file;
1323 
1324     self->old_files = old_files;
1325     self->old_display_names = NULL;
1326 
1327     for (l = old_files; l != NULL; l = l->next)
1328     {
1329         file = l->data;
1330 
1331         old_name = g_string_new (g_file_get_basename (file));
1332 
1333         self->old_display_names = g_list_prepend (self->old_display_names, old_name);
1334     }
1335 
1336     self->old_display_names = g_list_reverse (self->old_display_names);
1337 }
1338 
1339 void
nautilus_file_undo_info_batch_rename_set_data_post(NautilusFileUndoInfoBatchRename * self,GList * new_files)1340 nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRename *self,
1341                                                     GList                           *new_files)
1342 {
1343     GList *l;
1344     GString *new_name;
1345     GFile *file;
1346 
1347     self->new_files = new_files;
1348     self->new_display_names = NULL;
1349 
1350     for (l = new_files; l != NULL; l = l->next)
1351     {
1352         file = l->data;
1353 
1354         new_name = g_string_new (g_file_get_basename (file));
1355 
1356         self->new_display_names = g_list_prepend (self->new_display_names, new_name);
1357     }
1358 
1359     self->new_display_names = g_list_reverse (self->new_display_names);
1360 }
1361 
1362 /* starred files */
1363 struct _NautilusFileUndoInfoStarred
1364 {
1365     NautilusFileUndoInfo parent_instance;
1366 
1367     GList *files;
1368     /* Whether the action was starring or unstarring */
1369     gboolean starred;
1370 };
1371 
1372 G_DEFINE_TYPE (NautilusFileUndoInfoStarred, nautilus_file_undo_info_starred, NAUTILUS_TYPE_FILE_UNDO_INFO);
1373 
1374 enum
1375 {
1376     PROP_FILES = 1,
1377     PROP_STARRED,
1378     NUM_PROPERTIES
1379 };
1380 
1381 static void
starred_strings_func(NautilusFileUndoInfo * info,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)1382 starred_strings_func (NautilusFileUndoInfo  *info,
1383                       gchar                **undo_label,
1384                       gchar                **undo_description,
1385                       gchar                **redo_label,
1386                       gchar                **redo_description)
1387 {
1388     NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
1389 
1390     if (self->starred)
1391     {
1392         *undo_description = g_strdup_printf (ngettext ("Unstar %d file",
1393                                                        "Unstar %d files",
1394                                                        g_list_length (self->files)),
1395                                              g_list_length (self->files));
1396         *redo_description = g_strdup_printf (ngettext ("Star %d file",
1397                                                        "Star %d files",
1398                                                        g_list_length (self->files)),
1399                                              g_list_length (self->files));
1400         *undo_label = g_strdup (_("_Undo Starring"));
1401         *redo_label = g_strdup (_("_Redo Starring"));
1402     }
1403     else
1404     {
1405         *undo_description = g_strdup_printf (ngettext ("Star %d file",
1406                                                        "Star %d files",
1407                                                        g_list_length (self->files)),
1408                                              g_list_length (self->files));
1409         *redo_description = g_strdup_printf (ngettext ("Unstar %d file",
1410                                                        "Unstar %d files",
1411                                                        g_list_length (self->files)),
1412                                              g_list_length (self->files));
1413         *undo_label = g_strdup (_("_Undo Unstarring"));
1414         *redo_label = g_strdup (_("_Redo Unstarring"));
1415     }
1416 }
1417 
1418 static void
on_undo_starred_tags_updated(GObject * object,GAsyncResult * res,gpointer user_data)1419 on_undo_starred_tags_updated (GObject      *object,
1420                               GAsyncResult *res,
1421                               gpointer      user_data)
1422 {
1423     GTask *task;
1424     NautilusFileUndoInfo *undo_info;
1425 
1426     undo_info = NAUTILUS_FILE_UNDO_INFO (object);
1427 
1428     task = user_data;
1429     g_clear_object (&task);
1430 
1431     file_undo_info_operation_callback (NULL, NULL, NULL, undo_info);
1432 }
1433 
1434 static void
starred_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1435 starred_redo_func (NautilusFileUndoInfo           *info,
1436                    GtkWindow                      *parent_window,
1437                    NautilusFileOperationsDBusData *dbus_data)
1438 {
1439     NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
1440     g_autoptr (NautilusTagManager) tag_manager = nautilus_tag_manager_get ();
1441 
1442     if (self->starred)
1443     {
1444         nautilus_tag_manager_star_files (tag_manager,
1445                                          G_OBJECT (info),
1446                                          self->files,
1447                                          on_undo_starred_tags_updated,
1448                                          NULL);
1449     }
1450     else
1451     {
1452         nautilus_tag_manager_unstar_files (tag_manager,
1453                                            G_OBJECT (info),
1454                                            self->files,
1455                                            on_undo_starred_tags_updated,
1456                                            NULL);
1457     }
1458 }
1459 
1460 static void
starred_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1461 starred_undo_func (NautilusFileUndoInfo           *info,
1462                    GtkWindow                      *parent_window,
1463                    NautilusFileOperationsDBusData *dbus_data)
1464 {
1465     NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (info);
1466     g_autoptr (NautilusTagManager) tag_manager = nautilus_tag_manager_get ();
1467 
1468     if (self->starred)
1469     {
1470         nautilus_tag_manager_unstar_files (tag_manager,
1471                                            G_OBJECT (info),
1472                                            self->files,
1473                                            on_undo_starred_tags_updated,
1474                                            NULL);
1475     }
1476     else
1477     {
1478         nautilus_tag_manager_star_files (tag_manager,
1479                                          G_OBJECT (info),
1480                                          self->files,
1481                                          on_undo_starred_tags_updated,
1482                                          NULL);
1483     }
1484 }
1485 
1486 static void
nautilus_file_undo_info_starred_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1487 nautilus_file_undo_info_starred_set_property (GObject      *object,
1488                                               guint         prop_id,
1489                                               const GValue *value,
1490                                               GParamSpec   *pspec)
1491 {
1492     NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (object);
1493 
1494     switch (prop_id)
1495     {
1496         case PROP_FILES:
1497         {
1498             self->files = nautilus_file_list_copy (g_value_get_pointer (value));
1499         }
1500         break;
1501 
1502         case PROP_STARRED:
1503         {
1504             self->starred = g_value_get_boolean (value);
1505         }
1506         break;
1507 
1508         default:
1509         {
1510             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1511         }
1512     }
1513 }
1514 
1515 static void
nautilus_file_undo_info_starred_init(NautilusFileUndoInfoStarred * self)1516 nautilus_file_undo_info_starred_init (NautilusFileUndoInfoStarred *self)
1517 {
1518 }
1519 
1520 static void
nautilus_file_undo_info_starred_finalize(GObject * obj)1521 nautilus_file_undo_info_starred_finalize (GObject *obj)
1522 {
1523     NautilusFileUndoInfoStarred *self = NAUTILUS_FILE_UNDO_INFO_STARRED (obj);
1524 
1525     nautilus_file_list_free (self->files);
1526 
1527     G_OBJECT_CLASS (nautilus_file_undo_info_starred_parent_class)->finalize (obj);
1528 }
1529 
1530 static void
nautilus_file_undo_info_starred_class_init(NautilusFileUndoInfoStarredClass * klass)1531 nautilus_file_undo_info_starred_class_init (NautilusFileUndoInfoStarredClass *klass)
1532 {
1533     GObjectClass *oclass = G_OBJECT_CLASS (klass);
1534     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
1535 
1536     oclass->finalize = nautilus_file_undo_info_starred_finalize;
1537     oclass->set_property = nautilus_file_undo_info_starred_set_property;
1538 
1539     iclass->undo_func = starred_undo_func;
1540     iclass->redo_func = starred_redo_func;
1541     iclass->strings_func = starred_strings_func;
1542 
1543     g_object_class_install_property (oclass,
1544                                      PROP_FILES,
1545                                      g_param_spec_pointer ("files",
1546                                                            "files",
1547                                                            "The files for which to undo star/unstar",
1548                                                            G_PARAM_WRITABLE |
1549                                                            G_PARAM_CONSTRUCT_ONLY));
1550     g_object_class_install_property (oclass,
1551                                      PROP_STARRED,
1552                                      g_param_spec_boolean ("starred",
1553                                                            "starred",
1554                                                            "Whether the files were starred or unstarred",
1555                                                            FALSE,
1556                                                            G_PARAM_WRITABLE |
1557                                                            G_PARAM_CONSTRUCT_ONLY));
1558 }
1559 
1560 GList *
nautilus_file_undo_info_starred_get_files(NautilusFileUndoInfoStarred * self)1561 nautilus_file_undo_info_starred_get_files (NautilusFileUndoInfoStarred *self)
1562 {
1563     return self->files;
1564 }
1565 
1566 gboolean
nautilus_file_undo_info_starred_is_starred(NautilusFileUndoInfoStarred * self)1567 nautilus_file_undo_info_starred_is_starred (NautilusFileUndoInfoStarred *self)
1568 {
1569     return self->starred;
1570 }
1571 
1572 NautilusFileUndoInfo *
nautilus_file_undo_info_starred_new(GList * files,gboolean starred)1573 nautilus_file_undo_info_starred_new (GList    *files,
1574                                      gboolean  starred)
1575 {
1576     NautilusFileUndoInfoStarred *self;
1577 
1578     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_STARRED,
1579                          "op-type", NAUTILUS_FILE_UNDO_OP_STARRED,
1580                          "item-count", g_list_length (files),
1581                          "files", files,
1582                          "starred", starred,
1583                          NULL);
1584 
1585     return NAUTILUS_FILE_UNDO_INFO (self);
1586 }
1587 
1588 /* trash */
1589 struct _NautilusFileUndoInfoTrash
1590 {
1591     NautilusFileUndoInfo parent_instance;
1592 
1593     GHashTable *trashed;
1594 };
1595 
G_DEFINE_TYPE(NautilusFileUndoInfoTrash,nautilus_file_undo_info_trash,NAUTILUS_TYPE_FILE_UNDO_INFO)1596 G_DEFINE_TYPE (NautilusFileUndoInfoTrash, nautilus_file_undo_info_trash, NAUTILUS_TYPE_FILE_UNDO_INFO)
1597 
1598 static void
1599 trash_strings_func (NautilusFileUndoInfo  *info,
1600                     gchar                **undo_label,
1601                     gchar                **undo_description,
1602                     gchar                **redo_label,
1603                     gchar                **redo_description)
1604 {
1605     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
1606     gint count = g_hash_table_size (self->trashed);
1607 
1608     if (count != 1)
1609     {
1610         *undo_description = g_strdup_printf (ngettext ("Restore %d item from trash",
1611                                                        "Restore %d items from trash", count),
1612                                              count);
1613         *redo_description = g_strdup_printf (ngettext ("Move %d item to trash",
1614                                                        "Move %d items to trash", count),
1615                                              count);
1616     }
1617     else
1618     {
1619         GList *keys;
1620         char *name, *orig_path;
1621         GFile *file;
1622 
1623         keys = g_hash_table_get_keys (self->trashed);
1624         file = keys->data;
1625         name = g_file_get_basename (file);
1626         orig_path = g_file_get_path (file);
1627         *undo_description = g_strdup_printf (_("Restore “%s” to “%s”"), name, orig_path);
1628 
1629         g_free (name);
1630         g_free (orig_path);
1631         g_list_free (keys);
1632 
1633         name = g_file_get_parse_name (file);
1634         *redo_description = g_strdup_printf (_("Move “%s” to trash"), name);
1635 
1636         g_free (name);
1637     }
1638 
1639     *undo_label = g_strdup (_("_Undo Trash"));
1640     *redo_label = g_strdup (_("_Redo Trash"));
1641 }
1642 
1643 static void
trash_redo_func_callback(GHashTable * debuting_uris,gboolean user_cancel,gpointer user_data)1644 trash_redo_func_callback (GHashTable *debuting_uris,
1645                           gboolean    user_cancel,
1646                           gpointer    user_data)
1647 {
1648     NautilusFileUndoInfoTrash *self = user_data;
1649     GHashTable *new_trashed_files;
1650     GTimeVal current_time;
1651     gsize updated_trash_time;
1652     GFile *file;
1653     GList *keys, *l;
1654 
1655     if (!user_cancel)
1656     {
1657         new_trashed_files =
1658             g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
1659                                    g_object_unref, NULL);
1660 
1661         keys = g_hash_table_get_keys (self->trashed);
1662 
1663         g_get_current_time (&current_time);
1664         updated_trash_time = current_time.tv_sec;
1665 
1666         for (l = keys; l != NULL; l = l->next)
1667         {
1668             file = l->data;
1669             g_hash_table_insert (new_trashed_files,
1670                                  g_object_ref (file), GSIZE_TO_POINTER (updated_trash_time));
1671         }
1672 
1673         g_list_free (keys);
1674         g_hash_table_destroy (self->trashed);
1675 
1676         self->trashed = new_trashed_files;
1677     }
1678 
1679     file_undo_info_delete_callback (debuting_uris, user_cancel, user_data);
1680 }
1681 
1682 static void
trash_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1683 trash_redo_func (NautilusFileUndoInfo           *info,
1684                  GtkWindow                      *parent_window,
1685                  NautilusFileOperationsDBusData *dbus_data)
1686 {
1687     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
1688 
1689     if (g_hash_table_size (self->trashed) > 0)
1690     {
1691         GList *locations;
1692 
1693         locations = g_hash_table_get_keys (self->trashed);
1694         nautilus_file_operations_trash_or_delete_async (locations, parent_window,
1695                                                         dbus_data,
1696                                                         trash_redo_func_callback, self);
1697 
1698         g_list_free (locations);
1699     }
1700 }
1701 
1702 static void
trash_retrieve_files_to_restore_thread(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1703 trash_retrieve_files_to_restore_thread (GTask        *task,
1704                                         gpointer      source_object,
1705                                         gpointer      task_data,
1706                                         GCancellable *cancellable)
1707 {
1708     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (source_object);
1709     GFileEnumerator *enumerator;
1710     GHashTable *to_restore;
1711     GFile *trash;
1712     GError *error = NULL;
1713 
1714     to_restore = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
1715                                         g_object_unref, g_object_unref);
1716 
1717     trash = g_file_new_for_uri ("trash:///");
1718 
1719     enumerator = g_file_enumerate_children (trash,
1720                                             G_FILE_ATTRIBUTE_STANDARD_NAME ","
1721                                             G_FILE_ATTRIBUTE_TRASH_DELETION_DATE ","
1722                                             G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
1723                                             G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1724                                             NULL, &error);
1725 
1726     if (enumerator)
1727     {
1728         GFileInfo *info;
1729         gpointer lookupvalue;
1730         GFile *item;
1731         glong trash_time, orig_trash_time;
1732         const char *origpath;
1733         GFile *origfile;
1734 
1735         while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)
1736         {
1737             /* Retrieve the original file uri */
1738             origpath = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
1739             origfile = g_file_new_for_path (origpath);
1740 
1741             lookupvalue = g_hash_table_lookup (self->trashed, origfile);
1742 
1743             if (lookupvalue)
1744             {
1745                 GDateTime *date;
1746 
1747                 orig_trash_time = GPOINTER_TO_SIZE (lookupvalue);
1748                 trash_time = 0;
1749                 date = g_file_info_get_deletion_date (info);
1750                 if (date)
1751                 {
1752                     trash_time = g_date_time_to_unix (date);
1753                     g_date_time_unref (date);
1754                 }
1755 
1756                 if (ABS (orig_trash_time - trash_time) <= TRASH_TIME_EPSILON)
1757                 {
1758                     /* File in the trash */
1759                     item = g_file_get_child (trash, g_file_info_get_name (info));
1760                     g_hash_table_insert (to_restore, item, g_object_ref (origfile));
1761                 }
1762             }
1763 
1764             g_object_unref (origfile);
1765         }
1766         g_file_enumerator_close (enumerator, FALSE, NULL);
1767         g_object_unref (enumerator);
1768     }
1769     g_object_unref (trash);
1770 
1771     if (error != NULL)
1772     {
1773         g_task_return_error (task, error);
1774         g_hash_table_destroy (to_restore);
1775     }
1776     else
1777     {
1778         g_task_return_pointer (task, to_restore, NULL);
1779     }
1780 }
1781 
1782 static void
trash_retrieve_files_to_restore_async(NautilusFileUndoInfoTrash * self,GAsyncReadyCallback callback,gpointer user_data)1783 trash_retrieve_files_to_restore_async (NautilusFileUndoInfoTrash *self,
1784                                        GAsyncReadyCallback        callback,
1785                                        gpointer                   user_data)
1786 {
1787     GTask *task;
1788 
1789     task = g_task_new (G_OBJECT (self), NULL, callback, user_data);
1790 
1791     g_task_run_in_thread (task, trash_retrieve_files_to_restore_thread);
1792 
1793     g_object_unref (task);
1794 }
1795 
1796 static void
trash_retrieve_files_ready(GObject * source,GAsyncResult * res,gpointer user_data)1797 trash_retrieve_files_ready (GObject      *source,
1798                             GAsyncResult *res,
1799                             gpointer      user_data)
1800 {
1801     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (source);
1802     GHashTable *files_to_restore;
1803     GError *error = NULL;
1804 
1805     files_to_restore = g_task_propagate_pointer (G_TASK (res), &error);
1806 
1807     if (error == NULL && g_hash_table_size (files_to_restore) > 0)
1808     {
1809         GList *gfiles_in_trash, *l;
1810         GFile *item;
1811         GFile *dest;
1812 
1813         gfiles_in_trash = g_hash_table_get_keys (files_to_restore);
1814 
1815         for (l = gfiles_in_trash; l != NULL; l = l->next)
1816         {
1817             item = l->data;
1818             dest = g_hash_table_lookup (files_to_restore, item);
1819 
1820             g_file_move (item, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL, NULL, NULL);
1821         }
1822 
1823         g_list_free (gfiles_in_trash);
1824 
1825         /* Here we must do what's necessary for the callback */
1826         file_undo_info_transfer_callback (NULL, (error == NULL), self);
1827     }
1828     else
1829     {
1830         file_undo_info_transfer_callback (NULL, FALSE, self);
1831     }
1832 
1833     if (files_to_restore != NULL)
1834     {
1835         g_hash_table_destroy (files_to_restore);
1836     }
1837 
1838     g_clear_error (&error);
1839 }
1840 
1841 static void
trash_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1842 trash_undo_func (NautilusFileUndoInfo           *info,
1843                  GtkWindow                      *parent_window,
1844                  NautilusFileOperationsDBusData *dbus_data)
1845 {
1846     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
1847 
1848     trash_retrieve_files_to_restore_async (self, trash_retrieve_files_ready, NULL);
1849 }
1850 
1851 static void
nautilus_file_undo_info_trash_init(NautilusFileUndoInfoTrash * self)1852 nautilus_file_undo_info_trash_init (NautilusFileUndoInfoTrash *self)
1853 {
1854     self->trashed = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
1855                                            g_object_unref, NULL);
1856 }
1857 
1858 static void
nautilus_file_undo_info_trash_finalize(GObject * obj)1859 nautilus_file_undo_info_trash_finalize (GObject *obj)
1860 {
1861     NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (obj);
1862     g_hash_table_destroy (self->trashed);
1863 
1864     G_OBJECT_CLASS (nautilus_file_undo_info_trash_parent_class)->finalize (obj);
1865 }
1866 
1867 static void
nautilus_file_undo_info_trash_class_init(NautilusFileUndoInfoTrashClass * klass)1868 nautilus_file_undo_info_trash_class_init (NautilusFileUndoInfoTrashClass *klass)
1869 {
1870     GObjectClass *oclass = G_OBJECT_CLASS (klass);
1871     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
1872 
1873     oclass->finalize = nautilus_file_undo_info_trash_finalize;
1874 
1875     iclass->undo_func = trash_undo_func;
1876     iclass->redo_func = trash_redo_func;
1877     iclass->strings_func = trash_strings_func;
1878 }
1879 
1880 NautilusFileUndoInfo *
nautilus_file_undo_info_trash_new(gint item_count)1881 nautilus_file_undo_info_trash_new (gint item_count)
1882 {
1883     return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH,
1884                          "op-type", NAUTILUS_FILE_UNDO_OP_MOVE_TO_TRASH,
1885                          "item-count", item_count,
1886                          NULL);
1887 }
1888 
1889 void
nautilus_file_undo_info_trash_add_file(NautilusFileUndoInfoTrash * self,GFile * file)1890 nautilus_file_undo_info_trash_add_file (NautilusFileUndoInfoTrash *self,
1891                                         GFile                     *file)
1892 {
1893     GTimeVal current_time;
1894     gsize orig_trash_time;
1895 
1896     g_get_current_time (&current_time);
1897     orig_trash_time = current_time.tv_sec;
1898 
1899     g_hash_table_insert (self->trashed, g_object_ref (file), GSIZE_TO_POINTER (orig_trash_time));
1900 }
1901 
1902 GList *
nautilus_file_undo_info_trash_get_files(NautilusFileUndoInfoTrash * self)1903 nautilus_file_undo_info_trash_get_files (NautilusFileUndoInfoTrash *self)
1904 {
1905     return g_hash_table_get_keys (self->trashed);
1906 }
1907 
1908 /* recursive permissions */
1909 struct _NautilusFileUndoInfoRecPermissions
1910 {
1911     NautilusFileUndoInfo parent_instance;
1912 
1913     GFile *dest_dir;
1914     GHashTable *original_permissions;
1915     guint32 dir_mask;
1916     guint32 dir_permissions;
1917     guint32 file_mask;
1918     guint32 file_permissions;
1919 };
1920 
G_DEFINE_TYPE(NautilusFileUndoInfoRecPermissions,nautilus_file_undo_info_rec_permissions,NAUTILUS_TYPE_FILE_UNDO_INFO)1921 G_DEFINE_TYPE (NautilusFileUndoInfoRecPermissions, nautilus_file_undo_info_rec_permissions, NAUTILUS_TYPE_FILE_UNDO_INFO)
1922 
1923 static void
1924 rec_permissions_strings_func (NautilusFileUndoInfo  *info,
1925                               gchar                **undo_label,
1926                               gchar                **undo_description,
1927                               gchar                **redo_label,
1928                               gchar                **redo_description)
1929 {
1930     NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
1931     char *name;
1932 
1933     name = g_file_get_path (self->dest_dir);
1934 
1935     *undo_description = g_strdup_printf (_("Restore original permissions of items enclosed in “%s”"), name);
1936     *redo_description = g_strdup_printf (_("Set permissions of items enclosed in “%s”"), name);
1937 
1938     *undo_label = g_strdup (_("_Undo Change Permissions"));
1939     *redo_label = g_strdup (_("_Redo Change Permissions"));
1940 
1941     g_free (name);
1942 }
1943 
1944 static void
rec_permissions_callback(gboolean success,gpointer callback_data)1945 rec_permissions_callback (gboolean success,
1946                           gpointer callback_data)
1947 {
1948     file_undo_info_transfer_callback (NULL, success, callback_data);
1949 }
1950 
1951 static void
rec_permissions_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1952 rec_permissions_redo_func (NautilusFileUndoInfo           *info,
1953                            GtkWindow                      *parent_window,
1954                            NautilusFileOperationsDBusData *dbus_data)
1955 {
1956     NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
1957     gchar *parent_uri;
1958 
1959     parent_uri = g_file_get_uri (self->dest_dir);
1960     nautilus_file_set_permissions_recursive (parent_uri,
1961                                              self->file_permissions,
1962                                              self->file_mask,
1963                                              self->dir_permissions,
1964                                              self->dir_mask,
1965                                              rec_permissions_callback, self);
1966     g_free (parent_uri);
1967 }
1968 
1969 static void
rec_permissions_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)1970 rec_permissions_undo_func (NautilusFileUndoInfo           *info,
1971                            GtkWindow                      *parent_window,
1972                            NautilusFileOperationsDBusData *dbus_data)
1973 {
1974     NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (info);
1975 
1976     if (g_hash_table_size (self->original_permissions) > 0)
1977     {
1978         GList *gfiles_list;
1979         guint32 perm;
1980         GList *l;
1981         GFile *dest;
1982         char *item;
1983 
1984         gfiles_list = g_hash_table_get_keys (self->original_permissions);
1985         for (l = gfiles_list; l != NULL; l = l->next)
1986         {
1987             item = l->data;
1988             perm = GPOINTER_TO_UINT (g_hash_table_lookup (self->original_permissions, item));
1989             dest = g_file_new_for_uri (item);
1990             g_file_set_attribute_uint32 (dest,
1991                                          G_FILE_ATTRIBUTE_UNIX_MODE,
1992                                          perm, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL);
1993             g_object_unref (dest);
1994         }
1995 
1996         g_list_free (gfiles_list);
1997         /* Here we must do what's necessary for the callback */
1998         file_undo_info_transfer_callback (NULL, TRUE, self);
1999     }
2000 }
2001 
2002 static void
nautilus_file_undo_info_rec_permissions_init(NautilusFileUndoInfoRecPermissions * self)2003 nautilus_file_undo_info_rec_permissions_init (NautilusFileUndoInfoRecPermissions *self)
2004 {
2005     self->original_permissions = g_hash_table_new_full (g_str_hash, g_str_equal,
2006                                                         g_free, NULL);
2007 }
2008 
2009 static void
nautilus_file_undo_info_rec_permissions_finalize(GObject * obj)2010 nautilus_file_undo_info_rec_permissions_finalize (GObject *obj)
2011 {
2012     NautilusFileUndoInfoRecPermissions *self = NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (obj);
2013 
2014     g_hash_table_destroy (self->original_permissions);
2015     g_clear_object (&self->dest_dir);
2016 
2017     G_OBJECT_CLASS (nautilus_file_undo_info_rec_permissions_parent_class)->finalize (obj);
2018 }
2019 
2020 static void
nautilus_file_undo_info_rec_permissions_class_init(NautilusFileUndoInfoRecPermissionsClass * klass)2021 nautilus_file_undo_info_rec_permissions_class_init (NautilusFileUndoInfoRecPermissionsClass *klass)
2022 {
2023     GObjectClass *oclass = G_OBJECT_CLASS (klass);
2024     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
2025 
2026     oclass->finalize = nautilus_file_undo_info_rec_permissions_finalize;
2027 
2028     iclass->undo_func = rec_permissions_undo_func;
2029     iclass->redo_func = rec_permissions_redo_func;
2030     iclass->strings_func = rec_permissions_strings_func;
2031 }
2032 
2033 NautilusFileUndoInfo *
nautilus_file_undo_info_rec_permissions_new(GFile * dest,guint32 file_permissions,guint32 file_mask,guint32 dir_permissions,guint32 dir_mask)2034 nautilus_file_undo_info_rec_permissions_new (GFile   *dest,
2035                                              guint32  file_permissions,
2036                                              guint32  file_mask,
2037                                              guint32  dir_permissions,
2038                                              guint32  dir_mask)
2039 {
2040     NautilusFileUndoInfoRecPermissions *self;
2041 
2042     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_REC_PERMISSIONS,
2043                          "op-type", NAUTILUS_FILE_UNDO_OP_RECURSIVE_SET_PERMISSIONS,
2044                          "item-count", 1,
2045                          NULL);
2046 
2047     self->dest_dir = g_object_ref (dest);
2048     self->file_permissions = file_permissions;
2049     self->file_mask = file_mask;
2050     self->dir_permissions = dir_permissions;
2051     self->dir_mask = dir_mask;
2052 
2053     return NAUTILUS_FILE_UNDO_INFO (self);
2054 }
2055 
2056 void
nautilus_file_undo_info_rec_permissions_add_file(NautilusFileUndoInfoRecPermissions * self,GFile * file,guint32 permission)2057 nautilus_file_undo_info_rec_permissions_add_file (NautilusFileUndoInfoRecPermissions *self,
2058                                                   GFile                              *file,
2059                                                   guint32                             permission)
2060 {
2061     gchar *original_uri = g_file_get_uri (file);
2062     g_hash_table_insert (self->original_permissions, original_uri, GUINT_TO_POINTER (permission));
2063 }
2064 
2065 /* single file change permissions */
2066 struct _NautilusFileUndoInfoPermissions
2067 {
2068     NautilusFileUndoInfo parent_instance;
2069 
2070     GFile *target_file;
2071     guint32 current_permissions;
2072     guint32 new_permissions;
2073 };
2074 
G_DEFINE_TYPE(NautilusFileUndoInfoPermissions,nautilus_file_undo_info_permissions,NAUTILUS_TYPE_FILE_UNDO_INFO)2075 G_DEFINE_TYPE (NautilusFileUndoInfoPermissions, nautilus_file_undo_info_permissions, NAUTILUS_TYPE_FILE_UNDO_INFO)
2076 
2077 static void
2078 permissions_strings_func (NautilusFileUndoInfo  *info,
2079                           gchar                **undo_label,
2080                           gchar                **undo_description,
2081                           gchar                **redo_label,
2082                           gchar                **redo_description)
2083 {
2084     NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
2085     gchar *name;
2086 
2087     name = g_file_get_parse_name (self->target_file);
2088     *undo_description = g_strdup_printf (_("Restore original permissions of “%s”"), name);
2089     *redo_description = g_strdup_printf (_("Set permissions of “%s”"), name);
2090 
2091     *undo_label = g_strdup (_("_Undo Change Permissions"));
2092     *redo_label = g_strdup (_("_Redo Change Permissions"));
2093 
2094     g_free (name);
2095 }
2096 
2097 static void
permissions_real_func(NautilusFileUndoInfoPermissions * self,guint32 permissions)2098 permissions_real_func (NautilusFileUndoInfoPermissions *self,
2099                        guint32                          permissions)
2100 {
2101     NautilusFile *file;
2102 
2103     file = nautilus_file_get (self->target_file);
2104     nautilus_file_set_permissions (file, permissions,
2105                                    file_undo_info_operation_callback, self);
2106 
2107     nautilus_file_unref (file);
2108 }
2109 
2110 static void
permissions_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2111 permissions_redo_func (NautilusFileUndoInfo           *info,
2112                        GtkWindow                      *parent_window,
2113                        NautilusFileOperationsDBusData *dbus_data)
2114 {
2115     NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
2116     permissions_real_func (self, self->new_permissions);
2117 }
2118 
2119 static void
permissions_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2120 permissions_undo_func (NautilusFileUndoInfo           *info,
2121                        GtkWindow                      *parent_window,
2122                        NautilusFileOperationsDBusData *dbus_data)
2123 {
2124     NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (info);
2125     permissions_real_func (self, self->current_permissions);
2126 }
2127 
2128 static void
nautilus_file_undo_info_permissions_init(NautilusFileUndoInfoPermissions * self)2129 nautilus_file_undo_info_permissions_init (NautilusFileUndoInfoPermissions *self)
2130 {
2131 }
2132 
2133 static void
nautilus_file_undo_info_permissions_finalize(GObject * obj)2134 nautilus_file_undo_info_permissions_finalize (GObject *obj)
2135 {
2136     NautilusFileUndoInfoPermissions *self = NAUTILUS_FILE_UNDO_INFO_PERMISSIONS (obj);
2137     g_clear_object (&self->target_file);
2138 
2139     G_OBJECT_CLASS (nautilus_file_undo_info_permissions_parent_class)->finalize (obj);
2140 }
2141 
2142 static void
nautilus_file_undo_info_permissions_class_init(NautilusFileUndoInfoPermissionsClass * klass)2143 nautilus_file_undo_info_permissions_class_init (NautilusFileUndoInfoPermissionsClass *klass)
2144 {
2145     GObjectClass *oclass = G_OBJECT_CLASS (klass);
2146     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
2147 
2148     oclass->finalize = nautilus_file_undo_info_permissions_finalize;
2149 
2150     iclass->undo_func = permissions_undo_func;
2151     iclass->redo_func = permissions_redo_func;
2152     iclass->strings_func = permissions_strings_func;
2153 }
2154 
2155 NautilusFileUndoInfo *
nautilus_file_undo_info_permissions_new(GFile * file,guint32 current_permissions,guint32 new_permissions)2156 nautilus_file_undo_info_permissions_new (GFile   *file,
2157                                          guint32  current_permissions,
2158                                          guint32  new_permissions)
2159 {
2160     NautilusFileUndoInfoPermissions *self;
2161 
2162     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_PERMISSIONS,
2163                          "op-type", NAUTILUS_FILE_UNDO_OP_SET_PERMISSIONS,
2164                          "item-count", 1,
2165                          NULL);
2166 
2167     self->target_file = g_object_ref (file);
2168     self->current_permissions = current_permissions;
2169     self->new_permissions = new_permissions;
2170 
2171     return NAUTILUS_FILE_UNDO_INFO (self);
2172 }
2173 
2174 /* group and owner change */
2175 struct _NautilusFileUndoInfoOwnership
2176 {
2177     NautilusFileUndoInfo parent_instance;
2178 
2179     GFile *target_file;
2180     char *original_ownership;
2181     char *new_ownership;
2182 };
2183 
G_DEFINE_TYPE(NautilusFileUndoInfoOwnership,nautilus_file_undo_info_ownership,NAUTILUS_TYPE_FILE_UNDO_INFO)2184 G_DEFINE_TYPE (NautilusFileUndoInfoOwnership, nautilus_file_undo_info_ownership, NAUTILUS_TYPE_FILE_UNDO_INFO)
2185 
2186 static void
2187 ownership_strings_func (NautilusFileUndoInfo  *info,
2188                         gchar                **undo_label,
2189                         gchar                **undo_description,
2190                         gchar                **redo_label,
2191                         gchar                **redo_description)
2192 {
2193     NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
2194     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (info);
2195     gchar *name;
2196 
2197     name = g_file_get_parse_name (self->target_file);
2198 
2199     if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_OWNER)
2200     {
2201         *undo_description = g_strdup_printf (_("Restore group of “%s” to “%s”"),
2202                                              name, self->original_ownership);
2203         *redo_description = g_strdup_printf (_("Set group of “%s” to “%s”"),
2204                                              name, self->new_ownership);
2205 
2206         *undo_label = g_strdup (_("_Undo Change Group"));
2207         *redo_label = g_strdup (_("_Redo Change Group"));
2208     }
2209     else if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_GROUP)
2210     {
2211         *undo_description = g_strdup_printf (_("Restore owner of “%s” to “%s”"),
2212                                              name, self->original_ownership);
2213         *redo_description = g_strdup_printf (_("Set owner of “%s” to “%s”"),
2214                                              name, self->new_ownership);
2215 
2216         *undo_label = g_strdup (_("_Undo Change Owner"));
2217         *redo_label = g_strdup (_("_Redo Change Owner"));
2218     }
2219 
2220     g_free (name);
2221 }
2222 
2223 static void
ownership_real_func(NautilusFileUndoInfoOwnership * self,const gchar * ownership)2224 ownership_real_func (NautilusFileUndoInfoOwnership *self,
2225                      const gchar                   *ownership)
2226 {
2227     NautilusFileUndoOp op_type = nautilus_file_undo_info_get_op_type (NAUTILUS_FILE_UNDO_INFO (self));
2228     NautilusFile *file;
2229 
2230     file = nautilus_file_get (self->target_file);
2231 
2232     if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_OWNER)
2233     {
2234         nautilus_file_set_owner (file,
2235                                  ownership,
2236                                  file_undo_info_operation_callback, self);
2237     }
2238     else if (op_type == NAUTILUS_FILE_UNDO_OP_CHANGE_GROUP)
2239     {
2240         nautilus_file_set_group (file,
2241                                  ownership,
2242                                  file_undo_info_operation_callback, self);
2243     }
2244 
2245     nautilus_file_unref (file);
2246 }
2247 
2248 static void
ownership_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2249 ownership_redo_func (NautilusFileUndoInfo           *info,
2250                      GtkWindow                      *parent_window,
2251                      NautilusFileOperationsDBusData *dbus_data)
2252 {
2253     NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
2254     ownership_real_func (self, self->new_ownership);
2255 }
2256 
2257 static void
ownership_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2258 ownership_undo_func (NautilusFileUndoInfo           *info,
2259                      GtkWindow                      *parent_window,
2260                      NautilusFileOperationsDBusData *dbus_data)
2261 {
2262     NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (info);
2263     ownership_real_func (self, self->original_ownership);
2264 }
2265 
2266 static void
nautilus_file_undo_info_ownership_init(NautilusFileUndoInfoOwnership * self)2267 nautilus_file_undo_info_ownership_init (NautilusFileUndoInfoOwnership *self)
2268 {
2269 }
2270 
2271 static void
nautilus_file_undo_info_ownership_finalize(GObject * obj)2272 nautilus_file_undo_info_ownership_finalize (GObject *obj)
2273 {
2274     NautilusFileUndoInfoOwnership *self = NAUTILUS_FILE_UNDO_INFO_OWNERSHIP (obj);
2275 
2276     g_clear_object (&self->target_file);
2277     g_free (self->original_ownership);
2278     g_free (self->new_ownership);
2279 
2280     G_OBJECT_CLASS (nautilus_file_undo_info_ownership_parent_class)->finalize (obj);
2281 }
2282 
2283 static void
nautilus_file_undo_info_ownership_class_init(NautilusFileUndoInfoOwnershipClass * klass)2284 nautilus_file_undo_info_ownership_class_init (NautilusFileUndoInfoOwnershipClass *klass)
2285 {
2286     GObjectClass *oclass = G_OBJECT_CLASS (klass);
2287     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
2288 
2289     oclass->finalize = nautilus_file_undo_info_ownership_finalize;
2290 
2291     iclass->undo_func = ownership_undo_func;
2292     iclass->redo_func = ownership_redo_func;
2293     iclass->strings_func = ownership_strings_func;
2294 }
2295 
2296 NautilusFileUndoInfo *
nautilus_file_undo_info_ownership_new(NautilusFileUndoOp op_type,GFile * file,const char * current_data,const char * new_data)2297 nautilus_file_undo_info_ownership_new (NautilusFileUndoOp  op_type,
2298                                        GFile              *file,
2299                                        const char         *current_data,
2300                                        const char         *new_data)
2301 {
2302     NautilusFileUndoInfoOwnership *self;
2303 
2304     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_OWNERSHIP,
2305                          "item-count", 1,
2306                          "op-type", op_type,
2307                          NULL);
2308 
2309     self->target_file = g_object_ref (file);
2310     self->original_ownership = g_strdup (current_data);
2311     self->new_ownership = g_strdup (new_data);
2312 
2313     return NAUTILUS_FILE_UNDO_INFO (self);
2314 }
2315 
2316 /* extract */
2317 struct _NautilusFileUndoInfoExtract
2318 {
2319     NautilusFileUndoInfo parent_instance;
2320 
2321     GList *sources;
2322     GFile *destination_directory;
2323     GList *outputs;
2324 };
2325 
G_DEFINE_TYPE(NautilusFileUndoInfoExtract,nautilus_file_undo_info_extract,NAUTILUS_TYPE_FILE_UNDO_INFO)2326 G_DEFINE_TYPE (NautilusFileUndoInfoExtract, nautilus_file_undo_info_extract, NAUTILUS_TYPE_FILE_UNDO_INFO)
2327 
2328 static void
2329 extract_callback (GList    *outputs,
2330                   gpointer  callback_data)
2331 {
2332     NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (callback_data);
2333     gboolean success;
2334 
2335     nautilus_file_undo_info_extract_set_outputs (self, outputs);
2336 
2337     success = self->outputs != NULL;
2338 
2339     file_undo_info_transfer_callback (NULL, success, self);
2340 }
2341 
2342 static void
extract_strings_func(NautilusFileUndoInfo * info,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)2343 extract_strings_func (NautilusFileUndoInfo  *info,
2344                       gchar                **undo_label,
2345                       gchar                **undo_description,
2346                       gchar                **redo_label,
2347                       gchar                **redo_description)
2348 {
2349     NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
2350     gint total_sources;
2351     gint total_outputs;
2352 
2353     *undo_label = g_strdup (_("_Undo Extract"));
2354     *redo_label = g_strdup (_("_Redo Extract"));
2355 
2356     total_sources = g_list_length (self->sources);
2357     total_outputs = g_list_length (self->outputs);
2358 
2359     if (total_outputs == 1)
2360     {
2361         GFile *output;
2362         g_autofree gchar *name = NULL;
2363 
2364         output = self->outputs->data;
2365         name = g_file_get_parse_name (output);
2366 
2367         *undo_description = g_strdup_printf (_("Delete “%s”"), name);
2368     }
2369     else
2370     {
2371         *undo_description = g_strdup_printf (ngettext ("Delete %d extracted file",
2372                                                        "Delete %d extracted files",
2373                                                        total_outputs),
2374                                              total_outputs);
2375     }
2376 
2377     if (total_sources == 1)
2378     {
2379         GFile *source;
2380         g_autofree gchar *name = NULL;
2381 
2382         source = self->sources->data;
2383         name = g_file_get_parse_name (source);
2384 
2385         *redo_description = g_strdup_printf (_("Extract “%s”"), name);
2386     }
2387     else
2388     {
2389         *redo_description = g_strdup_printf (ngettext ("Extract %d file",
2390                                                        "Extract %d files",
2391                                                        total_sources),
2392                                              total_sources);
2393     }
2394 }
2395 
2396 static void
extract_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2397 extract_redo_func (NautilusFileUndoInfo           *info,
2398                    GtkWindow                      *parent_window,
2399                    NautilusFileOperationsDBusData *dbus_data)
2400 {
2401     NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
2402 
2403     nautilus_file_operations_extract_files (self->sources,
2404                                             self->destination_directory,
2405                                             parent_window,
2406                                             dbus_data,
2407                                             extract_callback,
2408                                             self);
2409 }
2410 
2411 static void
extract_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2412 extract_undo_func (NautilusFileUndoInfo           *info,
2413                    GtkWindow                      *parent_window,
2414                    NautilusFileOperationsDBusData *dbus_data)
2415 {
2416     NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (info);
2417 
2418     nautilus_file_operations_delete_async (self->outputs, parent_window,
2419                                            dbus_data,
2420                                            file_undo_info_delete_callback, self);
2421 }
2422 
2423 static void
nautilus_file_undo_info_extract_init(NautilusFileUndoInfoExtract * self)2424 nautilus_file_undo_info_extract_init (NautilusFileUndoInfoExtract *self)
2425 {
2426 }
2427 
2428 static void
nautilus_file_undo_info_extract_finalize(GObject * obj)2429 nautilus_file_undo_info_extract_finalize (GObject *obj)
2430 {
2431     NautilusFileUndoInfoExtract *self = NAUTILUS_FILE_UNDO_INFO_EXTRACT (obj);
2432 
2433     g_object_unref (self->destination_directory);
2434     g_list_free_full (self->sources, g_object_unref);
2435     if (self->outputs)
2436     {
2437         g_list_free_full (self->outputs, g_object_unref);
2438     }
2439 
2440     G_OBJECT_CLASS (nautilus_file_undo_info_extract_parent_class)->finalize (obj);
2441 }
2442 
2443 static void
nautilus_file_undo_info_extract_class_init(NautilusFileUndoInfoExtractClass * klass)2444 nautilus_file_undo_info_extract_class_init (NautilusFileUndoInfoExtractClass *klass)
2445 {
2446     GObjectClass *oclass = G_OBJECT_CLASS (klass);
2447     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
2448 
2449     oclass->finalize = nautilus_file_undo_info_extract_finalize;
2450 
2451     iclass->undo_func = extract_undo_func;
2452     iclass->redo_func = extract_redo_func;
2453     iclass->strings_func = extract_strings_func;
2454 }
2455 
2456 void
nautilus_file_undo_info_extract_set_outputs(NautilusFileUndoInfoExtract * self,GList * outputs)2457 nautilus_file_undo_info_extract_set_outputs (NautilusFileUndoInfoExtract *self,
2458                                              GList                       *outputs)
2459 {
2460     if (self->outputs)
2461     {
2462         g_list_free_full (self->outputs, g_object_unref);
2463     }
2464     self->outputs = g_list_copy_deep (outputs,
2465                                       (GCopyFunc) g_object_ref,
2466                                       NULL);
2467 }
2468 
2469 NautilusFileUndoInfo *
nautilus_file_undo_info_extract_new(GList * sources,GFile * destination_directory)2470 nautilus_file_undo_info_extract_new (GList *sources,
2471                                      GFile *destination_directory)
2472 {
2473     NautilusFileUndoInfoExtract *self;
2474 
2475     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_EXTRACT,
2476                          "item-count", 1,
2477                          "op-type", NAUTILUS_FILE_UNDO_OP_EXTRACT,
2478                          NULL);
2479 
2480     self->sources = g_list_copy_deep (sources,
2481                                       (GCopyFunc) g_object_ref,
2482                                       NULL);
2483     self->destination_directory = g_object_ref (destination_directory);
2484 
2485     return NAUTILUS_FILE_UNDO_INFO (self);
2486 }
2487 
2488 
2489 /* compress */
2490 struct _NautilusFileUndoInfoCompress
2491 {
2492     NautilusFileUndoInfo parent_instance;
2493 
2494     GList *sources;
2495     GFile *output;
2496     AutoarFormat format;
2497     AutoarFilter filter;
2498     gchar *passphrase;
2499 };
2500 
G_DEFINE_TYPE(NautilusFileUndoInfoCompress,nautilus_file_undo_info_compress,NAUTILUS_TYPE_FILE_UNDO_INFO)2501 G_DEFINE_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_compress, NAUTILUS_TYPE_FILE_UNDO_INFO)
2502 
2503 static void
2504 compress_callback (GFile    *new_file,
2505                    gboolean  success,
2506                    gpointer  callback_data)
2507 {
2508     NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (callback_data);
2509 
2510     if (success)
2511     {
2512         g_set_object (&self->output, new_file);
2513     }
2514 
2515     file_undo_info_transfer_callback (NULL, success, self);
2516 }
2517 
2518 static void
compress_strings_func(NautilusFileUndoInfo * info,gchar ** undo_label,gchar ** undo_description,gchar ** redo_label,gchar ** redo_description)2519 compress_strings_func (NautilusFileUndoInfo  *info,
2520                        gchar                **undo_label,
2521                        gchar                **undo_description,
2522                        gchar                **redo_label,
2523                        gchar                **redo_description)
2524 {
2525     NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
2526     g_autofree gchar *output_name = NULL;
2527     gint sources_count;
2528 
2529     output_name = g_file_get_parse_name (self->output);
2530     *undo_description = g_strdup_printf (_("Delete “%s”"), output_name);
2531 
2532     sources_count = g_list_length (self->sources);
2533     if (sources_count == 1)
2534     {
2535         GFile *source;
2536         g_autofree gchar *source_name = NULL;
2537 
2538         source = self->sources->data;
2539         source_name = g_file_get_parse_name (source);
2540 
2541         *redo_description = g_strdup_printf (_("Compress “%s”"), source_name);
2542     }
2543     else
2544     {
2545         *redo_description = g_strdup_printf (ngettext ("Compress %d file",
2546                                                        "Compress %d files",
2547                                                        sources_count),
2548                                              sources_count);
2549     }
2550 
2551     *undo_label = g_strdup (_("_Undo Compress"));
2552     *redo_label = g_strdup (_("_Redo Compress"));
2553 }
2554 
2555 static void
compress_redo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2556 compress_redo_func (NautilusFileUndoInfo           *info,
2557                     GtkWindow                      *parent_window,
2558                     NautilusFileOperationsDBusData *dbus_data)
2559 {
2560     NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
2561 
2562     nautilus_file_operations_compress (self->sources,
2563                                        self->output,
2564                                        self->format,
2565                                        self->filter,
2566                                        self->passphrase,
2567                                        parent_window,
2568                                        dbus_data,
2569                                        compress_callback,
2570                                        self);
2571 }
2572 
2573 static void
compress_undo_func(NautilusFileUndoInfo * info,GtkWindow * parent_window,NautilusFileOperationsDBusData * dbus_data)2574 compress_undo_func (NautilusFileUndoInfo           *info,
2575                     GtkWindow                      *parent_window,
2576                     NautilusFileOperationsDBusData *dbus_data)
2577 {
2578     NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (info);
2579     GList *files = NULL;
2580 
2581     files = g_list_prepend (files, self->output);
2582 
2583     nautilus_file_operations_delete_async (files, parent_window,
2584                                            dbus_data,
2585                                            file_undo_info_delete_callback, self);
2586 
2587     g_list_free (files);
2588 }
2589 
2590 static void
nautilus_file_undo_info_compress_init(NautilusFileUndoInfoCompress * self)2591 nautilus_file_undo_info_compress_init (NautilusFileUndoInfoCompress *self)
2592 {
2593 }
2594 
2595 static void
nautilus_file_undo_info_compress_finalize(GObject * obj)2596 nautilus_file_undo_info_compress_finalize (GObject *obj)
2597 {
2598     NautilusFileUndoInfoCompress *self = NAUTILUS_FILE_UNDO_INFO_COMPRESS (obj);
2599 
2600     g_list_free_full (self->sources, g_object_unref);
2601     g_clear_object (&self->output);
2602     g_free (self->passphrase);
2603 
2604     G_OBJECT_CLASS (nautilus_file_undo_info_compress_parent_class)->finalize (obj);
2605 }
2606 
2607 static void
nautilus_file_undo_info_compress_class_init(NautilusFileUndoInfoCompressClass * klass)2608 nautilus_file_undo_info_compress_class_init (NautilusFileUndoInfoCompressClass *klass)
2609 {
2610     GObjectClass *oclass = G_OBJECT_CLASS (klass);
2611     NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
2612 
2613     oclass->finalize = nautilus_file_undo_info_compress_finalize;
2614 
2615     iclass->undo_func = compress_undo_func;
2616     iclass->redo_func = compress_redo_func;
2617     iclass->strings_func = compress_strings_func;
2618 }
2619 
2620 NautilusFileUndoInfo *
nautilus_file_undo_info_compress_new(GList * sources,GFile * output,AutoarFormat format,AutoarFilter filter,const gchar * passphrase)2621 nautilus_file_undo_info_compress_new (GList        *sources,
2622                                       GFile        *output,
2623                                       AutoarFormat  format,
2624                                       AutoarFilter  filter,
2625                                       const gchar  *passphrase)
2626 {
2627     NautilusFileUndoInfoCompress *self;
2628 
2629     self = g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_COMPRESS,
2630                          "item-count", 1,
2631                          "op-type", NAUTILUS_FILE_UNDO_OP_COMPRESS,
2632                          NULL);
2633 
2634     self->sources = g_list_copy_deep (sources, (GCopyFunc) g_object_ref, NULL);
2635     self->output = g_object_ref (output);
2636     self->format = format;
2637     self->filter = filter;
2638     self->passphrase = g_strdup (passphrase);
2639 
2640     return NAUTILUS_FILE_UNDO_INFO (self);
2641 }
2642