[Xfce4-commits] r29892 - in thunar/branches/migration-to-gio: . thunar

Jannis Pohlmann jannis at xfce.org
Thu Apr 23 20:57:06 CEST 2009


Author: jannis
Date: 2009-04-23 18:57:05 +0000 (Thu, 23 Apr 2009)
New Revision: 29892

Modified:
   thunar/branches/migration-to-gio/ChangeLog
   thunar/branches/migration-to-gio/thunar/Makefile.am
   thunar/branches/migration-to-gio/thunar/thunar-application.c
   thunar/branches/migration-to-gio/thunar/thunar-dialogs.c
   thunar/branches/migration-to-gio/thunar/thunar-dnd.c
   thunar/branches/migration-to-gio/thunar/thunar-io-jobs.c
   thunar/branches/migration-to-gio/thunar/thunar-io-jobs.h
   thunar/branches/migration-to-gio/thunar/thunar-launcher.c
   thunar/branches/migration-to-gio/thunar/thunar-permissions-chooser.c
   thunar/branches/migration-to-gio/thunar/thunar-standard-view.c
   thunar/branches/migration-to-gio/thunar/thunar-transfer-job.c
   thunar/branches/migration-to-gio/thunar/thunar-transfer-job.h
Log:
	* thunar/Makefile.am, thunar/thunar-io-jobs-util.{c,h}: Add new files
	  for I/O job utility functions. Right now there's only one new
	  function called thunar_io_jobs_util_next_duplicate_file() which
	  generates alternative "copy of X", "another copy of X",
	  "third copy of X" and "nth copy of X" #GFiles for an input #GFile.
	  It also works for symbolic links.
	* thunar/thunar-application.{c,h}, thunar/thunar-dnd.c,
	  thunar/thunar-io-jobs.{c,h}, thunar/thunar-launcher.c,
	  thunar-standard-view.c: Add new
	  job thunar_io_jobs_link_files() and use it in
	  thunar_application_link_into(). Disable
	  thunar_application_restore_files() for now so that we can replace
	  thunar_application_collect_and_launch() and
	  thunar_application_launch() with the implementations based on GIO.
	  Enable creating links in thunar-dnd.c again. Update ThunarLauncher
	  and ThunarStandardView to reflect the API changes in
	  ThunarApplication.
	* thunar/thunar-dialogs.c: In thunar_dialogs_show_job_ask_replace(),
	  use different labels for target symlinks than for normal files to
	  make clear that we're only replacing the symlinks, not the files
	  they point to.
	* thunar/thunar-permissions-chooser.c: Make sure the array index
	  is never out of bounds when iterating over the combos.
	* thunar/thunar-transfer-job.{c,h}: Improve the copy/move algorithm so
	  that it resembles the old behaviour, creates "copy of X" files when
	  copying/linking files into the same directory, handles directory
	  merges properly and is more readable.

Modified: thunar/branches/migration-to-gio/ChangeLog
===================================================================
--- thunar/branches/migration-to-gio/ChangeLog	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/ChangeLog	2009-04-23 18:57:05 UTC (rev 29892)
@@ -1,5 +1,35 @@
 2009-04-23	Jannis Pohlmann <jannis at xfce.org>
 
+	* thunar/Makefile.am, thunar/thunar-io-jobs-util.{c,h}: Add new files
+	  for I/O job utility functions. Right now there's only one new
+	  function called thunar_io_jobs_util_next_duplicate_file() which
+	  generates alternative "copy of X", "another copy of X", 
+	  "third copy of X" and "nth copy of X" #GFiles for an input #GFile.
+	  It also works for symbolic links.
+	* thunar/thunar-application.{c,h}, thunar/thunar-dnd.c, 
+	  thunar/thunar-io-jobs.{c,h}, thunar/thunar-launcher.c,
+	  thunar-standard-view.c: Add new
+	  job thunar_io_jobs_link_files() and use it in
+	  thunar_application_link_into(). Disable
+	  thunar_application_restore_files() for now so that we can replace
+	  thunar_application_collect_and_launch() and
+	  thunar_application_launch() with the implementations based on GIO.
+	  Enable creating links in thunar-dnd.c again. Update ThunarLauncher
+	  and ThunarStandardView to reflect the API changes in
+	  ThunarApplication.
+	* thunar/thunar-dialogs.c: In thunar_dialogs_show_job_ask_replace(), 
+	  use different labels for target symlinks than for normal files to 
+	  make clear that we're only replacing the symlinks, not the files 
+	  they point to.
+	* thunar/thunar-permissions-chooser.c: Make sure the array index
+	  is never out of bounds when iterating over the combos.
+	* thunar/thunar-transfer-job.{c,h}: Improve the copy/move algorithm so
+	  that it resembles the old behaviour, creates "copy of X" files when
+	  copying/linking files into the same directory, handles directory
+	  merges properly and is more readable.
+
+2009-04-23	Jannis Pohlmann <jannis at xfce.org>
+
 	* thunar/Makefile.am, thunar/thunar-transfer-job.{c,h}: Implement
 	  ThunarTransferJob as an equivalent to ThunarVfsTransferJob. The code
 	  is very similar except that the error handling is a bit different

Modified: thunar/branches/migration-to-gio/thunar/Makefile.am
===================================================================
--- thunar/branches/migration-to-gio/thunar/Makefile.am	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/Makefile.am	2009-04-23 18:57:05 UTC (rev 29892)
@@ -98,6 +98,8 @@
 	thunar-icon-view.h						\
 	thunar-io-jobs.c						\
 	thunar-io-jobs.h						\
+	thunar-io-jobs-util.c						\
+	thunar-io-jobs-util.h						\
 	thunar-io-scan-directory.c					\
 	thunar-io-scan-directory.h					\
 	thunar-job.c							\

Modified: thunar/branches/migration-to-gio/thunar/thunar-application.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-application.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-application.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -49,14 +49,9 @@
 
 
 
-/* Prototype for the Thunar-VFS job launchers */
-typedef ThunarVfsJob *(*Launcher) (GList   *source_path_list,
-                                   GList   *target_path_list,
-                                   GError **error);
-
 /* Prototype for the Thunar job launchers */
-typedef ThunarJob *(*JobLauncher) (GList  *source_path_list,
-                                   GList  *target_path_list);
+typedef ThunarJob *(*Launcher) (GList  *source_path_list,
+                                GList  *target_path_list);
 
 
 
@@ -85,8 +80,8 @@
                                                              const gchar            *icon_name,
                                                              const gchar            *title,
                                                              Launcher                launcher,
-                                                             GList                  *source_path_list,
-                                                             ThunarVfsPath          *target_path,
+                                                             GList                  *source_file_list,
+                                                             GFile                  *target_file,
                                                              GClosure               *new_files_closure);
 static void       thunar_application_launch                 (ThunarApplication      *application,
                                                              gpointer                parent,
@@ -96,22 +91,6 @@
                                                              GList                  *source_path_list,
                                                              GList                  *target_path_list,
                                                              GClosure               *new_files_closure);
-static void       thunar_application_collect_and_launch_job (ThunarApplication      *application,
-                                                             gpointer                parent,
-                                                             const gchar            *icon_name,
-                                                             const gchar            *title,
-                                                             JobLauncher             launcher,
-                                                             GList                  *source_file_list,
-                                                             GFile                  *target_file,
-                                                             GClosure               *new_files_closure);
-static void       thunar_application_launch_job             (ThunarApplication      *application,
-                                                             gpointer                parent,
-                                                             const gchar            *icon_name,
-                                                             const gchar            *title,
-                                                             JobLauncher             launcher,
-                                                             GList                  *source_path_list,
-                                                             GList                  *target_path_list,
-                                                             GClosure               *new_files_closure);
 static GtkWidget *thunar_application_open_window_with_role  (ThunarApplication      *application,
                                                              const gchar            *role,
                                                              ThunarFile             *directory,
@@ -361,172 +340,10 @@
                                        const gchar       *icon_name,
                                        const gchar       *title,
                                        Launcher           launcher,
-                                       GList             *source_path_list,
-                                       ThunarVfsPath     *target_path,
+                                       GList             *source_file_list,
+                                       GFile             *target_file,
                                        GClosure          *new_files_closure)
 {
-  ThunarVfsInfo *info;
-  ThunarVfsPath *path;
-  GError        *err = NULL;
-  GList         *target_path_list = NULL;
-  GList         *lp;
-  gchar         *original_path;
-  gchar         *original_name;
-
-  /* check if we have anything to operate on */
-  if (G_UNLIKELY (source_path_list == NULL))
-    return;
-
-  /* generate the target path list */
-  for (lp = g_list_last (source_path_list); err == NULL && lp != NULL; lp = lp->prev)
-    {
-      /* reset the path */
-      path = NULL;
-
-      /* verify that we're not trying to collect a root node */
-      if (G_UNLIKELY (thunar_vfs_path_is_root (lp->data)))
-        {
-          /* tell the user that we cannot perform the requested operation */
-          g_set_error (&err, G_FILE_ERROR, G_FILE_ERROR_INVAL, "%s", g_strerror (EINVAL));
-        }
-      else
-        {
-          /* check if we're copying from a location in the trash */
-          if (G_UNLIKELY (thunar_vfs_path_get_scheme (lp->data) == THUNAR_VFS_PATH_SCHEME_TRASH))
-            {
-              /* determine the info for the trashed resource */
-              info = thunar_vfs_info_new_for_path (lp->data, NULL);
-              if (G_LIKELY (info != NULL))
-                {
-                  /* try to use the basename of the original path */
-                  original_path = thunar_vfs_info_get_metadata (info, THUNAR_VFS_INFO_METADATA_TRASH_ORIGINAL_PATH, NULL);
-                  if (G_LIKELY (original_path != NULL))
-                    {
-                      /* g_path_get_basename() may return '.' or '/' */
-                      original_name = g_path_get_basename (original_path);
-                      if (strcmp (original_name, ".") != 0 && strchr (original_name, G_DIR_SEPARATOR) == NULL)
-                        path = thunar_vfs_path_relative (target_path, original_name);
-                      g_free (original_name);
-                      g_free (original_path);
-                    }
-
-                  /* release the info */
-                  thunar_vfs_info_unref (info);
-                }
-            }
-
-          /* fallback to the path's basename */
-          if (G_LIKELY (path == NULL))
-            path = thunar_vfs_path_relative (target_path, thunar_vfs_path_get_name (lp->data));
-
-          /* add to the target path list */
-          target_path_list = g_list_prepend (target_path_list, path);
-        }
-    }
-
-  /* check if we failed */
-  if (G_UNLIKELY (err != NULL))
-    {
-      /* display an error message to the user */
-      thunar_dialogs_show_error (parent, err, _("Failed to launch operation"));
-
-      /* release the error */
-      g_error_free (err);
-    }
-  else
-    {
-      /* launch the operation */
-      thunar_application_launch (application, parent, icon_name, title, launcher,
-                                 source_path_list, target_path_list, new_files_closure);
-    }
-
-  /* release the target path list */
-  thunar_vfs_path_list_free (target_path_list);
-}
-
-
-
-static void
-thunar_application_launch (ThunarApplication *application,
-                           gpointer           parent,
-                           const gchar       *icon_name,
-                           const gchar       *title,
-                           Launcher           launcher,
-                           GList             *source_path_list,
-                           GList             *target_path_list,
-                           GClosure          *new_files_closure)
-{
-  ThunarVfsJob *job;
-  GtkWindow    *window;
-  GtkWidget    *dialog;
-  GdkScreen    *screen;
-  GError       *error = NULL;
-
-  _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
-
-  /* parse the parent pointer */
-  screen = thunar_util_parse_parent (parent, &window);
-
-  /* try to allocate a new job for the operation */
-  job = (*launcher) (source_path_list, target_path_list, &error);
-  if (G_UNLIKELY (job == NULL))
-    {
-      /* display an error message to the user */
-      thunar_dialogs_show_error (parent, error, _("Failed to launch operation"));
-
-      /* release the error */
-      g_error_free (error);
-    }
-  else
-    {
-      /* connect the "new-files" closure (if any) */
-      if (G_LIKELY (new_files_closure != NULL))
-        g_signal_connect_closure (G_OBJECT (job), "new-files", new_files_closure, FALSE);
-
-      /* allocate a progress dialog for the job */
-      dialog = g_object_new (THUNAR_TYPE_PROGRESS_DIALOG,
-                             "icon-name", icon_name,
-                             "title", title,
-                             "job", job,
-                             "screen", screen,
-                             NULL);
-
-      /* connect to the parent (if any) */
-      if (G_LIKELY (window != NULL))
-        gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
-
-      /* be sure to destroy the dialog when the job is done */
-      g_signal_connect_after (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), dialog);
-
-      /* hook up the dialog window */
-      thunar_application_take_window (application, GTK_WINDOW (dialog));
-
-      /* Set up a timer to show the dialog, to make sure we don't
-       * just popup and destroy a dialog for a very short job.
-       */
-      if (G_LIKELY (application->show_dialogs_timer_id == 0))
-        {
-          application->show_dialogs_timer_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 750, thunar_application_show_dialogs,
-                                                                   application, thunar_application_show_dialogs_destroy);
-        }
-
-      /* drop our reference on the job */
-      g_object_unref (G_OBJECT (job));
-    }
-}
-
-
-
-static void
-thunar_application_collect_and_launch_job (ThunarApplication *application,
-                                           gpointer           parent,
-                                           const gchar       *icon_name,
-                                           const gchar       *title,
-                                           JobLauncher        launcher,
-                                           GList             *source_file_list,
-                                           GFile             *target_file,
-                                           GClosure          *new_files_closure)
-{
   GFile  *file;
   GError *err = NULL;
   GList  *target_file_list = NULL;
@@ -570,8 +387,8 @@
   else
     {
       /* launch the operation */
-      thunar_application_launch_job (application, parent, icon_name, title, launcher,
-                                     source_file_list, target_file_list, new_files_closure);
+      thunar_application_launch (application, parent, icon_name, title, launcher,
+                                 source_file_list, target_file_list, new_files_closure);
     }
 
   /* release the target path list */
@@ -581,14 +398,14 @@
 
 
 static void
-thunar_application_launch_job (ThunarApplication *application,
-                               gpointer           parent,
-                               const gchar       *icon_name,
-                               const gchar       *title,
-                               JobLauncher        launcher,
-                               GList             *source_file_list,
-                               GList             *target_file_list,
-                               GClosure          *new_files_closure)
+thunar_application_launch (ThunarApplication *application,
+                           gpointer           parent,
+                           const gchar       *icon_name,
+                           const gchar       *title,
+                           Launcher           launcher,
+                           GList             *source_file_list,
+                           GList             *target_file_list,
+                           GClosure          *new_files_closure)
 {
   ThunarJob *job;
   GtkWindow *window;
@@ -1312,9 +1129,9 @@
   _thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
 
   /* launch the operation */
-  thunar_application_launch_job (application, parent, "stock_folder-copy",
-                                 _("Copying files..."), thunar_io_jobs_copy_files,
-                                 source_file_list, target_file_list, new_files_closure);
+  thunar_application_launch (application, parent, "stock_folder-copy",
+                             _("Copying files..."), thunar_io_jobs_copy_files,
+                             source_file_list, target_file_list, new_files_closure);
 }
 
 
@@ -1345,9 +1162,9 @@
   _thunar_return_if_fail (G_IS_FILE (target_file));
 
   /* collect the target files and launch the job */
-  thunar_application_collect_and_launch_job (application, parent, "stock_folder-copy",
-                                             _("Copying files..."), thunar_io_jobs_copy_files,
-                                             source_file_list, target_file, new_files_closure);
+  thunar_application_collect_and_launch (application, parent, "stock_folder-copy",
+                                         _("Copying files..."), thunar_io_jobs_copy_files,
+                                         source_file_list, target_file, new_files_closure);
 }
 
 
@@ -1356,33 +1173,33 @@
  * thunar_application_link_into:
  * @application       : a #ThunarApplication.
  * @parent            : a #GdkScreen, a #GtkWidget or %NULL.
- * @source_path_list  : the list of #ThunarVfsPath<!---->s that should be symlinked.
- * @target_path       : the target directory.
+ * @source_file_list  : the list of #GFile<!---->s that should be symlinked.
+ * @target_file       : the target directory.
  * @new_files_closure : a #GClosure to connect to the job's "new-files" signal,
  *                      which will be emitted when the job finishes with the
- *                      list of #ThunarVfsPath<!---->s created by the job, or
+ *                      list of #GFile<!---->s created by the job, or
  *                      %NULL if you're not interested in the signal.
  *
- * Symlinks all files referenced by the @source_path_list to the directory
- * referenced by @target_path. This method takes care of all user
+ * Symlinks all files referenced by the @source_file_list to the directory
+ * referenced by @target_file. This method takes care of all user
  * interaction.
  **/
 void
 thunar_application_link_into (ThunarApplication *application,
                               gpointer           parent,
-                              GList             *source_path_list,
-                              ThunarVfsPath     *target_path,
+                              GList             *source_file_list,
+                              GFile     *target_file,
                               GClosure          *new_files_closure)
 {
   _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
   _thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
-  _thunar_return_if_fail (target_path != NULL);
+  _thunar_return_if_fail (G_IS_FILE (target_file));
 
-  /* collect the target paths and launch the job */
+  /* collect the target files and launch the job */
   thunar_application_collect_and_launch (application, parent, "stock_link",
                                          _("Creating symbolic links..."),
-                                         thunar_vfs_link_files, source_path_list,
-                                         target_path, new_files_closure);
+                                         thunar_io_jobs_link_files, source_file_list,
+                                         target_file, new_files_closure);
 }
 
 
@@ -1430,10 +1247,10 @@
     }
 
   /* launch the operation */
-  thunar_application_collect_and_launch_job (application, parent, icon, text,
-                                             thunar_io_jobs_move_files, 
-                                             source_file_list, target_file, 
-                                             new_files_closure);
+  thunar_application_collect_and_launch (application, parent, icon, text,
+                                         thunar_io_jobs_move_files, 
+                                         source_file_list, target_file, 
+                                         new_files_closure);
 }
 
 
@@ -1536,9 +1353,9 @@
       if (G_LIKELY (response == GTK_RESPONSE_YES))
         {
           /* launch the "Delete" operation */
-          thunar_application_launch_job (application, parent, "stock_delete",
-                                         _("Deleting files..."), unlink_stub,
-                                         path_list, path_list, NULL);
+          thunar_application_launch (application, parent, "stock_delete",
+                                     _("Deleting files..."), unlink_stub,
+                                     path_list, path_list, NULL);
         }
     }
   else
@@ -1569,28 +1386,28 @@
  * thunar_application_creat:
  * @application       : a #ThunarApplication.
  * @parent            : a #GdkScreen, a #GtkWidget or %NULL.
- * @path_list         : the list of files to create.
+ * @file_list         : the list of files to create.
  * @new_files_closure : a #GClosure to connect to the job's "new-files" signal,
  *                      which will be emitted when the job finishes with the
- *                      list of #ThunarVfsPath<!---->s created by the job, or
+ *                      list of #GFile<!---->s created by the job, or
  *                      %NULL if you're not interested in the signal.
  *
- * Creates empty files for all #ThunarVfsPath<!---->s listed in @path_list. This
+ * Creates empty files for all #GFile<!---->s listed in @file_list. This
  * method takes care of all user interaction.
  **/
 void
 thunar_application_creat (ThunarApplication *application,
                           gpointer           parent,
-                          GList             *path_list,
+                          GList             *file_list,
                           GClosure          *new_files_closure)
 {
   _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
   _thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
   
   /* launch the operation */
-  thunar_application_launch_job (application, parent, "stock_new",
-                                 _("Creating files..."), creat_stub,
-                                 path_list, path_list, new_files_closure);
+  thunar_application_launch (application, parent, "stock_new",
+                             _("Creating files..."), creat_stub,
+                             file_list, file_list, new_files_closure);
 }
 
 
@@ -1608,28 +1425,28 @@
  * thunar_application_mkdir:
  * @application       : a #ThunarApplication.
  * @parent            : a #GdkScreen, a #GtkWidget or %NULL.
- * @path_list         : the list of directories to create.
+ * @file_list         : the list of directories to create.
  * @new_files_closure : a #GClosure to connect to the job's "new-files" signal,
  *                      which will be emitted when the job finishes with the
- *                      list of #ThunarVfsPath<!---->s created by the job, or
+ *                      list of #GFile<!---->s created by the job, or
  *                      %NULL if you're not interested in the signal.
  *
- * Creates all directories referenced by the @path_list. This method takes care of all user
+ * Creates all directories referenced by the @file_list. This method takes care of all user
  * interaction.
  **/
 void
 thunar_application_mkdir (ThunarApplication *application,
                           gpointer           parent,
-                          GList             *path_list,
+                          GList             *file_list,
                           GClosure          *new_files_closure)
 {
   _thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
   _thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
 
   /* launch the operation */
-  thunar_application_launch_job (application, parent, "stock_folder",
-                                 _("Creating directories..."), mkdir_stub,
-                                 path_list, path_list, new_files_closure);
+  thunar_application_launch (application, parent, "stock_folder",
+                             _("Creating directories..."), mkdir_stub,
+                             file_list, file_list, new_files_closure);
 }
 
 
@@ -1651,7 +1468,7 @@
   GtkWidget *dialog;
   GtkWindow *window;
   GdkScreen *screen;
-  GList      path_list;
+  GList      file_list;
   gint       response;
 
   _thunar_return_if_fail (THUNAR_IS_APPLICATION (application));
@@ -1686,17 +1503,17 @@
       /* fake a path list with only the trash root (the root
        * folder itself will never be unlinked, so this is safe)
        */
-      path_list.data = g_file_new_for_trash ();
-      path_list.next = NULL;
-      path_list.prev = NULL;
+      file_list.data = g_file_new_for_trash ();
+      file_list.next = NULL;
+      file_list.prev = NULL;
 
       /* launch the operation */
-      thunar_application_launch_job (application, parent, "gnome-fs-trash-empty",
-                                     _("Emptying the Trash..."),
-                                     unlink_stub, &path_list, NULL, NULL);
+      thunar_application_launch (application, parent, "gnome-fs-trash-empty",
+                                 _("Emptying the Trash..."),
+                                 unlink_stub, &file_list, NULL, NULL);
 
       /* cleanup */
-      g_object_unref (path_list.data);
+      g_object_unref (file_list.data);
     }
 }
 
@@ -1721,6 +1538,7 @@
                                   GList             *trash_file_list,
                                   GClosure          *new_files_closure)
 {
+#if 0
   ThunarVfsPath *target_path;
   const gchar   *original_path;
   GtkWidget     *dialog;
@@ -1833,6 +1651,7 @@
   /* cleanup */
   thunar_vfs_path_list_free (target_path_list);
   thunar_vfs_path_list_free (source_path_list);
+#endif
 }
 
 

Modified: thunar/branches/migration-to-gio/thunar/thunar-dialogs.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-dialogs.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-dialogs.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -1,6 +1,7 @@
 /* $Id$ */
 /*-
  * Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -602,7 +603,16 @@
   gtk_table_attach (GTK_TABLE (table), image, 0, 1, 0, 1, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
   gtk_widget_show (image);
 
-  text = g_strdup_printf (_("This folder already contains a file \"%s\"."), thunar_file_get_display_name (dst_file));
+  if (thunar_file_is_symlink (dst_file))
+    {
+      text = g_strdup_printf (_("This folder already contains a symbolic link \"%s\"."), 
+                              thunar_file_get_display_name (dst_file));
+    }
+  else
+    {
+      text = g_strdup_printf (_("This folder already contains a file \"%s\"."), 
+                              thunar_file_get_display_name (dst_file));
+    }
   label = gtk_label_new (text);
   gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
   gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big ());
@@ -610,7 +620,11 @@
   gtk_widget_show (label);
   g_free (text);
 
-  text = g_strdup_printf (Q_("ReplaceDialogPart1|Do you want to replace the existing file"));
+  if (thunar_file_is_symlink (dst_file))
+    text = g_strdup_printf (Q_("ReplaceDialogPart1|Do you want to replace the link"));
+  else
+    text = g_strdup_printf (Q_("ReplaceDialogPart1|Do you want to replace the existing file"));
+
   label = gtk_label_new (text);
   gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f);
   gtk_table_attach (GTK_TABLE (table), label, 1, 3, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);

Modified: thunar/branches/migration-to-gio/thunar/thunar-dnd.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-dnd.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-dnd.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -189,15 +189,15 @@
 /**
  * thunar_dnd_perform:
  * @widget            : the #GtkWidget on which the drop was done.
- * @file              : the #ThunarFile on which the @path_list was dropped.
- * @path_list         : the list of #GFile<!---->s that was dropped.
+ * @file              : the #ThunarFile on which the @file_list was dropped.
+ * @file_list         : the list of #GFile<!---->s that was dropped.
  * @action            : the #GdkDragAction that was performed.
  * @new_files_closure : a #GClosure to connect to the job's "new-files" signal,
  *                      which will be emitted when the job finishes with the
  *                      list of #GFile<!---->s created by the job, or
  *                      %NULL if you're not interested in the signal.
  *
- * Performs the drop of @path_list on @file in @widget, as given in
+ * Performs the drop of @file_list on @file in @widget, as given in
  * @action and returns %TRUE if the drop was started successfully
  * (or even completed successfully), else %FALSE.
  *
@@ -207,7 +207,7 @@
 gboolean
 thunar_dnd_perform (GtkWidget    *widget,
                     ThunarFile   *file,
-                    GList        *path_list,
+                    GList        *file_list,
                     GdkDragAction action,
                     GClosure     *new_files_closure)
 {
@@ -229,17 +229,15 @@
       switch (action)
         {
         case GDK_ACTION_COPY:
-          thunar_application_copy_into (application, widget, path_list, thunar_file_get_file (file), new_files_closure);
+          thunar_application_copy_into (application, widget, file_list, thunar_file_get_file (file), new_files_closure);
           break;
 
         case GDK_ACTION_MOVE:
-          thunar_application_move_into (application, widget, path_list, thunar_file_get_file (file), new_files_closure);
+          thunar_application_move_into (application, widget, file_list, thunar_file_get_file (file), new_files_closure);
           break;
 
         case GDK_ACTION_LINK:
-          /* TODO Enable this again:
-          thunar_application_link_into (application, widget, path_list, thunar_file_get_path (file), new_files_closure);
-          */
+          thunar_application_link_into (application, widget, file_list, thunar_file_get_file (file), new_files_closure);
           break;
 
         default:
@@ -248,7 +246,7 @@
     }
   else if (thunar_file_is_executable (file))
     {
-      succeed = thunar_file_execute (file, gtk_widget_get_screen (widget), path_list, &error);
+      succeed = thunar_file_execute (file, gtk_widget_get_screen (widget), file_list, &error);
       if (G_UNLIKELY (!succeed))
         {
           /* display an error to the user */

Modified: thunar/branches/migration-to-gio/thunar/thunar-io-jobs.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-io-jobs.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-io-jobs.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -499,3 +499,121 @@
                                                      target_file_list,
                                                      THUNAR_TRANSFER_JOB_COPY));
 }
+
+
+
+static gboolean
+_thunar_io_jobs_link (ThunarJob   *job,
+                      GValueArray *param_values,
+                      GError     **error)
+{
+  ThunarJobResponse response;
+  GError           *err = NULL;
+  GList            *new_files_list = NULL;
+  GList            *source_file_list;
+  GList            *sp;
+  GList            *target_file_list;
+  GList            *tp;
+  gchar            *basename;
+  gchar            *display_name;
+  gchar            *source_path;
+
+  _thunar_return_val_if_fail (THUNAR_IS_JOB (job), FALSE);
+  _thunar_return_val_if_fail (param_values != NULL, FALSE);
+  _thunar_return_val_if_fail (param_values->n_values == 2, FALSE);
+  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  source_file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 0));
+  target_file_list = g_value_get_boxed (g_value_array_get_nth (param_values, 1));
+
+  /* we know the total list of paths to process */
+  thunar_job_set_total_files (job, source_file_list);
+
+  /* process all files */
+  for (sp = source_file_list, tp = target_file_list;
+       err == NULL && sp != NULL && tp != NULL;
+       sp = sp->next, tp = tp->next)
+    {
+      _thunar_assert (G_IS_FILE (sp->data));
+      _thunar_assert (G_IS_FILE (tp->data));
+
+      /* update progress information */
+      thunar_job_processing_file (job, sp);
+
+again:
+      source_path = g_file_get_path (sp->data);
+
+      if (G_LIKELY (source_path != NULL))
+        {
+          /* try to create the symlink */
+          g_file_make_symbolic_link (tp->data, source_path, 
+                                     thunar_job_get_cancellable (job),
+                                     &err);
+
+          g_free (source_path);
+
+          if (err == NULL)
+            new_files_list = g_file_list_prepend (new_files_list, sp->data);
+          else
+            {
+              /* check if we have an error from which we can recover */
+              if (err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
+                {
+                  /* ask the user whether he wants to overwrite the existing file */
+                  response = thunar_job_ask_overwrite (job, "%s", err->message);
+
+                  /* release the error */
+                  g_clear_error (&err);
+
+                  /* try to delete the file */
+                  if (G_LIKELY (response == THUNAR_JOB_RESPONSE_YES))
+                    {
+                      /* try to remove the target file (fail if not possible) */
+                      if (g_file_delete (tp->data, thunar_job_get_cancellable (job), &err))
+                        goto again;
+                    }
+                }
+            }
+        }
+      else
+        {
+          basename = g_file_get_basename (sp->data);
+          display_name = g_filename_display_name (basename);
+          g_set_error (&err, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                       _("Could not create symbolic link to \"%s\" "
+                         "because it is not a local file"), display_name);
+          g_free (display_name);
+          g_free (basename);
+        }
+    }
+
+  if (err != NULL)
+    {
+      g_file_list_free (new_files_list);
+      g_propagate_error (error, err);
+      return FALSE;
+    }
+  else
+    {
+      /* TODO 
+      thunar_job_new_files (job, new_files_list);
+      */
+      g_file_list_free (new_files_list);
+      return TRUE;
+    }
+}
+
+
+
+ThunarJob *
+thunar_io_jobs_link_files (GList *source_file_list,
+                           GList *target_file_list)
+{
+  _thunar_return_val_if_fail (source_file_list != NULL, NULL);
+  _thunar_return_val_if_fail (target_file_list != NULL, NULL);
+  _thunar_return_val_if_fail (g_list_length (source_file_list) == g_list_length (target_file_list), NULL);
+
+  return thunar_simple_job_launch (_thunar_io_jobs_link, 2,
+                                   G_TYPE_FILE_LIST, source_file_list,
+                                   G_TYPE_FILE_LIST, target_file_list);
+}

Modified: thunar/branches/migration-to-gio/thunar/thunar-io-jobs.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-io-jobs.h	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-io-jobs.h	2009-04-23 18:57:05 UTC (rev 29892)
@@ -32,6 +32,8 @@
                                             GList *target_file_list) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 ThunarJob *thunar_io_jobs_copy_files       (GList *source_file_list,
                                             GList *target_file_list) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+ThunarJob *thunar_io_jobs_link_files       (GList *source_file_list,
+                                            GList *target_file_list) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
 
 G_END_DECLS
 

Modified: thunar/branches/migration-to-gio/thunar/thunar-launcher.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-launcher.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-launcher.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -1141,28 +1141,28 @@
                                        ThunarLauncher *launcher)
 {
   ThunarApplication *application;
-  ThunarVfsPath     *desktop_path;
-  GList             *paths;
+  GFile             *desktop_file;
+  GList             *files;
 
   _thunar_return_if_fail (GTK_IS_ACTION (action));
   _thunar_return_if_fail (THUNAR_IS_LAUNCHER (launcher));
 
-  /* determine the source paths */
-  paths = thunar_file_list_to_path_list (launcher->selected_files);
-  if (G_UNLIKELY (paths == NULL))
+  /* determine the source files */
+  files = thunar_file_list_to_g_file_list (launcher->selected_files);
+  if (G_UNLIKELY (files == NULL))
     return;
 
-  /* determine the path to the ~/Desktop folder */
-  desktop_path = thunar_vfs_path_new (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), NULL);
+  /* determine the file to the ~/Desktop folder */
+  desktop_file = g_file_new_for_desktop ();
 
   /* launch the link job */
   application = thunar_application_get ();
-  thunar_application_link_into (application, launcher->widget, paths, desktop_path, NULL);
+  thunar_application_link_into (application, launcher->widget, files, desktop_file, NULL);
   g_object_unref (G_OBJECT (application));
 
   /* cleanup */
-  thunar_vfs_path_unref (desktop_path);
-  thunar_vfs_path_list_free (paths);
+  g_object_unref (desktop_file);
+  g_file_list_free (files);
 }
 
 

Modified: thunar/branches/migration-to-gio/thunar/thunar-permissions-chooser.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-permissions-chooser.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-permissions-chooser.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -749,7 +749,7 @@
     return;
 
   /* determine the new mode from the combo box */
-  for (n = 0; chooser->access_combos[n] != combo && n < G_N_ELEMENTS (chooser->access_combos); ++n);
+  for (n = 0; n < G_N_ELEMENTS (chooser->access_combos) && chooser->access_combos[n] != combo ; ++n);
   dir_mode = file_mode = (gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) << 1) << (n * 3);
   dir_mask = file_mask = 0006 << (n * 3);
 

Modified: thunar/branches/migration-to-gio/thunar/thunar-standard-view.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-standard-view.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-standard-view.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -1904,12 +1904,13 @@
       if (G_LIKELY (current_directory != NULL))
         {
           /* fake the source path list */
+          /* TODO Use a GFile here */
           source_path_list.data = info->path;
           source_path_list.next = NULL;
           source_path_list.prev = NULL;
 
           /* fake the target path list */
-          target_path_list.data = thunar_vfs_path_relative (thunar_file_get_path (current_directory), name);
+          target_path_list.data = g_file_get_child (thunar_file_get_file (current_directory), name);
           target_path_list.next = NULL;
           target_path_list.prev = NULL;
 
@@ -1920,7 +1921,7 @@
           g_object_unref (G_OBJECT (application));
 
           /* release the target path */
-          thunar_vfs_path_unref (target_path_list.data);
+          g_object_unref (target_path_list.data);
         }
 
       /* release the file name */
@@ -2175,7 +2176,7 @@
   ThunarApplication *application;
   ThunarFile        *current_directory;
   GClosure          *new_files_closure;
-  GList             *selected_paths;
+  GList             *selected_files;
 
   _thunar_return_if_fail (GTK_IS_ACTION (action));
   _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view));
@@ -2185,20 +2186,20 @@
   if (G_LIKELY (current_directory != NULL))
     {
       /* determine the selected paths for the view */
-      selected_paths = thunar_file_list_to_path_list (standard_view->selected_files);
-      if (G_LIKELY (selected_paths != NULL))
+      selected_files = thunar_file_list_to_g_file_list (standard_view->selected_files);
+      if (G_LIKELY (selected_files != NULL))
         {
           /* link the selected files into the current directory, which effectively
            * creates new unique links for the files.
            */
           application = thunar_application_get ();
           new_files_closure = thunar_standard_view_new_files_closure (standard_view);
-          thunar_application_link_into (application, GTK_WIDGET (standard_view), selected_paths,
-                                        thunar_file_get_path (current_directory), new_files_closure);
+          thunar_application_link_into (application, GTK_WIDGET (standard_view), selected_files,
+                                        thunar_file_get_file (current_directory), new_files_closure);
           g_object_unref (G_OBJECT (application));
 
           /* clean up */
-          thunar_vfs_path_list_free (selected_paths);
+          g_file_list_free (selected_files);
         }
     }
 }

Modified: thunar/branches/migration-to-gio/thunar/thunar-transfer-job.c
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-transfer-job.c	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-transfer-job.c	2009-04-23 18:57:05 UTC (rev 29892)
@@ -26,6 +26,7 @@
 #include <gio/gio.h>
 
 #include <thunar/thunar-io-scan-directory.h>
+#include <thunar/thunar-io-jobs-util.h>
 #include <thunar/thunar-job.h>
 #include <thunar/thunar-private.h>
 #include <thunar/thunar-transfer-job.h>
@@ -59,6 +60,8 @@
   GList                *target_file_list;
 
   guint64               total_size;
+  guint64               total_progress;
+  guint64               file_progress;
 };
 
 struct _ThunarTransferNode
@@ -120,6 +123,8 @@
   job->source_node_list = NULL;
   job->target_file_list = NULL;
   job->total_size = 0;
+  job->total_progress = 0;
+  job->file_progress = 0;
 }
 
 
@@ -148,8 +153,17 @@
 
   _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job));
   
-  if (G_LIKELY (total_num_bytes > 0))
-    thunar_job_percent (THUNAR_JOB (job), (current_num_bytes * 100.0) / total_num_bytes);
+  if (G_LIKELY (job->total_size > 0))
+    {
+      /* update total progress */
+      job->total_progress += (current_num_bytes - job->file_progress);
+
+      /* update file progress */
+      job->file_progress = current_num_bytes;
+
+      /* notify callers about the progress we made */
+      thunar_job_percent (THUNAR_JOB (job), (job->total_progress * 100.0) / job->total_size);
+    }
 }
 
 
@@ -226,40 +240,208 @@
 
 
 static gboolean
+ttj_copy_file (ThunarTransferJob *job,
+               GFile             *source_file,
+               GFile             *target_file,
+               GFileCopyFlags     copy_flags,
+               gboolean           merge_directories,
+               GError           **error)
+{
+  GFileType source_type;
+  GFileType target_type;
+  gboolean  target_exists;
+  GError   *err = NULL;
+
+  _thunar_return_val_if_fail (THUNAR_IS_TRANSFER_JOB (job), FALSE);
+  _thunar_return_val_if_fail (G_IS_FILE (source_file), FALSE);
+  _thunar_return_val_if_fail (G_IS_FILE (target_file), FALSE);
+  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  /* reset the file progress */
+  job->file_progress = 0;
+
+  if (thunar_job_set_error_if_cancelled (THUNAR_JOB (job), error))
+    return FALSE;
+
+  source_type = g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                        thunar_job_get_cancellable (THUNAR_JOB (job)));
+
+  if (thunar_job_set_error_if_cancelled (THUNAR_JOB (job), error))
+    return FALSE;
+
+  target_type = g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                        thunar_job_get_cancellable (THUNAR_JOB (job)));
+
+  if (thunar_job_set_error_if_cancelled (THUNAR_JOB (job), error))
+    return FALSE;
+
+  /* check if the target is a symlink and we are in overwrite mode */
+  if (target_type == G_FILE_TYPE_SYMBOLIC_LINK && (copy_flags & G_FILE_COPY_OVERWRITE) != 0)
+    {
+      /* try to delete the symlink */
+      if (!g_file_delete (target_file, thunar_job_get_cancellable (THUNAR_JOB (job)), &err))
+        {
+          g_propagate_error (error, err);
+          return FALSE;
+        }
+    }
+
+  /* try to copy the file */
+  g_file_copy (source_file, target_file, copy_flags,
+               thunar_job_get_cancellable (THUNAR_JOB (job)),
+               thunar_transfer_job_progress, THUNAR_JOB (job), &err);
+
+  /* check if there were errors */
+  if (G_UNLIKELY (err != NULL && err->domain == G_IO_ERROR))
+    {
+      if (err->code == G_IO_ERROR_WOULD_MERGE 
+          || (err->code == G_IO_ERROR_EXISTS 
+              && source_type == G_FILE_TYPE_DIRECTORY
+              && target_type == G_FILE_TYPE_DIRECTORY))
+        {
+          /* we tried to overwrite a directory with a directory. this normally results 
+           * in a merge. ignore the error we actually *want* to merge */
+          if (merge_directories)
+            g_clear_error (&err);
+        }
+      else if (err->code == G_IO_ERROR_WOULD_RECURSE)
+        {
+          g_clear_error (&err);
+
+          /* we tried to copy a directory and either 
+           *
+           * - the target did not exist which means we simple have to 
+           *   create the target directory
+           *
+           * or
+           *
+           * - the target is not a directory and we tried to overwrite it in 
+           *   which case we have to delete it first and then create the target
+           *   directory
+           */
+
+          /* check if the target file exists */
+          target_exists = g_file_query_exists (target_file,
+                                               thunar_job_get_cancellable (THUNAR_JOB (job)));
+
+          /* abort on cancellation, continue otherwise */
+          if (!thunar_job_set_error_if_cancelled (THUNAR_JOB (job), &err))
+            {
+              if (target_exists)
+                {
+                  /* the target still exists and thus is not a directory. try to remove it */
+                  g_file_delete (target_file, 
+                                 thunar_job_get_cancellable (THUNAR_JOB ((job))), 
+                                 &err);
+                }
+
+              /* abort on error or cancellation, continue otherwise */
+              if (err == NULL)
+                {
+                  /* now try to create the directory */
+                  g_file_make_directory (target_file, 
+                                         thunar_job_get_cancellable (THUNAR_JOB (job)), 
+                                         &err);
+                }
+            }
+        }
+    }
+
+  if (G_UNLIKELY (err != NULL))
+    {
+      g_propagate_error (error, err);
+      return FALSE;
+    }
+  else
+    {
+      return TRUE;
+    }
+}
+
+
+
+/**
+ * thunar_transfer_job_copy_file:
+ * @job                : a #ThunarTransferJob.
+ * @source_file        : the source #GFile to copy.
+ * @target_file        : the destination #GFile to copy to.
+ * @error              : return location for errors or %NULL.
+ *
+ * Tries to copy @source_file to @target_file. The real destination is the
+ * return value and may differ from @target_file (e.g. if you try to copy
+ * the file "/foo/bar" into the same directory you'll end up with something
+ * like "/foo/copy of bar" instead of "/foo/bar". 
+ *
+ * The return value is guaranteed to be %NULL on errors and @error will
+ * always be set in those cases. If the file is skipped, the return value
+ * will be @source_file.
+ *
+ * Return value: the destination #GFile to which @source_file was copied 
+ *               or linked. The caller is reposible to release it with 
+ *               g_object_unref() if no longer needed. It points to 
+ *               @source_file if the file was skipped and will be %NULL 
+ *               on error or cancellation.
+ **/
+static GFile *
 thunar_transfer_job_copy_file (ThunarTransferJob *job,
                                GFile             *source_file,
                                GFile             *target_file,
-                               GFile            **target_file_return,
                                GError           **error)
 {
   ThunarJobResponse response;
   GFileCopyFlags    copy_flags = G_FILE_COPY_NOFOLLOW_SYMLINKS;
   GError           *err = NULL;
+  gint              n;
 
-  _thunar_return_val_if_fail (THUNAR_IS_TRANSFER_JOB (job), FALSE);
-  _thunar_return_val_if_fail (G_IS_FILE (source_file), FALSE);
-  _thunar_return_val_if_fail (G_IS_FILE (target_file), FALSE);
-  _thunar_return_val_if_fail (target_file_return != NULL && *target_file_return == NULL, FALSE);
-  _thunar_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+  _thunar_return_val_if_fail (THUNAR_IS_TRANSFER_JOB (job), NULL);
+  _thunar_return_val_if_fail (G_IS_FILE (source_file), NULL);
+  _thunar_return_val_if_fail (G_IS_FILE (target_file), NULL);
+  _thunar_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
+  /* abort on cancellation */
   if (thunar_job_set_error_if_cancelled (THUNAR_JOB (job), error))
-    return FALSE;
+    return NULL;
 
   /* various attempts to copy the file */
   while (err == NULL)
     {
-      /* try to copy the file from source_file to the target_file */
-      /* TODO generate duplicate names like 'copy of \"%s\"' if source and target file
-       * are equal */
-      if (g_file_copy (source_file, target_file, copy_flags, 
-                       thunar_job_get_cancellable (THUNAR_JOB (job)),
-                       thunar_transfer_job_progress, THUNAR_JOB (job), &err))
+      if (G_LIKELY (!g_file_equal (source_file, target_file)))
         {
-          /* return the real target file */
-          *target_file_return = target_file;
-          return TRUE;
+          /* try to copy the file from source_file to the target_file */
+          if (ttj_copy_file (job, source_file, target_file, copy_flags, TRUE, &err))
+            {
+              /* return the real target file */
+              return g_object_ref (target_file);
+            }
         }
+      else
+        {
+          for (n = 1; err == NULL; ++n)
+            {
+              GFile *duplicate_file = thunar_io_jobs_util_next_duplicate_file (THUNAR_JOB (job), 
+                                                                               source_file, 
+                                                                               TRUE, n, &err);
 
+              if (err == NULL)
+                {
+                  /* try to copy the file from source file to the duplicate file */
+                  if (ttj_copy_file (job, source_file, duplicate_file, copy_flags, TRUE, &err))
+                    {
+                      /* return the real target file */
+                      return duplicate_file;
+                    }
+                  
+                  g_object_unref (duplicate_file);
+                }
+
+              if (err != NULL && err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
+                {
+                  /* this duplicate already exists => clear the error to try the next alternative */
+                  g_clear_error (&err);
+                }
+            }
+        }
+
       /* check if we can recover from this error */
       if (err->domain == G_IO_ERROR && err->code == G_IO_ERROR_EXISTS)
         {
@@ -267,7 +449,8 @@
           g_clear_error (&err);
 
           /* ask the user whether to replace the target file */
-          response = thunar_job_ask_replace (THUNAR_JOB (job), source_file, target_file, &err);
+          response = thunar_job_ask_replace (THUNAR_JOB (job), source_file, 
+                                             target_file, &err);
 
           if (err != NULL)
             break;
@@ -276,26 +459,24 @@
           if (response == THUNAR_JOB_RESPONSE_RETRY)
             continue;
 
-          /* add overwrite flag and try again if we should overwrite */
+          /* add overwrite flag and retry if we should overwrite */
           if (response == THUNAR_JOB_RESPONSE_YES)
             {
               copy_flags |= G_FILE_COPY_OVERWRITE;
               continue;
             }
 
-          /* check if the file should not be overwritten */
+          /* tell the caller we skipped the file if the user 
+           * doesn't want to retry/overwrite */
           if (response == THUNAR_JOB_RESPONSE_NO)
-            {
-              /* tell the caller that we skipped this one */
-              *target_file_return = NULL;
-              return TRUE;
-            }
+            return g_object_ref (source_file);
         }
     }
 
+  _thunar_assert (err != NULL);
+
   g_propagate_error (error, err);
-
-  return FALSE;
+  return NULL;
 }
 
 
@@ -311,7 +492,7 @@
   ThunarJobResponse response;
   GFileInfo        *info;
   GError           *err = NULL;
-  GFile            *target_file_return = NULL;
+  GFile            *real_target_file = NULL;
   gchar            *basename;
 
   _thunar_return_if_fail (THUNAR_IS_TRANSFER_JOB (job));
@@ -355,19 +536,18 @@
       thunar_job_info_message (THUNAR_JOB (job), g_file_info_get_display_name (info));
 
 retry_copy:
-      target_file_return = NULL;
-
       /* copy the item specified by this node (not recursively) */
-      if (thunar_transfer_job_copy_file (job, node->source_file, target_file, &target_file_return, &err))
+      real_target_file = thunar_transfer_job_copy_file (job, node->source_file, target_file, &err);
+      if (G_LIKELY (real_target_file != NULL))
         {
-          /* target file return == NULL means to skip the file */
-          if (G_LIKELY (target_file_return != NULL))
+          /* node->source_file == real_target_file means to skip the file */
+          if (G_LIKELY (node->source_file != real_target_file))
             {
               /* check if we have children to copy */
               if (node->children != NULL)
                 {
                   /* copy all children of this node */
-                  thunar_transfer_job_copy_node (job, node->children, NULL, target_file_return, NULL, &err);
+                  thunar_transfer_job_copy_node (job, node->children, NULL, real_target_file, NULL, &err);
 
                   /* free resources allocted for the children */
                   thunar_transfer_node_free (node->children);
@@ -378,16 +558,14 @@
               if (G_UNLIKELY (err != NULL))
                 {
                   /* outa here, freeing the target paths */
-                  g_object_unref (target_file_return);
+                  g_object_unref (real_target_file);
                   g_object_unref (target_file);
                   break;
                 }
 
               /* add the real target file to the return list */
               if (G_LIKELY (target_file_list_return != NULL))
-                *target_file_list_return = g_list_prepend (*target_file_list_return, target_file_return);
-              else
-                g_object_unref (target_file_return);
+                *target_file_list_return = g_file_list_prepend (*target_file_list_return, real_target_file);
 
 retry_remove:
               /* try to remove the source directory if we are on copy+remove fallback for move */
@@ -405,6 +583,8 @@
                     goto retry_remove;
                 }
             }
+
+          g_object_unref (real_target_file);
         }
       else if (err != NULL)
         { 
@@ -434,8 +614,6 @@
   /* propagate error if we failed or the job was cancelled */
   if (G_UNLIKELY (err != NULL))
     g_propagate_error (error, err);
-
-  return;
 }
 
 
@@ -493,8 +671,7 @@
                            G_FILE_COPY_NOFOLLOW_SYMLINKS 
                            | G_FILE_COPY_NO_FALLBACK_FOR_MOVE,
                            thunar_job_get_cancellable (job),
-                           thunar_transfer_job_progress,
-                           job, &err))
+                           NULL, NULL, &err))
             {
               /* add the target file to the new files list */
               new_files_list = g_file_list_prepend (new_files_list, tp->data);
@@ -525,6 +702,11 @@
                 }
             }
         }
+      else if (transfer_job->type == THUNAR_TRANSFER_JOB_COPY)
+        {
+          if (!thunar_transfer_job_collect_node (transfer_job, node, &err))
+            break;
+        }
 
       g_object_unref (info);
     }

Modified: thunar/branches/migration-to-gio/thunar/thunar-transfer-job.h
===================================================================
--- thunar/branches/migration-to-gio/thunar/thunar-transfer-job.h	2009-04-23 00:56:37 UTC (rev 29891)
+++ thunar/branches/migration-to-gio/thunar/thunar-transfer-job.h	2009-04-23 18:57:05 UTC (rev 29892)
@@ -33,6 +33,7 @@
 typedef enum /*< enum >*/
 {
   THUNAR_TRANSFER_JOB_COPY,
+  THUNAR_TRANSFER_JOB_LINK,
   THUNAR_TRANSFER_JOB_MOVE,
   THUNAR_TRANSFER_JOB_TRASH,
 } ThunarTransferJobType;




More information about the Xfce4-commits mailing list