summaryrefslogtreecommitdiff
path: root/libnautilus-private/nautilus-file-undo-operations.c
diff options
context:
space:
mode:
authorCosimo Cecchi <cosimoc@gnome.org>2012-01-21 19:00:10 -0500
committerCosimo Cecchi <cosimoc@gnome.org>2012-01-21 19:00:10 -0500
commit362fb6464b62d6fed896d1bc53f6fc763f8fa6fb (patch)
treee5e6ffb2f9bebbe5b4f00510cc0492fbd3bb5610 /libnautilus-private/nautilus-file-undo-operations.c
parentc063418e66ed0fdc40b4fd48bc5bd29c0cbefa09 (diff)
downloadnautilus-362fb6464b62d6fed896d1bc53f6fc763f8fa6fb.tar.gz
undo: rework undo for the trash operation to be asynchronous
Also, make the mtime checks actually useful; we need to check the trash::deletion-date attribute and match it with the time we trashed the file (which we can easily know using g_get_current_time()).
Diffstat (limited to 'libnautilus-private/nautilus-file-undo-operations.c')
-rw-r--r--libnautilus-private/nautilus-file-undo-operations.c215
1 files changed, 137 insertions, 78 deletions
diff --git a/libnautilus-private/nautilus-file-undo-operations.c b/libnautilus-private/nautilus-file-undo-operations.c
index 4b8fa1f0d..d2d1f7659 100644
--- a/libnautilus-private/nautilus-file-undo-operations.c
+++ b/libnautilus-private/nautilus-file-undo-operations.c
@@ -72,67 +72,6 @@ uri_list_to_gfile_list (GList * urilist)
return file_list;
}
-/* TODO: Synch-I/O, error handling */
-static GHashTable *
-retrieve_files_to_restore (GHashTable * trashed)
-{
- GFileEnumerator *enumerator;
- GHashTable *to_restore;
- GFile *trash;
-
- to_restore = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, g_free);
-
- trash = g_file_new_for_uri ("trash:///");
-
- enumerator = g_file_enumerate_children (trash,
- G_FILE_ATTRIBUTE_STANDARD_NAME","
- G_FILE_ATTRIBUTE_TIME_MODIFIED","
- G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, NULL);
-
- if (enumerator) {
- GFileInfo *info;
- guint64 *mtime;
- gpointer lookupvalue;
- GFile *item;
- guint64 mtime_item;
- char *origpath;
- GFile *origfile;
- char *origuri;
-
- mtime = 0;
- while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) {
- /* Retrieve the original file uri */
- origpath = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
- origfile = g_file_new_for_path (origpath);
- origuri = g_file_get_uri (origfile);
- g_object_unref (origfile);
- g_free (origpath);
-
- lookupvalue = g_hash_table_lookup (trashed, origuri);
-
- if (lookupvalue) {
- mtime = (guint64 *)lookupvalue;
- mtime_item = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
- if (*mtime == mtime_item) {
- /* File in the trash */
- item = g_file_get_child (trash, g_file_info_get_name (info));
- g_hash_table_insert (to_restore, item, origuri);
- }
- } else {
- g_free (origuri);
- }
-
- }
- g_file_enumerator_close (enumerator, FALSE, NULL);
- g_object_unref (enumerator);
- }
- g_object_unref (trash);
-
- return to_restore;
-}
-
/* description helpers */
static void
nautilus_file_undo_info_init (NautilusFileUndoInfo *self)
@@ -1062,19 +1001,123 @@ trash_redo_func (NautilusFileUndoInfo *info,
}
}
+static GHashTable *
+trash_retrieve_files_to_restore_finish (NautilusFileUndoInfoTrash *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GHashTable *retval = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+
+ if (retval == NULL) {
+ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+ }
+
+ return retval;
+}
+
static void
-trash_undo_func (NautilusFileUndoInfo *info,
- GtkWindow *parent_window)
+trash_retrieve_files_to_restore_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
{
- NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
- GHashTable *files_to_restore;
+ NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (object);
+ GFileEnumerator *enumerator;
+ GHashTable *to_restore;
+ GFile *trash;
+ GError *error = NULL;
- /* Internally managed op, pop flag. */
- nautilus_file_undo_manager_pop_flag ();
+ to_restore = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, g_free);
+
+ trash = g_file_new_for_uri ("trash:///");
- files_to_restore = retrieve_files_to_restore (self->priv->trashed);
+ enumerator = g_file_enumerate_children (trash,
+ G_FILE_ATTRIBUTE_STANDARD_NAME","
+ G_FILE_ATTRIBUTE_TRASH_DELETION_DATE","
+ G_FILE_ATTRIBUTE_TRASH_ORIG_PATH,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, &error);
+
+ if (enumerator) {
+ GFileInfo *info;
+ gpointer lookupvalue;
+ GFile *item;
+ GTimeVal timeval;
+ glong trash_time, orig_trash_time;
+ char *origpath;
+ GFile *origfile;
+ char *origuri;
+ const char *time_string;
+
+ while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL) {
+ /* Retrieve the original file uri */
+ origpath = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_TRASH_ORIG_PATH);
+ origfile = g_file_new_for_path (origpath);
+ origuri = g_file_get_uri (origfile);
+ g_object_unref (origfile);
+ g_free (origpath);
+
+ lookupvalue = g_hash_table_lookup (self->priv->trashed, origuri);
- if (g_hash_table_size (files_to_restore) > 0) {
+ if (lookupvalue) {
+ orig_trash_time = GPOINTER_TO_SIZE (lookupvalue);
+ time_string = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_TRASH_DELETION_DATE);
+ if (time_string != NULL) {
+ g_time_val_from_iso8601 (time_string, &timeval);
+ trash_time = timeval.tv_sec;
+ } else {
+ trash_time = 0;
+ }
+
+ if (trash_time == orig_trash_time) {
+ /* File in the trash */
+ item = g_file_get_child (trash, g_file_info_get_name (info));
+ g_hash_table_insert (to_restore, item, origuri);
+ }
+ } else {
+ g_free (origuri);
+ }
+
+ }
+ g_file_enumerator_close (enumerator, FALSE, NULL);
+ g_object_unref (enumerator);
+ }
+ g_object_unref (trash);
+
+ if (error != NULL) {
+ g_simple_async_result_take_error (res, error);
+ g_hash_table_destroy (to_restore);
+ } else {
+ g_simple_async_result_set_op_res_gpointer (res, to_restore, NULL);
+ }
+}
+
+static void
+trash_retrieve_files_to_restore_async (NautilusFileUndoInfoTrash *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *async_op;
+
+ async_op = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+ trash_retrieve_files_to_restore_async);
+ g_simple_async_result_run_in_thread (async_op, trash_retrieve_files_to_restore_thread,
+ G_PRIORITY_DEFAULT, NULL);
+
+ g_object_unref (async_op);
+}
+
+static void
+trash_retrieve_files_ready (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (source);
+ GHashTable *files_to_restore;
+ GError *error = NULL;
+
+ files_to_restore = trash_retrieve_files_to_restore_finish (self, res, &error);
+
+ if (error == NULL && g_hash_table_size (files_to_restore) > 0) {
GList *gfiles_in_trash, *l;
GFile *item;
GFile *dest;
@@ -1086,6 +1129,7 @@ trash_undo_func (NautilusFileUndoInfo *info,
item = l->data;
value = g_hash_table_lookup (files_to_restore, item);
dest = g_file_new_for_uri (value);
+
g_file_move (item, dest, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, NULL, NULL, NULL);
g_object_unref (dest);
}
@@ -1093,10 +1137,25 @@ trash_undo_func (NautilusFileUndoInfo *info,
g_list_free (gfiles_in_trash);
}
- g_hash_table_destroy (files_to_restore);
+ if (files_to_restore != NULL) {
+ g_hash_table_destroy (files_to_restore);
+ }
/* Here we must do what's necessary for the callback */
- file_undo_info_transfer_callback (NULL, TRUE, self);
+ file_undo_info_transfer_callback (NULL, (error != NULL), self);
+ g_clear_error (&error);
+}
+
+static void
+trash_undo_func (NautilusFileUndoInfo *info,
+ GtkWindow *parent_window)
+{
+ NautilusFileUndoInfoTrash *self = NAUTILUS_FILE_UNDO_INFO_TRASH (info);
+
+ /* Internally managed op, pop flag. */
+ nautilus_file_undo_manager_pop_flag ();
+
+ trash_retrieve_files_to_restore_async (self, trash_retrieve_files_ready, NULL);
}
static void
@@ -1143,17 +1202,17 @@ nautilus_file_undo_info_trash_new (gint item_count)
void
nautilus_file_undo_info_trash_add_file (NautilusFileUndoInfoTrash *self,
- GFile *file,
- guint64 mtime)
+ GFile *file)
{
- guint64 *modification_time;
+ GTimeVal current_time;
+ gsize orig_trash_time;
gchar *original_uri;
- modification_time = g_new (guint64, 1);
- *modification_time = mtime;
-
+ g_get_current_time (&current_time);
+ orig_trash_time = current_time.tv_sec;
original_uri = g_file_get_uri (file);
- g_hash_table_insert (self->priv->trashed, original_uri, modification_time);
+
+ g_hash_table_insert (self->priv->trashed, original_uri, GSIZE_TO_POINTER (orig_trash_time));
}
/* recursive permissions */