[gthumb/ext: 58/79] Started work on copying folders recursively.



commit f9b389f3eecba08749ad19b023c91997fdaf90a6
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Jul 22 21:10:03 2009 +0200

    Started work on copying folders recursively.

 extensions/catalogs/gth-file-source-catalogs.c |    1 +
 extensions/comments/main.c                     |    9 +-
 extensions/file_manager/gth-copy-task.c        |    1 +
 extensions/file_manager/gth-duplicate-task.c   |   21 +-
 gthumb/file-cache.c                            |    2 +
 gthumb/gio-utils.c                             |  907 +++++++++---------------
 gthumb/gio-utils.h                             |   40 +-
 gthumb/glib-utils.c                            |   22 +
 gthumb/glib-utils.h                            |    1 +
 gthumb/gth-file-source-vfs.c                   |  192 +-----
 gthumb/gth-file-source.c                       |    9 +-
 gthumb/gth-file-source.h                       |    2 +
 gthumb/gth-main-default-hooks.c                |    4 +-
 13 files changed, 427 insertions(+), 784 deletions(-)
---
diff --git a/extensions/catalogs/gth-file-source-catalogs.c b/extensions/catalogs/gth-file-source-catalogs.c
index 3119747..01a216f 100644
--- a/extensions/catalogs/gth-file-source-catalogs.c
+++ b/extensions/catalogs/gth-file-source-catalogs.c
@@ -417,6 +417,7 @@ static void
 gth_file_source_catalogs_copy (GthFileSource    *file_source,
 			       GthFileData      *destination,
 			       GList            *file_list, /* GFile * list */
+			       gboolean          move,
 			       ProgressCallback  progress_callback,
 			       ReadyCallback     ready_callback,
 			       gpointer          data)
diff --git a/extensions/comments/main.c b/extensions/comments/main.c
index 26832dc..dc7a54a 100644
--- a/extensions/comments/main.c
+++ b/extensions/comments/main.c
@@ -67,15 +67,10 @@ get_place_for_test (GthTest       *test,
 
 
 void
-comments__add_sidecars_cb (GList  *sources,
+comments__add_sidecars_cb (GFile  *file,
 			   GList **sidecars)
 {
-	GList *scan;
-
-	for (scan = sources; scan; scan = scan->next) {
-		GFile *file = (GFile *) scan->data;
-		*sidecars = g_list_prepend (*sidecars, gth_comment_get_comment_file (file));
-	}
+	*sidecars = g_list_prepend (*sidecars, gth_comment_get_comment_file (file));
 }
 
 
diff --git a/extensions/file_manager/gth-copy-task.c b/extensions/file_manager/gth-copy-task.c
index 61a1251..39c6540 100644
--- a/extensions/file_manager/gth-copy-task.c
+++ b/extensions/file_manager/gth-copy-task.c
@@ -85,6 +85,7 @@ gth_copy_task_exec (GthTask *task)
 	gth_file_source_copy (self->priv->file_source,
 			      self->priv->destination,
 			      self->priv->files,
+			      self->priv->move,
 			      copy_progress_cb,
 			      copy_done_cb,
 			      self);
diff --git a/extensions/file_manager/gth-duplicate-task.c b/extensions/file_manager/gth-duplicate-task.c
index b56ab5f..02e451a 100644
--- a/extensions/file_manager/gth-duplicate-task.c
+++ b/extensions/file_manager/gth-duplicate-task.c
@@ -77,21 +77,15 @@ get_destination (GthFileData *file_data,
 
 
 static void
-copy_progress_cb (goffset      current_file,
-                  goffset      total_files,
-                  GFile       *source,
-                  GFile       *destination,
-                  goffset      current_num_bytes,
-                  goffset      total_num_bytes,
-                  gpointer     user_data)
+copy_progress_cb (GObject    *object,
+		  const char *description,
+		  const char *details,
+		  gboolean    pulse,
+		  double      fraction,
+		  gpointer    user_data)
 {
 	GthDuplicateTask *self = user_data;
-	char             *name;
-
-	name = _g_file_get_display_name (source);
-	gth_task_progress (GTH_TASK (self), _("Duplicating files"), name, FALSE, (double) current_num_bytes / total_num_bytes);
-
-	g_free (name);
+	gth_task_progress (GTH_TASK (self), _("Duplicating files"), details, pulse, fraction);
 }
 
 
@@ -139,6 +133,7 @@ duplicate_current_file (GthDuplicateTask *self)
 
 	_g_copy_file_async (file_data->file,
 			    destination,
+			    FALSE,
 			    G_FILE_COPY_ALL_METADATA,
 			    G_PRIORITY_DEFAULT,
 			    self->priv->cancellable,
diff --git a/gthumb/file-cache.c b/gthumb/file-cache.c
index 3e1e1a4..bb48cf9 100644
--- a/gthumb/file-cache.c
+++ b/gthumb/file-cache.c
@@ -264,6 +264,7 @@ copy_remote_file_to_cache (GthFileData      *file_data,
 		copy_data->dummy = FALSE;
 		_g_copy_file_async (file_data->file,
 				    cache_file,
+				    FALSE,
 				    G_FILE_COPY_OVERWRITE,
 				    G_PRIORITY_DEFAULT,
 				    cancellable,
@@ -325,6 +326,7 @@ update_file_from_cache (GthFileData      *file_data,
 	{
 		_g_copy_file_async (cache_file,
 				    file_data->file,
+				    FALSE,
 				    G_FILE_COPY_OVERWRITE,
 				    G_PRIORITY_DEFAULT,
 				    cancellable,
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index 832cdbb..42dad45 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -22,6 +22,7 @@
 
 #include <string.h>
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <gio/gio.h>
 #include "gth-file-data.h"
 #include "gth-hook.h"
@@ -870,87 +871,30 @@ g_query_info_async (GList             *files,
 }
 
 
-/* -- g_copy_files_async -- */
+/* -- _g_dummy_file_op_async  -- */
 
 
 typedef struct {
-	GList                 *sources;
-	GList                 *destinations;
-	GFileCopyFlags         flags;
-	int                    io_priority;
-	GCancellable          *cancellable;
-	CopyProgressCallback   progress_callback;
-	gpointer               progress_callback_data;
-	CopyDoneCallback       callback;
-	gpointer               user_data;
-
-	GList                 *source;
-	GList                 *destination;
-	int                    n_file;
-	int                    tot_files;
-
-	guint                  dummy_event;
-} CopyFilesData;
-
-
-static CopyFilesData*
-copy_files_data_new (GList                 *sources,
-		     GList                 *destinations,
-		     GFileCopyFlags         flags,
-		     int                    io_priority,
-		     GCancellable          *cancellable,
-		     CopyProgressCallback   progress_callback,
-		     gpointer               progress_callback_data,
-		     CopyDoneCallback       callback,
-		     gpointer               user_data)
-{
-	CopyFilesData *cfd;
-
-	cfd = g_new0 (CopyFilesData, 1);
-	cfd->sources = _g_file_list_dup (sources);
-	cfd->destinations = _g_file_list_dup (destinations);
-	cfd->flags = flags;
-	cfd->io_priority = io_priority;
-	cfd->cancellable = cancellable;
-	cfd->progress_callback = progress_callback;
-	cfd->progress_callback_data = progress_callback_data;
-	cfd->callback = callback;
-	cfd->user_data = user_data;
-
-	cfd->source = cfd->sources;
-	cfd->destination = cfd->destinations;
-	cfd->n_file = 1;
-	cfd->tot_files = g_list_length (cfd->sources);
-
-	return cfd;
-}
-
-
-static void
-copy_files_data_free (CopyFilesData *cfd)
-{
-	if (cfd == NULL)
-		return;
-	_g_file_list_free (cfd->sources);
-	_g_file_list_free (cfd->destinations);
-	g_free (cfd);
-}
+	CopyDoneCallback callback;
+	gpointer         user_data;
+	gulong           dummy_event;
+} DummyFileCopy;
 
 
 gboolean
 _g_dummy_file_op_completed (gpointer data)
 {
-	CopyFilesData *cfd = data;
+	DummyFileCopy *dfd = data;
 
-	if (cfd->dummy_event != 0) {
-		g_source_remove (cfd->dummy_event);
-		cfd->dummy_event = 0;
+	if (dfd->dummy_event != 0) {
+		g_source_remove (dfd->dummy_event);
+		dfd->dummy_event = 0;
 	}
 
-	if (cfd->callback)
-		cfd->callback (NULL, cfd->user_data);
+	if (dfd->callback)
+		dfd->callback (NULL, dfd->user_data);
 
-	copy_files_data_free (cfd);
+	g_free (dfd);
 
 	return FALSE;
 }
@@ -960,543 +904,447 @@ void
 _g_dummy_file_op_async (CopyDoneCallback callback,
 			gpointer         user_data)
 {
-	CopyFilesData *cfd;
+	DummyFileCopy *dfd;
 
-	cfd = copy_files_data_new (NULL,
-				   NULL,
-				   0,
-				   0,
-				   NULL,
-				   NULL,
-				   NULL,
-				   callback,
-				   user_data);
-	cfd->dummy_event = g_idle_add (_g_dummy_file_op_completed, cfd);
+	dfd = g_new0 (DummyFileCopy, 1);
+	dfd->callback = callback;
+	dfd->user_data = user_data;
+	dfd->dummy_event = g_idle_add (_g_dummy_file_op_completed, dfd);
 }
 
 
-static void g_copy_current_file (CopyFilesData *cfd);
+/* -- _g_copy_files_async -- */
 
 
-static void
-g_copy_next_file (CopyFilesData *cfd)
-{
-	cfd->source = g_list_next (cfd->source);
-	cfd->destination = g_list_next (cfd->destination);
-	cfd->n_file++;
+typedef struct {
+	GFile             *destination;
 
-	g_copy_current_file (cfd);
-}
+	GList             *dirs;  /* GFile list */
+	GList             *current_dir;
 
+	GList             *sources;  /* GFile list */
+	GList             *destinations;  /* GFile list */
+	GList             *current_source;
+	GList             *current_destination;
 
-static void
-g_copy_files_ready_cb (GObject      *source_object,
-		       GAsyncResult *result,
-		       gpointer      user_data)
-{
-	CopyFilesData *cfd = user_data;
-	GFile         *source = cfd->source->data;
-	GError        *error = NULL;
+	GList             *source_sidecars;  /* GFile list */
+	GList             *destination_sidecars;  /* GFile list */
+	GList             *current_source_sidecar;
+	GList             *current_destination_sidecar;
 
-	if (! g_file_copy_finish (source, result, &error)) {
-		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
-			g_clear_error (&error);
-			g_copy_next_file (cfd);
-			return;
-		}
+	GList             *current_directory_childs;  /* GFile list */
 
-		if (cfd->callback)
-			cfd->callback (error, cfd->user_data);
-		copy_files_data_free (cfd);
-		return;
-	}
+	int                n_files;
+	int                n_current;
 
-	g_copy_next_file (cfd);
-}
+	gboolean           move;
+	GFileCopyFlags     flags;
+	int                io_priority;
+	GCancellable      *cancellable;
+	ProgressCallback   progress_callback;
+	gpointer           progress_callback_data;
+	CopyDoneCallback   done_callback;
+	gpointer           user_data;
+} CopyData;
 
 
 static void
-g_copy_files_progess_cb (goffset  current_num_bytes,
-			 goffset  total_num_bytes,
-			 gpointer user_data)
+copy_data_free (CopyData *copy_data)
 {
-	CopyFilesData *cfd = user_data;
-
-	if (cfd->progress_callback)
-		cfd->progress_callback (cfd->n_file,
-					cfd->tot_files,
-					(GFile*) cfd->source->data,
-					(GFile*) cfd->destination->data,
-					current_num_bytes,
-					total_num_bytes,
-					cfd->progress_callback_data);
+	_g_object_list_unref (copy_data->current_directory_childs);
+	_g_object_list_unref (copy_data->destination_sidecars);
+	_g_object_list_unref (copy_data->source_sidecars);
+	_g_object_list_unref (copy_data->destinations);
+	_g_object_list_unref (copy_data->sources);
+	_g_object_list_unref (copy_data->dirs);
+	g_object_unref (copy_data->destination);
+	_g_object_unref (copy_data->cancellable);
+	g_free (copy_data);
 }
 
 
+static void copy_data__copy_current_directory_to_destination (CopyData *copy_data);
+
+
 static void
-g_copy_current_file (CopyFilesData *cfd)
+copy_data__copy_current_directory__done_cb (GError   *error,
+				            gpointer  user_data)
 {
-	if ((cfd->source == NULL) || (cfd->destination == NULL)) {
-		if (cfd->callback)
-			cfd->callback (NULL, cfd->user_data);
-		copy_files_data_free (cfd);
+	CopyData *copy_data = user_data;
+
+	if (error != NULL) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
 		return;
 	}
 
-	g_file_copy_async ((GFile*) cfd->source->data,
-			   (GFile*) cfd->destination->data,
-			   cfd->flags,
-			   cfd->io_priority,
-			   cfd->cancellable,
-			   g_copy_files_progess_cb,
-			   cfd,
-			   g_copy_files_ready_cb,
-			   cfd);
+	if (copy_data->move && ! g_file_delete ((GFile *) copy_data->current_dir->data, copy_data->cancellable, &error)) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
+		return;
+	}
+
+	copy_data->current_dir = copy_data->current_dir->next;
+	copy_data__copy_current_directory_to_destination (copy_data);
 }
 
 
-void
-g_copy_files_async (GList                 *sources,
-		    GList                 *destinations,
-		    GFileCopyFlags         flags,
-		    int                    io_priority,
-		    GCancellable          *cancellable,
-		    CopyProgressCallback   progress_callback,
-		    gpointer               progress_callback_data,
-		    CopyDoneCallback       callback,
-		    gpointer               user_data)
+static void
+copy_data__copy_current_directory__childs_done_cb (GError   *error,
+				                   gpointer  user_data)
 {
-	CopyFilesData *cfd;
-
-	cfd = copy_files_data_new (sources,
-				   destinations,
-				   flags,
-				   io_priority,
-				   cancellable,
-				   progress_callback,
-				   progress_callback_data,
-				   callback,
-				   user_data);
-
-	/* add the metadata sidecars if requested */
-
-	if (flags && G_FILE_COPY_ALL_METADATA) {
-		GList *source_sidecars = NULL;
-		GList *destination_sidecars = NULL;
+	CopyData *copy_data = user_data;
+	GFile    *current_directory;
+	char     *name;
+	GFile    *destination;
 
-		gth_hook_invoke ("add-sidecars", sources, &source_sidecars);
-		gth_hook_invoke ("add-sidecars", destinations, &destination_sidecars);
-
-		source_sidecars = g_list_reverse (source_sidecars);
-		destination_sidecars = g_list_reverse (destination_sidecars);
-
-		cfd->sources = g_list_concat (cfd->sources, source_sidecars);
-		cfd->destinations = g_list_concat (cfd->destinations, destination_sidecars);
+	if (error != NULL) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
+		return;
 	}
 
-	/* create the destination folders */
-
-	{
-		GHashTable *folders;
-		GList      *scan;
-		GList      *folder_list;
+	current_directory = (GFile *) copy_data->current_dir->data;
+	name = g_file_get_basename (current_directory);
+	destination = g_file_get_child (copy_data->destination, name);
 
-		folders = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, (GDestroyNotify) g_object_unref, NULL);
-		for (scan = cfd->destinations; scan; scan = scan->next) {
-			GFile *file = scan->data;
-			GFile *folder;
-
-			folder = g_file_get_parent (file);
-			if (folder == NULL)
-				continue;
-
-			if (! g_hash_table_lookup (folders, folder))
-				g_hash_table_insert (folders, g_object_ref (folder), GINT_TO_POINTER (1));
-
-			g_object_unref (folder);
-		}
-
-		folder_list = g_hash_table_get_keys (folders);
-		for (scan = folder_list; scan; scan = scan->next) {
-			GFile *folder = scan->data;
-
-			g_file_make_directory_with_parents (folder, NULL, NULL);
-		}
-
-		g_list_free (folder_list);
-		g_hash_table_destroy (folders);
+	if (! g_file_make_directory (destination, copy_data->cancellable, &error)) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
+		return;
 	}
 
-	/* copy a file at a time */
+	_g_copy_files_async (copy_data->current_directory_childs,
+			     destination,
+			     copy_data->move,
+			     copy_data->flags,
+			     copy_data->io_priority,
+			     copy_data->cancellable,
+			     copy_data->progress_callback,
+			     copy_data->progress_callback_data,
+			     copy_data__copy_current_directory__done_cb,
+			     copy_data);
 
-	g_copy_current_file (cfd);
+	g_object_unref (destination);
 }
 
 
-void
-_g_copy_file_async (GFile                 *source,
-		    GFile                 *destination,
-		    GFileCopyFlags         flags,
-		    int                    io_priority,
-		    GCancellable          *cancellable,
-		    CopyProgressCallback   progress_callback,
-		    gpointer               progress_callback_data,
-		    CopyDoneCallback       callback,
-		    gpointer               user_data)
+static void
+copy_data__copy_current_directory__for_each_file_cb (GFile     *file,
+						     GFileInfo *info,
+						     gpointer   user_data)
 {
-	GList *source_files;
-	GList *destination_files;
-
-	source_files = g_list_append (NULL, (gpointer) source);
-	destination_files = g_list_append (NULL, (gpointer) destination);
-
-	g_copy_files_async (source_files,
-			    destination_files,
-			    flags,
-			    io_priority,
-			    cancellable,
-			    progress_callback,
-			    progress_callback_data,
-			    callback,
-			    user_data);
-
-	g_list_free (source_files);
-	g_list_free (destination_files);
+	CopyData *copy_data = user_data;
+	copy_data->current_directory_childs = g_list_prepend (copy_data->current_directory_childs, g_object_ref (file));
 }
 
 
-/* -- g_directory_copy_async -- */
-
-
-typedef struct {
-	GFile                 *source;
-	GFile                 *destination;
-	GFileCopyFlags         flags;
-	int                    io_priority;
-	GCancellable          *cancellable;
-	CopyProgressCallback   progress_callback;
-	gpointer               progress_callback_data;
-	CopyDoneCallback       callback;
-	gpointer               user_data;
-	GError                *error;
-
-	GList                 *to_copy;
-	GList                 *current;
-	GFile                 *current_source;
-	GFile                 *current_destination;
-	int                    n_file, tot_files;
-	guint                  source_id;
-} DirectoryCopyData;
-
-
 static void
-directory_copy_data_free (DirectoryCopyData *dcd)
+copy_data__copy_current_directory_to_destination (CopyData *copy_data)
 {
-	if (dcd == NULL)
+	if (copy_data->current_dir == NULL) {
+		copy_data->done_callback (NULL, copy_data->user_data);
+		copy_data_free (copy_data);
 		return;
-
-	g_object_unref (dcd->source);
-	g_object_unref (dcd->destination);
-	if (dcd->current_source != NULL) {
-		g_object_unref (dcd->current_source);
-		dcd->current_source = NULL;
 	}
-	if (dcd->current_destination != NULL) {
-		g_object_unref (dcd->current_destination);
-		dcd->current_destination = NULL;
-	}
-	g_list_foreach (dcd->to_copy, (GFunc) child_data_free, NULL);
-	g_list_free (dcd->to_copy);
-	g_object_unref (dcd->cancellable);
-	g_free (dcd);
-}
-
-
-static gboolean
-g_directory_copy_done (gpointer user_data)
-{
-	DirectoryCopyData *dcd = user_data;
 
-	if (dcd->source_id != 0)
-		g_source_remove (dcd->source_id);
-
-	if (dcd->callback)
-		dcd->callback (dcd->error, dcd->user_data);
-	directory_copy_data_free (dcd);
-
-	return FALSE;
+	_g_object_list_unref (copy_data->current_directory_childs);
+	copy_data->current_directory_childs = NULL;
+	g_directory_foreach_child ((GFile *) copy_data->current_dir->data,
+				   FALSE,
+				   TRUE,
+				   "standard::name,standard::type",
+				   copy_data->cancellable,
+				   NULL,
+				   copy_data__copy_current_directory__for_each_file_cb,
+				   copy_data__copy_current_directory__childs_done_cb,
+				   copy_data);
 }
 
 
-static GFile *
-get_destination_for_file (DirectoryCopyData *dcd,
-			  GFile             *file)
-{
-	char  *uri;
-	char  *source_uri;
-	char  *partial_uri;
-	char  *path;
-	GFile *destination_file;
+static void copy_data__copy_current_sidecar (CopyData *copy_data);
 
-	if (! g_file_has_prefix (file, dcd->source))
-		return NULL;
 
-	uri = g_file_get_uri (file);
-	source_uri = g_file_get_uri (dcd->source);
-	partial_uri = uri + strlen (source_uri) + 1;
-	path = g_uri_unescape_string (partial_uri, "");
-	destination_file = _g_file_append_path (dcd->destination, path);
+static void
+copy_data__copy_current_sidecar_ready_cb (GObject      *source_object,
+				          GAsyncResult *result,
+				          gpointer      user_data)
+{
+	CopyData *copy_data = user_data;
 
-	g_free (path);
-	g_free (source_uri);
-	g_free (uri);
+	if (g_file_copy_finish ((GFile *) source_object, result, NULL)) {
+		if (copy_data->move)
+			g_file_delete ((GFile *) copy_data->current_source_sidecar->data, copy_data->cancellable, NULL);
+	}
 
-	return destination_file;
+	copy_data->current_source_sidecar = copy_data->current_source_sidecar->next;
+	copy_data->current_destination_sidecar = copy_data->current_destination_sidecar->next;
+	copy_data__copy_current_sidecar (copy_data);
 }
 
 
-static void g_directory_copy_current_child (DirectoryCopyData *dcd);
-
-
-static gboolean
-g_directory_copy_next_child (gpointer user_data)
-{
-	DirectoryCopyData *dcd = user_data;
-
-	g_source_remove (dcd->source_id);
-
-	dcd->current = g_list_next (dcd->current);
-	dcd->n_file++;
-	g_directory_copy_current_child (dcd);
-
-	return FALSE;
-}
+static void copy_data__copy_current_file (CopyData *copy_data);
 
 
 static void
-g_directory_copy_child_done_cb (GObject      *source_object,
-				GAsyncResult *result,
-				 gpointer     user_data)
+copy_data__copy_current_sidecar (CopyData *copy_data)
 {
-	DirectoryCopyData *dcd = user_data;
+	GFile *source;
+	GFile *destination;
 
-	if (! g_file_copy_finish ((GFile*)source_object, result, &(dcd->error))) {
-		dcd->source_id = g_idle_add (g_directory_copy_done, dcd);
+	if (copy_data->current_source_sidecar == NULL) {
+		copy_data->current_source = copy_data->current_source->next;
+		copy_data->current_destination = copy_data->current_destination->next;
+		copy_data__copy_current_file (copy_data);
 		return;
 	}
 
-	dcd->source_id = g_idle_add (g_directory_copy_next_child, dcd);
-}
-
-
-static void
-g_directory_copy_child_progess_cb (goffset  current_num_bytes,
-				      goffset  total_num_bytes,
-				      gpointer user_data)
-{
-	DirectoryCopyData *dcd = user_data;
-
-	if (dcd->progress_callback)
-		dcd->progress_callback (dcd->n_file,
-					dcd->tot_files,
-					dcd->current_source,
-					dcd->current_destination,
-					current_num_bytes,
-					total_num_bytes,
-					dcd->progress_callback_data);
+	source = copy_data->current_source_sidecar->data;
+	destination = copy_data->current_destination_sidecar->data;
+	g_file_copy_async (source,
+			   destination,
+			   G_FILE_COPY_OVERWRITE,
+			   copy_data->io_priority,
+			   copy_data->cancellable,
+			   NULL,
+			   NULL,
+			   copy_data__copy_current_sidecar_ready_cb,
+			   copy_data);
 }
 
 
 static void
-g_directory_copy_current_child (DirectoryCopyData *dcd)
+copy_data__copy_current_file_ready_cb (GObject      *source_object,
+				       GAsyncResult *result,
+				       gpointer      user_data)
 {
-	ChildData *child;
-	gboolean   async_op = FALSE;
+	CopyData *copy_data = user_data;
+	GError   *error = NULL;
+	GFile    *source;
+	GFile    *destination;
 
-	if (dcd->current == NULL) {
-		dcd->source_id = g_idle_add (g_directory_copy_done, dcd);
+	if (! g_file_copy_finish ((GFile *) source_object, result, &error)) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
 		return;
 	}
 
-	if (dcd->current_source != NULL) {
-		g_object_unref (dcd->current_source);
-		dcd->current_source = NULL;
-	}
-	if (dcd->current_destination != NULL) {
-		g_object_unref (dcd->current_destination);
-		dcd->current_destination = NULL;
-	}
+	source = (GFile *) copy_data->current_source->data;
+	destination = (GFile *) copy_data->current_destination->data;
 
-	child = dcd->current->data;
-	dcd->current_source = g_file_dup (child->file);
-	dcd->current_destination = get_destination_for_file (dcd, child->file);
-	if (dcd->current_destination == NULL) {
-		dcd->source_id = g_idle_add (g_directory_copy_next_child, dcd);
-		return;
-	}
+	if (copy_data->move)
+		g_file_delete (source, copy_data->cancellable, NULL);
 
-	switch (g_file_info_get_file_type (child->info)) {
-	case G_FILE_TYPE_DIRECTORY:
-		/* FIXME: how to make a directory asynchronously ? */
-
-		/* doesn't check the returned error for now, because when an
-		 * error occurs the code is not returned (for example when
-		 * a directory already exists the G_IO_ERROR_EXISTS code is
-		 * *not* returned), so we cannot discriminate between warnings
-		 * and fatal errors. (see bug #525155) */
-
-		g_file_make_directory (dcd->current_destination,
-				       NULL,
-				       NULL);
-
-		/*if (! g_file_make_directory (dcd->current_destination,
-					     dcd->cancellable,
-					     &(dcd->error)))
-		{
-			dcd->source_id = g_idle_add (g_directory_copy_done, dcd);
-			return;
-		}*/
-		break;
-	case G_FILE_TYPE_SYMBOLIC_LINK:
-		/* FIXME: how to make a link asynchronously ? */
-
-		g_file_make_symbolic_link (dcd->current_destination,
-					   g_file_info_get_symlink_target (child->info),
-					   NULL,
-					   NULL);
-
-		/*if (! g_file_make_symbolic_link (dcd->current_destination,
-						 g_file_info_get_symlink_target (child->info),
-						 dcd->cancellable,
-						 &(dcd->error)))
-		{
-			dcd->source_id = g_idle_add (g_directory_copy_done, dcd);
-			return;
-		}*/
-		break;
-	case G_FILE_TYPE_REGULAR:
-		g_file_copy_async (dcd->current_source,
-				   dcd->current_destination,
-				   dcd->flags,
-				   dcd->io_priority,
-				   dcd->cancellable,
-				   g_directory_copy_child_progess_cb,
-				   dcd,
-				   g_directory_copy_child_done_cb,
-				   dcd);
-		async_op = TRUE;
-		break;
-	default:
-		break;
+	/* copy the metadata sidecars if requested */
+
+	_g_object_list_unref (copy_data->source_sidecars);
+	_g_object_list_unref (copy_data->destination_sidecars);
+	copy_data->source_sidecars = NULL;
+	copy_data->destination_sidecars = NULL;
+	if (copy_data->flags && G_FILE_COPY_ALL_METADATA) {
+		gth_hook_invoke ("add-sidecars", source, &copy_data->source_sidecars);
+		gth_hook_invoke ("add-sidecars", destination, &copy_data->destination_sidecars);
+
+		copy_data->source_sidecars = g_list_reverse (copy_data->source_sidecars);
+		copy_data->destination_sidecars = g_list_reverse (copy_data->destination_sidecars);
 	}
 
-	if (! async_op)
-		dcd->source_id = g_idle_add (g_directory_copy_next_child, dcd);
+	copy_data->current_source_sidecar = copy_data->source_sidecars;
+	copy_data->current_destination_sidecar = copy_data->destination_sidecars;
+	copy_data__copy_current_sidecar (copy_data);
 }
 
 
-static gboolean
-g_directory_copy_start_copying (gpointer user_data)
+static void
+copy_data__copy_current_file_progress_cb (goffset  current_num_bytes,
+                                          goffset  total_num_bytes,
+                                          gpointer user_data)
 {
-	DirectoryCopyData *dcd = user_data;
-
-	g_source_remove (dcd->source_id);
-
-	dcd->to_copy = g_list_reverse (dcd->to_copy);
-	dcd->current = dcd->to_copy;
-	dcd->n_file = 1;
-	g_directory_copy_current_child (dcd);
+	/*CopyData *copy_data = user_data;*/
 
-	return FALSE;
+	/* FIXME */
 }
 
 
 static void
-g_directory_copy_list_ready (GError   *error,
-			     gpointer  user_data)
+copy_data__copy_current_file (CopyData *copy_data)
 {
-	DirectoryCopyData *dcd = user_data;
+	GFile *source;
+	GFile *destination;
 
-	if (error != NULL) {
-		dcd->error = g_error_copy (error);
-		dcd->source_id = g_idle_add (g_directory_copy_done, dcd);
+	if (copy_data->current_source == NULL) {
+		copy_data->current_dir = copy_data->dirs;
+		copy_data__copy_current_directory_to_destination (copy_data);
 		return;
 	}
 
-	dcd->source_id = g_idle_add (g_directory_copy_start_copying, dcd);
+	copy_data->n_current++;
+
+	source = copy_data->current_source->data;
+	destination = copy_data->current_destination->data;
+
+	if (copy_data->progress_callback != NULL) {
+		char *details;
+		char *source_name;
+		char *destination_name;
+
+		source_name = _g_file_get_display_name (source);
+		destination_name = _g_file_get_display_name (destination);
+		details = g_strdup_printf (_("Copying %s to %s"), source_name, destination_name);
+		copy_data->progress_callback (NULL,
+					      _("Copying files"),
+					      details,
+					      FALSE,
+					      (double) copy_data->n_current / (copy_data->n_files + 1),
+					      copy_data->progress_callback_data);
+
+		g_free (details);
+		g_free (destination_name);
+		g_free (source_name);
+	}
+
+	g_file_copy_async (source,
+			   destination,
+			   copy_data->flags,
+			   copy_data->io_priority,
+			   copy_data->cancellable,
+			   copy_data__copy_current_file_progress_cb,
+			   copy_data,
+			   copy_data__copy_current_file_ready_cb,
+			   copy_data);
 }
 
 
 static void
-g_directory_copy_for_each_file (GFile     *file,
-				GFileInfo *info,
-				gpointer   user_data)
+copy_data__copy_files_to_destination (CopyData *copy_data)
 {
-	DirectoryCopyData *dcd = user_data;
+	GList *scan;
 
-	dcd->to_copy = g_list_prepend (dcd->to_copy, child_data_new (file, info));
-	dcd->tot_files++;
-}
+	copy_data->n_files = g_list_length (copy_data->sources);
+	copy_data->n_current = 0;
 
 
-static DirOp
-g_directory_copy_start_dir (GFile      *directory,
-			    GFileInfo  *info,
-			    GError    **error,
-			    gpointer    user_data)
-{
-	DirectoryCopyData *dcd = user_data;
+	copy_data->destinations = NULL;
+	for (scan = copy_data->sources; scan; scan = scan->next) {
+		GFile *source = scan->data;
+		char  *source_name;
 
-	dcd->to_copy = g_list_prepend (dcd->to_copy, child_data_new (directory, info));
-	dcd->tot_files++;
+		source_name = g_file_get_basename (source);
+		copy_data->destinations = g_list_prepend (copy_data->destinations, g_file_get_child (copy_data->destination, source_name));
 
-	return DIR_OP_CONTINUE;
+		g_free (source_name);
+	}
+	copy_data->destinations = g_list_reverse (copy_data->destinations);
+
+	copy_data->current_source = copy_data->sources;
+	copy_data->current_destination = copy_data->destinations;
+	copy_data__copy_current_file (copy_data);
 }
 
 
 static void
-g_directory_copy_destination_info_ready_cb (GObject      *source_object,
-                                            GAsyncResult *result,
-                                            gpointer      user_data)
+copy_files__sources_info_ready_cb (GList    *files,
+			           GError   *error,
+			           gpointer  user_data)
 {
-	DirectoryCopyData *dcd = user_data;
-	GFileInfo         *info;
+	CopyData *copy_data = user_data;
+	GList    *scan;
 
-	info = g_file_query_info_finish (G_FILE (source_object), result, &dcd->error);
-	if (info == NULL) {
-		if (! g_error_matches (dcd->error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
-			g_directory_copy_done (dcd);
-			return;
-		}
+	if (error != NULL) {
+		copy_data->done_callback (error, copy_data->user_data);
+		copy_data_free (copy_data);
+		return;
 	}
 
-	g_clear_error (&dcd->error);
+	copy_data->sources = NULL;
+	copy_data->dirs = NULL;
+	for (scan = files; scan; scan = scan->next) {
+		GthFileData *file_data = scan->data;
 
-	if ((info != NULL) && (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)) {
-		dcd->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, "");
-		g_directory_copy_done (dcd);
-		return;
+		switch (g_file_info_get_file_type (file_data->info)) {
+		case G_FILE_TYPE_DIRECTORY:
+			copy_data->dirs = g_list_prepend (copy_data->dirs, g_object_ref (file_data->file));
+			break;
+		default:
+			copy_data->sources = g_list_prepend (copy_data->sources, g_object_ref (file_data->file));
+			break;
+		}
 	}
+	copy_data->sources = g_list_reverse (copy_data->sources);
+	copy_data->dirs = g_list_reverse (copy_data->dirs);
 
-	if (! g_file_make_directory (dcd->destination,
-			             dcd->cancellable,
-			             &dcd->error))
-	{
-		g_directory_copy_done (dcd);
-		return;
-	}
+	copy_data__copy_files_to_destination (copy_data);
+}
 
-	g_clear_error (&dcd->error);
 
-	g_directory_foreach_child (dcd->source,
-				   TRUE,
-				   TRUE,
-				   "standard::name,standard::type",
-				   dcd->cancellable,
-				   g_directory_copy_start_dir,
-				   g_directory_copy_for_each_file,
-				   g_directory_copy_list_ready,
-				   dcd);
+void
+_g_copy_files_async (GList            *sources, /* GFile list */
+		     GFile            *destination,
+		     gboolean          move,
+		     GFileCopyFlags    flags,
+		     int               io_priority,
+		     GCancellable     *cancellable,
+		     ProgressCallback  progress_callback,
+		     gpointer          progress_callback_data,
+		     CopyDoneCallback  done_callback,
+		     gpointer          user_data)
+{
+	CopyData *copy_data;
+
+	copy_data = g_new0 (CopyData, 1);
+	copy_data->destination = g_object_ref (destination);
+	copy_data->move = move;
+	copy_data->flags = flags;
+	copy_data->io_priority = io_priority;
+	copy_data->cancellable = g_object_ref (cancellable);
+	copy_data->progress_callback = progress_callback;
+	copy_data->progress_callback_data = progress_callback_data;
+	copy_data->done_callback = done_callback;
+	copy_data->user_data = user_data;
+
+	if (copy_data->progress_callback != NULL)
+		copy_data->progress_callback (NULL,
+					      _("Copying files"),
+					      _("Getting files information"),
+					      TRUE,
+					      0.0,
+					      copy_data->progress_callback_data);
+
+	g_query_info_async (sources,
+			    G_FILE_ATTRIBUTE_STANDARD_TYPE,
+			    cancellable,
+			    copy_files__sources_info_ready_cb,
+			    copy_data);
+}
+
+
+void
+_g_copy_file_async (GFile                 *source,
+		    GFile                 *destination,
+		    gboolean               move,
+		    GFileCopyFlags         flags,
+		    int                    io_priority,
+		    GCancellable          *cancellable,
+		    ProgressCallback       progress_callback,
+		    gpointer               progress_callback_data,
+		    CopyDoneCallback       callback,
+		    gpointer               user_data)
+{
+	GList *source_files;
+
+	source_files = g_list_append (NULL, (gpointer) source);
+	_g_copy_files_async (source_files,
+			     destination,
+			     move,
+			     flags,
+			     io_priority,
+			     cancellable,
+			     progress_callback,
+			     progress_callback_data,
+			     callback,
+			     user_data);
+
+	g_list_free (source_files);
 }
 
 
@@ -1509,8 +1357,6 @@ _g_move_file (GFile                 *source,
               gpointer               progress_callback_data,
               GError               **error)
 {
-	GList *sources;
-	GList *destinations;
 	GList *source_sidecars = NULL;
 	GList *destination_sidecars = NULL;
 	GList *scan1;
@@ -1532,12 +1378,10 @@ _g_move_file (GFile                 *source,
 
 	/* move the metadata sidecars if requested */
 
-	sources = g_list_prepend (NULL, source);
-	gth_hook_invoke ("add-sidecars", sources, &source_sidecars);
+	gth_hook_invoke ("add-sidecars", source, &source_sidecars);
 	source_sidecars = g_list_reverse (source_sidecars);
 
-	destinations = g_list_prepend (NULL, destination);
-	gth_hook_invoke ("add-sidecars", destinations, &destination_sidecars);
+	gth_hook_invoke ("add-sidecars", destination, &destination_sidecars);
 	destination_sidecars = g_list_reverse (destination_sidecars);
 
 	for (scan1 = source_sidecars, scan2 = destination_sidecars;
@@ -1551,49 +1395,12 @@ _g_move_file (GFile                 *source,
 	}
 
 	_g_object_list_unref (destination_sidecars);
-	g_list_free (destinations);
 	_g_object_list_unref (source_sidecars);
-	g_list_free (sources);
-
 
 	return TRUE;
 }
 
 
-void
-g_directory_copy_async (GFile                 *source,
-			GFile                 *destination,
-			GFileCopyFlags         flags,
-			int                    io_priority,
-			GCancellable          *cancellable,
-			CopyProgressCallback   progress_callback,
-			gpointer               progress_callback_data,
-			CopyDoneCallback       callback,
-			gpointer               user_data)
-{
-	DirectoryCopyData *dcd;
-
-	dcd = g_new0 (DirectoryCopyData, 1);
-	dcd->source = g_file_dup (source);
-	dcd->destination = g_file_dup (destination);
-	dcd->flags = flags;
-	dcd->io_priority = io_priority;
-	dcd->cancellable = g_object_ref (cancellable);
-	dcd->progress_callback = progress_callback;
-	dcd->progress_callback_data = progress_callback_data;
-	dcd->callback = callback;
-	dcd->user_data = user_data;
-
-	g_file_query_info_async (dcd->destination,
-				 "standard::name,standard::type",
-				 0,
-				 G_PRIORITY_DEFAULT,
-				 dcd->cancellable,
-				 g_directory_copy_destination_info_ready_cb,
-				 dcd);
-}
-
-
 gboolean
 _g_delete_files (GList     *file_list,
 		 gboolean   include_metadata,
@@ -1609,13 +1416,16 @@ _g_delete_files (GList     *file_list,
 	}
 
 	if (include_metadata) {
-		GList *sidecars = NULL;
+		GList *sidecars;
+		GList *scan;
 
-		gth_hook_invoke ("add-sidecars", file_list, &sidecars);
+		sidecars = NULL;
+		for (scan = file_list; scan; scan = scan->next)
+			gth_hook_invoke ("add-sidecars", scan->data, &sidecars);
 		sidecars = g_list_reverse (sidecars);
+
 		for (scan = sidecars; scan; scan = scan->next) {
 			GFile *file = scan->data;
-
 			g_file_delete (file, NULL, NULL);
 		}
 
@@ -2009,29 +1819,6 @@ _g_directory_create_unique (GFile       *parent,
 }
 
 
-GFileType
-_g_file_get_standard_type (GFile *file)
-{
-	GFileType  result;
-	GFileInfo *info;
-	GError    *error = NULL;
-
-	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
-	if (error == NULL) {
-		result = g_file_info_get_file_type (info);
-	}
-	else {
-		result = G_FILE_ATTRIBUTE_TYPE_INVALID;
-		g_error_free (error);
-	}
-
-	g_object_unref (info);
-
-	return result;
-}
-
-
-
 /* -- g_write_file -- */
 
 
diff --git a/gthumb/gio-utils.h b/gthumb/gio-utils.h
index c72788c..a466027 100644
--- a/gthumb/gio-utils.h
+++ b/gthumb/gio-utils.h
@@ -25,6 +25,7 @@
 
 #include <glib.h>
 #include <gio/gio.h>
+#include "typedefs.h"
 
 G_BEGIN_DECLS
 
@@ -49,13 +50,6 @@ typedef void (*ListReadyCallback)    (GList       *files,
 				      GList       *dirs,
 				      GError      *error,
 				      gpointer     user_data);
-typedef void (*CopyProgressCallback) (goffset      current_file,
-                                      goffset      total_files,
-                                      GFile       *source,
-                                      GFile       *destination,
-                                      goffset      current_num_bytes,
-                                      goffset      total_num_bytes,
-                                      gpointer     user_data);
 typedef void (*CopyDoneCallback)     (GError      *error,
 				      gpointer     user_data);
 typedef void (*BufferReadyCallback)  (void        *buffer,
@@ -98,38 +92,28 @@ void   g_query_info_async            (GList                 *files,        /* GF
 
 /* asynchronous copy functions */
 
-void   _g_dummy_file_op_async        (CopyDoneCallback       callback,
+void     _g_dummy_file_op_async      (CopyDoneCallback       callback,
 				      gpointer               user_data);
-void   g_copy_files_async            (GList                 *sources,
-				      GList                 *destinations,
-				      GFileCopyFlags         flags,
-				      int                    io_priority,
-				      GCancellable          *cancellable,
-				      CopyProgressCallback   progress_callback,
-				      gpointer               progress_callback_data,
-				      CopyDoneCallback       callback,
-				      gpointer               user_data);
-void   _g_copy_file_async            (GFile                 *source,
+void     _g_copy_files_async         (GList                 *sources,
 				      GFile                 *destination,
+				      gboolean               move,
 				      GFileCopyFlags         flags,
 				      int                    io_priority,
 				      GCancellable          *cancellable,
-				      CopyProgressCallback   progress_callback,
+				      ProgressCallback       progress_callback,
 				      gpointer               progress_callback_data,
 				      CopyDoneCallback       callback,
 				      gpointer               user_data);
-void   g_directory_copy_async        (GFile                 *source,
+void     _g_copy_file_async          (GFile                 *source,
 				      GFile                 *destination,
+				      gboolean               move,
 				      GFileCopyFlags         flags,
 				      int                    io_priority,
 				      GCancellable          *cancellable,
-				      CopyProgressCallback   progress_callback,
+				      ProgressCallback       progress_callback,
 				      gpointer               progress_callback_data,
 				      CopyDoneCallback       callback,
 				      gpointer               user_data);
-gboolean _g_delete_files             (GList                 *file_list,
-				      gboolean               include_metadata,
-				      GError               **error);
 gboolean _g_move_file                (GFile                 *source,
                                       GFile                 *destination,
                                       GFileCopyFlags         flags,
@@ -137,6 +121,12 @@ gboolean _g_move_file                (GFile                 *source,
                                       GFileProgressCallback  progress_callback,
                                       gpointer               progress_callback_data,
                                       GError               **error);
+gboolean _g_delete_files             (GList                 *file_list,
+				      gboolean               include_metadata,
+				      GError               **error);
+
+/* -- read/write/create file  -- */
+
 gboolean g_load_file_in_buffer       (GFile                 *file,
 				      void                 **buffer,
 				      gsize                 *size,
@@ -168,8 +158,6 @@ GFile * _g_directory_create_unique   (GFile                 *parent,
 				      const char            *display_name,
 				      const char            *suffix,
 				      GError               **error);
-GFileType
-	_g_file_get_standard_type    (GFile      *file);
 
 /* convenience macros */
 
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 1ded506..ff49f26 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -1522,6 +1522,28 @@ _g_file_get_display_name (GFile *file)
 }
 
 
+GFileType
+_g_file_get_standard_type (GFile *file)
+{
+	GFileType  result;
+	GFileInfo *info;
+	GError    *error = NULL;
+
+	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
+	if (error == NULL) {
+		result = g_file_info_get_file_type (info);
+	}
+	else {
+		result = G_FILE_ATTRIBUTE_TYPE_INVALID;
+		g_error_free (error);
+	}
+
+	g_object_unref (info);
+
+	return result;
+}
+
+
 GFile *
 _g_file_get_child (GFile *file,
 		   ...)
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index 08af24f..a817591 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -206,6 +206,7 @@ char *          _g_build_uri                     (const char *base,
 /* GIO utils */
 
 char *          _g_file_get_display_name         (GFile      *file);
+GFileType 	_g_file_get_standard_type        (GFile      *file);
 GFile *         _g_file_get_child                (GFile      *file,
 						  ...);
 GIcon *         _g_file_get_icon                 (GFile      *file);
diff --git a/gthumb/gth-file-source-vfs.c b/gthumb/gth-file-source-vfs.c
index 626cced..fb68701 100644
--- a/gthumb/gth-file-source-vfs.c
+++ b/gthumb/gth-file-source-vfs.c
@@ -239,177 +239,22 @@ gth_file_source_vfs_list (GthFileSource *file_source,
 
 
 typedef struct {
-	GthFileSourceVfs *file_source;
-	GthFileData      *destination;
-	GList            *file_list;
-	ProgressCallback  progress_callback;
-	ReadyCallback     ready_callback;
-	gpointer          user_data;
-	GList            *files;
-	GList            *dirs;
-	GList            *current_dir;
-	char             *message;
+	GthFileSource *file_source;
+	ReadyCallback  ready_callback;
+	gpointer       user_data;
 } CopyOpData;
 
 
 static void
-copy_op_data_free (CopyOpData *cod)
-{
-	g_object_unref (cod->file_source);
-	g_object_unref (cod->destination);
-	_g_object_list_unref (cod->file_list);
-	_g_object_list_unref (cod->files);
-	_g_object_list_unref (cod->dirs);
-	g_free (cod->message);
-	g_free (cod);
-}
-
-
-static void
-copy__copy_files_done (GError   *error,
-		       gpointer  user_data)
+copy_done_cb (GError   *error,
+	      gpointer  user_data)
 {
 	CopyOpData *cod = user_data;
 
 	cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
-	copy_op_data_free (cod);
-}
-
-
-static void
-copy__copy_files (CopyOpData *cod)
-{
-	GList *destinations;
-	GList *scan;
-
-	destinations = NULL;
-	for (scan = cod->files; scan; scan = scan->next) {
-		GFile *source = scan->data;
-		char  *source_basename;
-
-		source_basename = g_file_get_basename (source);
-		destinations = g_list_prepend (destinations, g_file_get_child (cod->destination->file, source_basename));
-
-		g_free (source_basename);
-	}
 
-	g_copy_files_async  (cod->files,
-			     destinations,
-			     G_FILE_COPY_NONE,
-			     G_PRIORITY_DEFAULT,
-			     gth_file_source_get_cancellable (GTH_FILE_SOURCE (cod->file_source)),
-			     NULL,
-			     NULL,
-			     copy__copy_files_done,
-			     cod);
-
-	_g_object_list_unref (destinations);
-}
-
-
-static void copy__copy_current_dir (CopyOpData *cod);
-
-
-static void
-copy__copy_current_dir_done (GError   *error,
-			     gpointer  user_data)
-{
-	CopyOpData *cod = user_data;
-
-	if (error != NULL) {
-		cod->ready_callback (G_OBJECT (cod->file_source), error, cod->user_data);
-		copy_op_data_free (cod);
-		return;
-	}
-
-	cod->current_dir = cod->current_dir->next;
-	copy__copy_current_dir (cod);
-}
-
-
-static void
-copy__copy_current_dir_progress (goffset   current_file,
-                                 goffset   total_files,
-                                 GFile    *source,
-                                 GFile    *destination,
-                                 goffset   current_num_bytes,
-                                 goffset   total_num_bytes,
-                                 gpointer  user_data)
-{
-	CopyOpData  *cod = user_data;
-	GthFileData *source_file_data;
-	char        *details;
-
-	if (cod->progress_callback == NULL)
-		return;
-
-	source_file_data = (GthFileData *) cod->current_dir->data;
-	details = g_strdup_printf (_("Copying files from '%s'"), g_file_info_get_display_name (source_file_data->info));
-	(cod->progress_callback) (G_OBJECT (cod->file_source), cod->message, details, FALSE, ((double) current_num_bytes) / total_num_bytes, cod->user_data);
-
-	g_free (details);
-}
-
-
-static void
-copy__copy_current_dir (CopyOpData *cod)
-{
-	GthFileData *source;
-	char        *source_basename;
-	GFile       *destination;
-
-	if (cod->current_dir == NULL) {
-		copy__copy_files (cod);
-		return;
-	}
-
-	source = (GthFileData *) cod->current_dir->data;
-	source_basename = g_file_get_basename (source->file);
-	destination = g_file_get_child (cod->destination->file, source_basename);
-
-	g_directory_copy_async (source->file,
-				destination,
-				G_FILE_COPY_NONE,
-				G_PRIORITY_DEFAULT,
-				gth_file_source_get_cancellable (GTH_FILE_SOURCE (cod->file_source)),
-				copy__copy_current_dir_progress,
-				cod,
-				copy__copy_current_dir_done,
-				cod);
-
-	g_object_unref (destination);
-	g_free (source_basename);
-}
-
-
-static void
-copy__file_list_info_ready_cb (GList    *files,
-			       GError   *error,
-			       gpointer  user_data)
-{
-	CopyOpData *cod = user_data;
-	GList      *scan;
-
-	for (scan = files; scan; scan = scan->next) {
-		GthFileData *file_data = scan->data;
-
-		switch (g_file_info_get_file_type (file_data->info)) {
-		case G_FILE_TYPE_DIRECTORY:
-			cod->dirs = g_list_prepend (cod->dirs, g_object_ref (file_data));
-			break;
-		case G_FILE_TYPE_REGULAR:
-		case G_FILE_TYPE_SYMBOLIC_LINK:
-			cod->files = g_list_prepend (cod->files, g_object_ref (file_data->file));
-			break;
-		default:
-			break;
-		}
-	}
-	cod->files = g_list_reverse (cod->files);
-	cod->dirs = g_list_reverse (cod->dirs);
-
-	cod->current_dir = cod->dirs;
-	copy__copy_current_dir (cod);
+	g_object_unref (cod->file_source);
+	g_free (cod);
 }
 
 
@@ -417,6 +262,7 @@ static void
 gth_file_source_vfs_copy (GthFileSource    *file_source,
 			  GthFileData      *destination,
 			  GList            *file_list, /* GFile * list */
+			  gboolean          move,
 			  ProgressCallback  progress_callback,
 		          ReadyCallback     ready_callback,
 			  gpointer          data)
@@ -425,21 +271,19 @@ gth_file_source_vfs_copy (GthFileSource    *file_source,
 
 	cod = g_new0 (CopyOpData, 1);
 	cod->file_source = g_object_ref (file_source);
-	cod->destination = g_object_ref (destination);
-	cod->file_list = _g_object_list_ref (file_list);
-	cod->progress_callback = progress_callback;
 	cod->ready_callback = ready_callback;
 	cod->user_data = data;
-	cod->message = g_strdup_printf (_("Copying files to '%s'"), g_file_info_get_display_name (destination->info));
 
-	if (cod->progress_callback != NULL)
-		(cod->progress_callback) (G_OBJECT (file_source), cod->message, _("Getting files information"), TRUE, 0.0, cod->user_data);
-
-	g_query_info_async (cod->file_list,
-			    G_FILE_ATTRIBUTE_STANDARD_TYPE,
-			    gth_file_source_get_cancellable (GTH_FILE_SOURCE (cod->file_source)),
-			    copy__file_list_info_ready_cb,
-			    cod);
+	_g_copy_files_async (file_list,
+			     destination->file,
+			     move,
+			     G_FILE_COPY_ALL_METADATA,
+			     G_PRIORITY_DEFAULT,
+			     gth_file_source_get_cancellable (file_source),
+			     progress_callback,
+			     data,
+			     copy_done_cb,
+			     cod);
 }
 
 
diff --git a/gthumb/gth-file-source.c b/gthumb/gth-file-source.c
index 92bcc59..f37ed3c 100644
--- a/gthumb/gth-file-source.c
+++ b/gthumb/gth-file-source.c
@@ -81,6 +81,7 @@ typedef struct {
 typedef struct {
 	GthFileData      *destination;
 	GList            *file_list;
+	gboolean          move;
 	ProgressCallback  progress_callback;
 	ReadyCallback     ready_callback;
 	gpointer          data;
@@ -190,6 +191,7 @@ static void
 gth_file_source_queue_copy (GthFileSource    *file_source,
 			    GthFileData      *destination,
 			    GList            *file_list,
+			    gboolean          move,
 			    ProgressCallback  progress_callback,
 			    ReadyCallback     ready_callback,
 			    gpointer          data)
@@ -201,6 +203,7 @@ gth_file_source_queue_copy (GthFileSource    *file_source,
 	async_op->op = FILE_SOURCE_OP_COPY;
 	async_op->data.copy.destination = gth_file_data_dup (destination);
 	async_op->data.copy.file_list = _g_file_list_dup (file_list);
+	async_op->data.copy.move = move;
 	async_op->data.copy.progress_callback = progress_callback;
 	async_op->data.copy.ready_callback = ready_callback;
 	async_op->data.copy.data = data;
@@ -248,6 +251,7 @@ gth_file_source_exec_next_in_queue (GthFileSource *file_source)
 		gth_file_source_copy (file_source,
 				      async_op->data.copy.destination,
 				      async_op->data.copy.file_list,
+				      async_op->data.copy.move,
 				      async_op->data.copy.progress_callback,
 				      async_op->data.copy.ready_callback,
 				      async_op->data.copy.data);
@@ -692,15 +696,16 @@ void
 gth_file_source_copy (GthFileSource    *file_source,
 		      GthFileData      *destination,
 		      GList            *file_list, /* GFile * list */
+		      gboolean          move,
 		      ProgressCallback  progress_callback,
 		      ReadyCallback     ready_callback,
 		      gpointer          data)
 {
 	if (gth_file_source_is_active (file_source)) {
-		gth_file_source_queue_copy (file_source, destination, file_list, progress_callback, ready_callback, data);
+		gth_file_source_queue_copy (file_source, destination, file_list, move, progress_callback, ready_callback, data);
 		return;
 	}
-	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->copy (file_source, destination, file_list, progress_callback, ready_callback, data);
+	GTH_FILE_SOURCE_GET_CLASS (G_OBJECT (file_source))->copy (file_source, destination, file_list, move, progress_callback, ready_callback, data);
 }
 
 
diff --git a/gthumb/gth-file-source.h b/gthumb/gth-file-source.h
index 55cf866..17014a2 100644
--- a/gthumb/gth-file-source.h
+++ b/gthumb/gth-file-source.h
@@ -89,6 +89,7 @@ struct _GthFileSourceClass
 	void         (*copy)                  (GthFileSource    *file_source,
 					       GthFileData      *destination,
 					       GList            *file_list, /* GFile * list */
+					       gboolean          move,
 					       ProgressCallback  progress_callback,
 					       ReadyCallback     callback,
 					       gpointer          data);
@@ -136,6 +137,7 @@ void           gth_file_source_rename                (GthFileSource    *file_sou
 void           gth_file_source_copy                  (GthFileSource    *file_source,
 						      GthFileData      *destination,
 						      GList            *file_list, /* GFile list */
+						      gboolean          move,
 						      ProgressCallback  progress_callback,
 						      ReadyCallback     ready_callback,
 						      gpointer          data);
diff --git a/gthumb/gth-main-default-hooks.c b/gthumb/gth-main-default-hooks.c
index b5d45aa..895da30 100644
--- a/gthumb/gth-main-default-hooks.c
+++ b/gthumb/gth-main-default-hooks.c
@@ -134,12 +134,12 @@ gth_main_register_default_hooks (void)
 	gth_hook_register ("save-pixbuf", 1);
 
 	/**
-	 * Called when copying files in g_copy_files_async with the
+	 * Called when copying files in _g_copy_files_async with the
 	 * G_FILE_COPY_ALL_METADATA flag activated and when deleting file
 	 * with _g_delete_files.  Used to add sidecar files that contain
 	 * file metadata.
 	 *
-	 * @sources (GList *): the original file list, a GFile * list.
+	 * @file (GFile *): the original file.
 	 * @sidecar_sources (GList **): the sidecars list.
 	 */
 	gth_hook_register ("add-sidecars", 2);



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