summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2007-11-30 11:03:42 +0000
committerAlexander Larsson <alexl@src.gnome.org>2007-11-30 11:03:42 +0000
commited8a5525bb40107e9ca35a3950f41ab356d96c5d (patch)
treecf6d56c67fc6197015e187e715f27a07ce1a9c39
parent8a9680b4aef501c2421ca7f6ece470673680064d (diff)
downloadnautilus-ed8a5525bb40107e9ca35a3950f41ab356d96c5d.tar.gz
More uri -> gfile API changes
2007-11-30 Alexander Larsson <alexl@redhat.com> * libnautilus-private/nautilus-file-changes-queue.[ch]: More uri -> gfile API changes * libnautilus-private/nautilus-file-operations.[ch]: Add move operation * src/file-manager/fm-directory-view.c: Use move operation svn path=/branches/gio-branch/; revision=13461
-rw-r--r--ChangeLog11
-rw-r--r--libnautilus-private/nautilus-file-changes-queue.c26
-rw-r--r--libnautilus-private/nautilus-file-changes-queue.h12
-rw-r--r--libnautilus-private/nautilus-file-operations.c676
-rw-r--r--libnautilus-private/nautilus-file-operations.h7
-rw-r--r--src/file-manager/fm-directory-view.c16
6 files changed, 672 insertions, 76 deletions
diff --git a/ChangeLog b/ChangeLog
index 83a28a717..2b8854ee9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2007-11-30 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-file-changes-queue.[ch]:
+ More uri -> gfile API changes
+
+ * libnautilus-private/nautilus-file-operations.[ch]:
+ Add move operation
+
+ * src/file-manager/fm-directory-view.c:
+ Use move operation
+
2007-11-29 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-file-changes-queue.[ch]:
diff --git a/libnautilus-private/nautilus-file-changes-queue.c b/libnautilus-private/nautilus-file-changes-queue.c
index 14c64bb86..a5d0df5b5 100644
--- a/libnautilus-private/nautilus-file-changes-queue.c
+++ b/libnautilus-private/nautilus-file-changes-queue.c
@@ -223,7 +223,23 @@ nautilus_file_changes_queue_file_removed (GFile *location)
}
void
-nautilus_file_changes_queue_file_moved (const char *from, const char *to)
+nautilus_file_changes_queue_file_moved (GFile *from,
+ GFile *to)
+{
+ NautilusFileChange *new_item;
+ NautilusFileChangesQueue *queue;
+
+ queue = nautilus_file_changes_queue_get ();
+
+ new_item = g_new (NautilusFileChange, 1);
+ new_item->kind = CHANGE_FILE_MOVED;
+ new_item->from_uri = g_file_get_uri (from);
+ new_item->to_uri = g_file_get_uri (to);
+ nautilus_file_changes_queue_add_common (queue, new_item);
+}
+
+void
+nautilus_file_changes_queue_file_moved_by_uri (const char *from, const char *to)
{
NautilusFileChange *new_item;
NautilusFileChangesQueue *queue;
@@ -269,8 +285,8 @@ nautilus_file_changes_queue_schedule_metadata_copy_by_uri (const char *from_uri,
}
void
-nautilus_file_changes_queue_schedule_metadata_move (const char *from_uri,
- const char *to_uri)
+nautilus_file_changes_queue_schedule_metadata_move (GFile *from,
+ GFile *to)
{
NautilusFileChange *new_item;
NautilusFileChangesQueue *queue;
@@ -279,8 +295,8 @@ nautilus_file_changes_queue_schedule_metadata_move (const char *from_uri,
new_item = g_new (NautilusFileChange, 1);
new_item->kind = CHANGE_METADATA_MOVED;
- new_item->from_uri = g_strdup (from_uri);
- new_item->to_uri = g_strdup (to_uri);
+ new_item->from_uri = g_file_get_uri (from);
+ new_item->to_uri = g_file_get_uri (to);
nautilus_file_changes_queue_add_common (queue, new_item);
}
diff --git a/libnautilus-private/nautilus-file-changes-queue.h b/libnautilus-private/nautilus-file-changes-queue.h
index 9bdfcdfb7..221c64926 100644
--- a/libnautilus-private/nautilus-file-changes-queue.h
+++ b/libnautilus-private/nautilus-file-changes-queue.h
@@ -32,14 +32,16 @@ void nautilus_file_changes_queue_file_changed (GFile *lo
void nautilus_file_changes_queue_file_changed_by_uri (const char *uri);
void nautilus_file_changes_queue_file_removed (GFile *location);
void nautilus_file_changes_queue_file_removed_by_uri (const char *uri);
-void nautilus_file_changes_queue_file_moved (const char *from_uri,
+void nautilus_file_changes_queue_file_moved (GFile *from,
+ GFile *to);
+void nautilus_file_changes_queue_file_moved_by_uri (const char *from_uri,
const char *to_uri);
-void nautilus_file_changes_queue_schedule_metadata_copy (GFile *from,
- GFile *to);
+void nautilus_file_changes_queue_schedule_metadata_copy (GFile *from,
+ GFile *to);
void nautilus_file_changes_queue_schedule_metadata_copy_by_uri (const char *from_uri,
const char *to_uri);
-void nautilus_file_changes_queue_schedule_metadata_move (const char *from_uri,
- const char *to_uri);
+void nautilus_file_changes_queue_schedule_metadata_move (GFile *from,
+ GFile *to);
void nautilus_file_changes_queue_schedule_metadata_remove (GFile *location);
void nautilus_file_changes_queue_schedule_metadata_remove_by_uri (const char *uri);
void nautilus_file_changes_queue_schedule_position_set (GFile *location,
diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c
index 882529e1c..519505202 100644
--- a/libnautilus-private/nautilus-file-operations.c
+++ b/libnautilus-private/nautilus-file-operations.c
@@ -77,8 +77,12 @@
static gboolean confirm_trash_auto_value;
/* TODO:
- * Implement missing functions
+ * Add cancellation
+ * Implement missing functions:
+ * duplicate, new file, new folder, empty trash, set_permissions recursive
+ * Make delete handle recursive deletes
* Use CommonJob in trash/delete code
+ * TESTING!!!
*/
typedef struct {
@@ -98,6 +102,7 @@ typedef struct {
typedef struct {
CommonJob common;
+ gboolean is_move;
GList *files;
GFile *destination;
GdkPoint *icon_positions;
@@ -106,7 +111,7 @@ typedef struct {
GHashTable *debuting_files;
void (*done_callback) (GHashTable *debuting_uris, gpointer data);
gpointer done_callback_data;
-} CopyJob;
+} CopyMoveJob;
#define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 15
#define NSEC_PER_SEC 1000000000
@@ -4782,7 +4787,7 @@ verify_destination (CommonJob *job,
}
static void
-report_copy_progress (CopyJob *copy_job,
+report_copy_progress (CopyMoveJob *copy_job,
SourceInfo *source_info,
TransferInfo *transfer_info)
{
@@ -4792,9 +4797,12 @@ report_copy_progress (CopyJob *copy_job,
int remaining_time;
guint64 now;
CommonJob *job;
+ gboolean is_move;
job = (CommonJob *)copy_job;
+ is_move = copy_job->is_move;
+
now = g_thread_gettime ();
if (transfer_info->last_report_time != 0 &&
@@ -4812,19 +4820,25 @@ report_copy_progress (CopyJob *copy_job,
if (source_info->num_files == 1) {
nautilus_progress_info_take_status (job->progress,
- f (_("Copying \"%B\" to \"%B\""),
+ f (is_move ?
+ _("Moving \"%B\" to \"%B\""):
+ _("Copying \"%B\" to \"%B\""),
(GFile *)copy_job->files->data,
copy_job->destination));
} else if (copy_job->files != NULL &&
copy_job->files->next == NULL) {
nautilus_progress_info_take_status (job->progress,
- f (_("Copying %d files (in \"%B\") to \"%B\""),
+ f (is_move?
+ _("Moving %d files (in \"%B\") to \"%B\""):
+ _("Copying %d files (in \"%B\") to \"%B\""),
files_left,
(GFile *)copy_job->files->data,
copy_job->destination));
} else {
nautilus_progress_info_take_status (job->progress,
- f (_("Copying %d files to \"%B\""),
+ f (is_move?
+ _("Moving %d files to \"%B\""):
+ _("Copying %d files to \"%B\""),
files_left, copy_job->destination));
}
@@ -4931,14 +4945,16 @@ is_dir (GFile *file)
return res;
}
-static void copy_file (CopyJob *job,
- GFile *src,
- GFile *dest_dir,
- gboolean same_fs,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- GHashTable *debuting_files,
- GdkPoint *point);
+static void copy_move_file (CopyMoveJob *job,
+ GFile *src,
+ GFile *dest_dir,
+ gboolean same_fs,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info,
+ GHashTable *debuting_files,
+ GdkPoint *point,
+ gboolean overwrite,
+ gboolean *skipped_file);
static gboolean
create_dest_dir (CommonJob *job,
@@ -4991,14 +5007,15 @@ create_dest_dir (CommonJob *job,
}
static void
-copy_directory (CopyJob *copy_job,
- GFile *src,
- GFile *dest,
- gboolean same_fs,
- gboolean create_dest,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- GHashTable *debuting_files)
+copy_move_directory (CopyMoveJob *copy_job,
+ GFile *src,
+ GFile *dest,
+ gboolean same_fs,
+ gboolean create_dest,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info,
+ GHashTable *debuting_files,
+ gboolean *skipped_file)
{
GFileInfo *info;
GError *error;
@@ -5007,12 +5024,14 @@ copy_directory (CopyJob *copy_job,
char *primary, *secondary, *details;
int response;
gboolean skip_error;
+ gboolean local_skipped_file;
CommonJob *job;
job = (CommonJob *)copy_job;
if (create_dest) {
if (!create_dest_dir (job, src, dest)) {
+ *skipped_file = TRUE;
return;
}
if (debuting_files) {
@@ -5020,7 +5039,9 @@ copy_directory (CopyJob *copy_job,
}
}
-
+
+ local_skipped_file = FALSE;
+
skip_error = should_skip_readdir_error (job, src);
retry:
error = NULL;
@@ -5036,13 +5057,17 @@ copy_directory (CopyJob *copy_job,
(info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
src_file = g_file_get_child (src,
g_file_info_get_name (info));
- copy_file (copy_job, src_file, dest, same_fs, source_info, transfer_info, NULL, NULL);
+ copy_move_file (copy_job, src_file, dest, same_fs, source_info, transfer_info, NULL, NULL, FALSE, &local_skipped_file);
g_object_unref (info);
}
g_file_enumerator_close (enumerator, job->cancellable, NULL);
if (error) {
- primary = f (_("Error while copying."));
+ if (copy_job->is_move) {
+ primary = f (_("Error while moving."));
+ } else {
+ primary = f (_("Error while copying."));
+ }
details = NULL;
if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
@@ -5066,6 +5091,7 @@ copy_directory (CopyJob *copy_job,
job->aborted = TRUE;
} else if (response == 1) {
/* Skip: Do Nothing */
+ local_skipped_file = TRUE;
} else {
g_assert_not_reached ();
}
@@ -5079,7 +5105,11 @@ copy_directory (CopyJob *copy_job,
g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (create_dest));
}
} else {
- primary = f (_("Error while copying."));
+ if (copy_job->is_move) {
+ primary = f (_("Error while moving."));
+ } else {
+ primary = f (_("Error while copying."));
+ }
details = NULL;
if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
@@ -5094,7 +5124,7 @@ copy_directory (CopyJob *copy_job,
primary,
secondary,
details,
- SKIP, GTK_STOCK_CANCEL, RETRY,
+ GTK_STOCK_CANCEL, SKIP, RETRY,
NULL);
g_error_free (error);
@@ -5103,6 +5133,7 @@ copy_directory (CopyJob *copy_job,
job->aborted = TRUE;
} else if (response == 1) {
/* Skip: Do Nothing */
+ local_skipped_file = TRUE;
} else if (response == 2) {
goto retry;
} else {
@@ -5116,6 +5147,44 @@ copy_directory (CopyJob *copy_job,
G_FILE_COPY_NOFOLLOW_SYMLINKS,
job->cancellable, NULL);
}
+
+ if (!job->aborted && copy_job->is_move &&
+ /* Don't delete source if there was a skipped file */
+ !local_skipped_file) {
+ if (!g_file_delete (src, job->cancellable, &error)) {
+ if (job->skip_all_error) {
+ goto skip;
+ }
+ primary = f (_("Error while moving \"%B\"."), src);
+ secondary = f (_("Couldn't remove the source folder."));
+ details = error->message;
+
+ response = run_warning (job,
+ primary,
+ secondary,
+ details,
+ GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
+ NULL);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ job->aborted = TRUE;
+ } else if (response == 1) { /* skip all */
+ job->skip_all_error = TRUE;
+ local_skipped_file = TRUE;
+ } else if (response == 2) { /* skip */
+ local_skipped_file = TRUE;
+ } else {
+ g_assert_not_reached ();
+ }
+
+ skip:
+ g_error_free (error);
+ }
+ }
+
+ if (local_skipped_file) {
+ *skipped_file = TRUE;
+ }
}
static gboolean
@@ -5234,7 +5303,7 @@ remove_target_recursively (CommonJob *job,
}
typedef struct {
- CopyJob *job;
+ CopyMoveJob *job;
goffset last_size;
SourceInfo *source_info;
TransferInfo *transfer_info;
@@ -5263,33 +5332,34 @@ copy_file_progress_callback (goffset current_num_bytes,
/* Debuting files is non-NULL only for toplevel items */
static void
-copy_file (CopyJob *copy_job,
- GFile *src,
- GFile *dest_dir,
- gboolean same_fs,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- GHashTable *debuting_files,
- GdkPoint *position)
+copy_move_file (CopyMoveJob *copy_job,
+ GFile *src,
+ GFile *dest_dir,
+ gboolean same_fs,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info,
+ GHashTable *debuting_files,
+ GdkPoint *position,
+ gboolean overwrite,
+ gboolean *skipped_file)
{
GFile *dest;
GError *error;
- gboolean overwrite;
GFileCopyFlags flags;
char *primary, *secondary, *details;
int response;
ProgressData pdata;
gboolean would_recurse;
CommonJob *job;
+ gboolean res;
job = (CommonJob *)copy_job;
if (should_skip_file (job, src)) {
+ *skipped_file = TRUE;
return;
}
- overwrite = FALSE;
-
dest = get_target_file (src, dest_dir, same_fs);
retry:
@@ -5303,12 +5373,24 @@ copy_file (CopyJob *copy_job,
pdata.last_size = 0;
pdata.source_info = source_info;
pdata.transfer_info = transfer_info;
- if (g_file_copy (src, dest,
- flags,
- job->cancellable,
- copy_file_progress_callback,
- &pdata,
- &error)) {
+
+ if (copy_job->is_move) {
+ res = g_file_move (src, dest,
+ flags,
+ job->cancellable,
+ copy_file_progress_callback,
+ &pdata,
+ &error);
+ } else {
+ res = g_file_copy (src, dest,
+ flags,
+ job->cancellable,
+ copy_file_progress_callback,
+ &pdata,
+ &error);
+ }
+
+ if (res) {
transfer_info->num_files ++;
report_copy_progress (copy_job, source_info, transfer_info);
@@ -5322,9 +5404,8 @@ copy_file (CopyJob *copy_job,
g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE));
}
- g_object_unref (dest);
-
nautilus_file_changes_queue_file_added (dest);
+ g_object_unref (dest);
return;
}
@@ -5430,11 +5511,16 @@ copy_file (CopyJob *copy_job,
error = NULL;
/* Copying a dir onto file, first remove the file */
- if (!g_file_delete (dest, job->cancellable, &error)) {
+ if (!g_file_delete (dest, job->cancellable, &error) &&
+ !IS_IO_ERROR (error, NOT_FOUND)) {
if (job->skip_all_error) {
goto out;
}
- primary = f (_("Error while copying \"%B\"."), src);
+ if (copy_job->is_move) {
+ primary = f (_("Error while moving \"%B\"."), src);
+ } else {
+ primary = f (_("Error while copying \"%B\"."), src);
+ }
secondary = f (_("Couldn't remove the already existing file with the same name in %F."), dest_dir);
details = error->message;
@@ -5459,16 +5545,23 @@ copy_file (CopyJob *copy_job,
goto out;
}
+ if (error) {
+ g_error_free (error);
+ error = NULL;
+ }
if (debuting_files) { /* Only remove metadata for toplevel items */
nautilus_file_changes_queue_schedule_metadata_remove (dest);
}
nautilus_file_changes_queue_file_removed (dest);
}
- copy_directory (copy_job, src, dest, same_fs,
- would_recurse,
- source_info, transfer_info,
- debuting_files);
+ copy_move_directory (copy_job, src, dest, same_fs,
+ would_recurse,
+ source_info, transfer_info,
+ debuting_files, skipped_file);
+
+ g_object_unref (dest);
+ return;
}
/* Other error */
@@ -5477,7 +5570,7 @@ copy_file (CopyJob *copy_job,
goto out;
}
primary = f (_("Error while copying \"%B\"."), src);
- secondary = f (_("There was an error getting copying the file into %F."), dest_dir);
+ secondary = f (_("There was an error copying the file into %F."), dest_dir);
details = error->message;
response = run_warning (job,
@@ -5500,12 +5593,12 @@ copy_file (CopyJob *copy_job,
}
}
out:
-
+ *skipped_file = TRUE; /* Or aborted, but same-same */
g_object_unref (dest);
}
static void
-copy_files (CopyJob *job,
+copy_files (CopyMoveJob *job,
const char *dest_fs_id,
SourceInfo *source_info,
TransferInfo *transfer_info)
@@ -5516,6 +5609,7 @@ copy_files (CopyJob *job,
gboolean same_fs;
int i;
GdkPoint *point;
+ gboolean skipped_file;
common = &job->common;
@@ -5538,12 +5632,13 @@ copy_files (CopyJob *job,
if (dest_fs_id) {
same_fs = has_fs_id (src, dest_fs_id);
}
-
- copy_file (job, src, job->destination,
- same_fs,
- source_info, transfer_info,
- job->debuting_files,
- point);
+
+ skipped_file = FALSE;
+ copy_move_file (job, src, job->destination,
+ same_fs,
+ source_info, transfer_info,
+ job->debuting_files,
+ point, FALSE, &skipped_file);
i++;
}
}
@@ -5551,7 +5646,7 @@ copy_files (CopyJob *job,
static void
copy_job_done (gpointer user_data)
{
- CopyJob *job;
+ CopyMoveJob *job;
job = user_data;
if (job->done_callback) {
@@ -5561,8 +5656,11 @@ copy_job_done (gpointer user_data)
eel_g_object_list_free (job->files);
g_object_unref (job->destination);
g_hash_table_unref (job->debuting_files);
+ g_free (job->icon_positions);
finalize_common ((CommonJob *)job);
+
+ nautilus_file_changes_consume_changes (TRUE);
}
static void
@@ -5570,7 +5668,7 @@ copy_job (GIOJob *io_job,
GCancellable *cancellable,
gpointer user_data)
{
- CopyJob *job;
+ CopyMoveJob *job;
CommonJob *common;
SourceInfo source_info;
TransferInfo transfer_info;
@@ -5626,10 +5724,10 @@ nautilus_file_operations_copy (GList *files,
void (*done_callback) (GHashTable *debuting_files, gpointer data),
gpointer done_callback_data)
{
- CopyJob *job;
+ CopyMoveJob *job;
GdkScreen *screen;
- job = op_job_new (CopyJob, parent_window);
+ job = op_job_new (CopyMoveJob, parent_window);
job->done_callback = done_callback;
job->done_callback_data = done_callback_data;
job->files = eel_g_object_list_copy (files);
@@ -5655,6 +5753,452 @@ nautilus_file_operations_copy (GList *files,
job->common.cancellable);
}
+static void
+report_move_progress (CopyMoveJob *move_job, int total, int left)
+{
+ CommonJob *job;
+
+ job = (CommonJob *)move_job;
+
+ nautilus_progress_info_take_status (job->progress,
+ f (_("Preparing to Move to \"%B\""),
+ move_job->destination));
+
+ nautilus_progress_info_take_details (job->progress,
+ f (_("Preparing to move %d files"), left));
+
+ nautilus_progress_info_pulse_progress (job->progress);
+}
+
+static void
+move_file_prepare (CopyMoveJob *move_job,
+ GFile *src,
+ GFile *dest_dir,
+ gboolean same_fs,
+ GHashTable *debuting_files,
+ GdkPoint *position,
+ GList **copy_files,
+ GArray *copy_positions)
+{
+ GFile *dest;
+ GError *error;
+ CommonJob *job;
+ gboolean overwrite;
+ char *primary, *secondary, *details;
+ int response;
+ GFileCopyFlags flags;
+ gboolean would_recurse;
+
+ overwrite = FALSE;
+
+ job = (CommonJob *)move_job;
+
+ dest = get_target_file (src, dest_dir, same_fs);
+
+ retry:
+
+ flags = G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_NO_FALLBACK_FOR_MOVE;
+ if (overwrite) {
+ flags |= G_FILE_COPY_OVERWRITE;
+ }
+
+ error = NULL;
+ if (g_file_move (src, dest,
+ flags,
+ job->cancellable,
+ NULL,
+ NULL,
+ &error)) {
+
+ if (debuting_files) {
+ g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE));
+ }
+
+ nautilus_file_changes_queue_file_moved (src, dest);
+ nautilus_file_changes_queue_schedule_metadata_move (src, dest);
+
+ return;
+ }
+
+ /* Conflict */
+ if (!overwrite &&
+ IS_IO_ERROR (error, EXISTS)) {
+ gboolean is_merge;
+
+ g_error_free (error);
+
+ is_merge = FALSE;
+ if (is_dir (dest)) {
+ if (is_dir (src)) {
+ is_merge = TRUE;
+ primary = f (_("A folder named \"%B\" already exists. Do you want to merge the source folder?"),
+ dest);
+ secondary = f (_("The source folder already exists in \"%B\". "
+ "Merging will ask for confirmation before replacing any files in the folder that conflict with the files being moved."),
+ dest_dir);
+
+ } else {
+ primary = f (_("A folder named \"%B\" already exists. Do you want to replace it?"),
+ dest);
+ secondary = f (_("The folder already exists in \"%F\". "
+ "Replacing it will remove all files in the folder."),
+ dest_dir);
+ }
+ } else {
+ primary = f (_("A file named \"%B\" already exists. Do you want to replace it?"),
+ dest);
+ secondary = f (_("The file already exists in \"%F\". "
+ "Replacing it will overwrite its content."),
+ dest_dir);
+ }
+
+ if ((is_merge && job->merge_all) ||
+ (!is_merge && job->replace_all)) {
+ g_free (primary);
+ g_free (secondary);
+ g_error_free (error);
+
+ overwrite = TRUE;
+ goto retry;
+ }
+
+ if (job->skip_all_conflict) {
+ g_free (primary);
+ g_free (secondary);
+ g_error_free (error);
+
+ goto out;
+ }
+
+ response = run_warning (job,
+ primary,
+ secondary,
+ NULL,
+ GTK_STOCK_CANCEL,
+ SKIP_ALL,
+ is_merge?MERGE_ALL:REPLACE_ALL,
+ SKIP,
+ is_merge?MERGE:REPLACE,
+ NULL);
+
+ g_error_free (error);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ job->aborted = TRUE;
+ } else if (response == 1 || response == 3) { /* skip all / skip */
+ if (response == 1) {
+ job->skip_all_conflict = TRUE;
+ }
+ } else if (response == 2 || response == 4) { /* merge/replace all / merge/replace*/
+ if (response == 2) {
+ if (is_merge) {
+ job->merge_all = TRUE;
+ } else {
+ job->replace_all = TRUE;
+ }
+ }
+ overwrite = TRUE;
+ goto retry;
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+
+ else if (IS_IO_ERROR (error, WOULD_RECURSE) ||
+ IS_IO_ERROR (error, WOULD_MERGE) ||
+ IS_IO_ERROR (error, NOT_SUPPORTED)) {
+ gboolean delete_dest;
+ would_recurse = error->code == G_IO_ERROR_WOULD_RECURSE;
+ g_error_free (error);
+
+ delete_dest = FALSE;
+ if (overwrite && would_recurse) {
+ delete_dest = TRUE;
+
+ error = NULL;
+ }
+
+ *copy_files = g_list_prepend (*copy_files, src);
+ if (position) {
+ g_array_append_val (copy_positions, *position);
+ }
+ }
+
+ /* Other error */
+ else {
+ if (job->skip_all_error) {
+ goto out;
+ }
+ primary = f (_("Error while moving \"%B\"."), src);
+ secondary = f (_("There was an error moving the file into %F."), dest_dir);
+ details = error->message;
+
+ response = run_warning (job,
+ primary,
+ secondary,
+ details,
+ GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
+ NULL);
+
+ g_error_free (error);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ job->aborted = TRUE;
+ } else if (response == 1) { /* skip all */
+ job->skip_all_error = TRUE;
+ } else if (response == 2) { /* skip */
+ /* do nothing */
+ } else {
+ g_assert_not_reached ();
+ }
+ }
+
+ out:
+ g_object_unref (dest);
+}
+
+static void
+move_files_prepare (CopyMoveJob *job,
+ const char *dest_fs_id,
+ GList **copy_files,
+ GArray *copy_positions)
+{
+ CommonJob *common;
+ GList *l;
+ GFile *src;
+ gboolean same_fs;
+ int i;
+ GdkPoint *point;
+ int total, left;
+
+ common = &job->common;
+
+ total = left = g_list_length (job->files);
+
+ report_move_progress (job, total, left);
+
+ i = 0;
+ for (l = job->files;
+ l != NULL && !common->aborted ;
+ l = l->next) {
+ src = l->data;
+
+ if (i < job->n_icon_positions) {
+ point = &job->icon_positions[i];
+ } else {
+ point = NULL;
+ }
+
+
+ same_fs = FALSE;
+ if (dest_fs_id) {
+ same_fs = has_fs_id (src, dest_fs_id);
+ }
+
+ move_file_prepare (job, src, job->destination,
+ same_fs,
+ job->debuting_files,
+ point,
+ copy_files,
+ copy_positions);
+ i++;
+ }
+
+}
+
+static void
+move_files (CopyMoveJob *job,
+ GList *files,
+ GArray *icon_positions,
+ const char *dest_fs_id,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info)
+{
+ CommonJob *common;
+ GList *l;
+ GFile *src;
+ gboolean same_fs;
+ int i;
+ GdkPoint *point;
+ gboolean skipped_file;
+
+ common = &job->common;
+
+ report_copy_progress (job, source_info, transfer_info);
+
+ i = 0;
+ for (l = files;
+ l != NULL && !common->aborted ;
+ l = l->next) {
+ src = l->data;
+
+ if (i < icon_positions->len) {
+ point = &g_array_index (icon_positions, GdkPoint, i);
+ } else {
+ point = NULL;
+ }
+
+ same_fs = FALSE;
+ if (dest_fs_id) {
+ same_fs = has_fs_id (src, dest_fs_id);
+ }
+
+ /* Set overwrite to true, as the user has
+ selected overwrite on all toplevel items */
+ skipped_file = FALSE;
+ copy_move_file (job, src, job->destination,
+ same_fs,
+ source_info, transfer_info,
+ job->debuting_files,
+ point, TRUE, &skipped_file);
+ i++;
+ }
+}
+
+
+static void
+move_job_done (gpointer user_data)
+{
+ CopyMoveJob *job;
+
+ job = user_data;
+ if (job->done_callback) {
+ job->done_callback (job->debuting_files, job->done_callback_data);
+ }
+
+ eel_g_object_list_free (job->files);
+ g_object_unref (job->destination);
+ g_hash_table_unref (job->debuting_files);
+ g_free (job->icon_positions);
+
+ finalize_common ((CommonJob *)job);
+
+ nautilus_file_changes_consume_changes (TRUE);
+}
+
+static void
+move_job (GIOJob *io_job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ CopyMoveJob *job;
+ CommonJob *common;
+ GList *copy_files;
+ GArray *copy_positions;
+ SourceInfo source_info;
+ TransferInfo transfer_info;
+ char *dest_fs_id;
+
+ job = user_data;
+ common = &job->common;
+ common->io_job = io_job;
+
+ dest_fs_id = NULL;
+
+ copy_files = NULL;
+ copy_positions = NULL;
+
+ nautilus_progress_info_start (job->common.progress);
+
+ verify_destination (&job->common,
+ job->destination,
+ &dest_fs_id,
+ -1);
+ if (common->aborted) {
+ goto aborted;
+ }
+
+ copy_files = NULL;
+ copy_positions = g_array_new (FALSE, TRUE, sizeof (GdkPoint));
+
+ /* This moves all files that we can do without copy + delete */
+ move_files_prepare (job, dest_fs_id, &copy_files, copy_positions);
+ if (common->aborted) {
+ goto aborted;
+ }
+
+ copy_files = g_list_reverse (copy_files);
+
+ /* The rest we need to do deep copy + delete behind on,
+ so scan for size */
+
+ memset (&source_info, 0, sizeof (SourceInfo));
+ scan_sources (copy_files,
+ &source_info,
+ common);
+ if (common->aborted) {
+ goto aborted;
+ }
+
+ verify_destination (&job->common,
+ job->destination,
+ &dest_fs_id,
+ source_info.num_bytes);
+ if (common->aborted) {
+ goto aborted;
+ }
+
+ memset (&transfer_info, 0, sizeof (transfer_info));
+ move_files (job,
+ copy_files,
+ copy_positions,
+ dest_fs_id,
+ &source_info, &transfer_info);
+
+ aborted:
+ g_list_free (copy_files);
+ if (copy_positions) {
+ g_array_free (copy_positions, TRUE);
+ }
+
+ g_free (dest_fs_id);
+
+ g_io_job_send_to_mainloop (io_job,
+ move_job_done,
+ job,
+ NULL,
+ FALSE);
+}
+
+void
+nautilus_file_operations_move (GList *files,
+ GArray *relative_item_points,
+ GFile *target_dir,
+ GtkWindow *parent_window,
+ void (*done_callback) (GHashTable *debuting_files, gpointer data),
+ gpointer done_callback_data)
+{
+ CopyMoveJob *job;
+ GdkScreen *screen;
+
+ job = op_job_new (CopyMoveJob, parent_window);
+ job->is_move = TRUE;
+ job->done_callback = done_callback;
+ job->done_callback_data = done_callback_data;
+ job->files = eel_g_object_list_copy (files);
+ job->destination = g_object_ref (target_dir);
+ if (relative_item_points != NULL &&
+ relative_item_points->len > 0) {
+ job->icon_positions =
+ g_memdup (relative_item_points->data,
+ sizeof (GdkPoint) * relative_item_points->len);
+ job->n_icon_positions = relative_item_points->len;
+ }
+ job->screen_num = 0;
+ if (parent_window) {
+ screen = gtk_widget_get_screen (GTK_WIDGET (parent_window));
+ job->screen_num = gdk_screen_get_number (screen);
+ }
+ job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
+
+ g_schedule_io_job (move_job,
+ job,
+ NULL, /* destroy notify */
+ 0,
+ job->common.cancellable);
+}
+
+
static void
not_supported_yet (void)
diff --git a/libnautilus-private/nautilus-file-operations.h b/libnautilus-private/nautilus-file-operations.h
index ba29c0381..02ba0842b 100644
--- a/libnautilus-private/nautilus-file-operations.h
+++ b/libnautilus-private/nautilus-file-operations.h
@@ -102,4 +102,11 @@ void nautilus_file_operations_copy (GList *files,
void (*done_callback) (GHashTable *debuting_uris, gpointer data),
gpointer done_callback_data);
+void nautilus_file_operations_move (GList *files,
+ GArray *relative_item_points,
+ GFile *target_dir,
+ GtkWindow *parent_window,
+ void (*done_callback) (GHashTable *debuting_files, gpointer data),
+ gpointer done_callback_data);
+
#endif /* NAUTILUS_FILE_OPERATIONS_H */
diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c
index 35ce1d052..c12985567 100644
--- a/src/file-manager/fm-directory-view.c
+++ b/src/file-manager/fm-directory-view.c
@@ -8159,6 +8159,22 @@ fm_directory_view_move_copy_items (const GList *item_uris,
eel_g_object_list_free (locations);
g_object_unref (dest);
+ } else if (copy_action == GDK_ACTION_MOVE) {
+ GList *locations;
+ GFile *dest;
+
+ dest = g_file_new_for_uri (target_uri);
+ locations = location_list_from_uri_list (item_uris);
+
+ nautilus_file_operations_move (locations,
+ relative_item_points,
+ dest,
+ fm_directory_view_get_containing_window (view),
+ copy_move_done_callback,
+ pre_copy_move (view));
+
+ eel_g_object_list_free (locations);
+ g_object_unref (dest);
} else {
nautilus_file_operations_copy_move
(item_uris, relative_item_points,