[nautilus/wip/csoriano/file-operations-rename: 2/2] file-operations: implement files rename
- From: Carlos Soriano Sánchez <csoriano src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/csoriano/file-operations-rename: 2/2] file-operations: implement files rename
- Date: Thu, 25 Aug 2016 13:50:23 +0000 (UTC)
commit 75f61633c72c7190256f24a2e8e902f3c64a2e83
Author: Carlos Soriano <csoriano gnome org>
Date: Thu Aug 25 15:49:05 2016 +0200
file-operations: implement files rename
src/nautilus-file-operations.c | 407 +++++++++++++++++++++++++++++++++++++---
src/nautilus-file-operations.h | 3 +
2 files changed, 381 insertions(+), 29 deletions(-)
---
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 24124da..0fdcc00 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -107,6 +107,14 @@ typedef struct {
typedef struct {
CommonJob common;
+ GList *files;
+ GList *new_names;
+ NautilusRenameCallback done_callback;
+ gpointer done_callback_data;
+} RenameJob;
+
+typedef struct {
+ CommonJob common;
GFile *dest_dir;
char *filename;
gboolean make_dir;
@@ -120,7 +128,6 @@ typedef struct {
gpointer done_callback_data;
} CreateJob;
-
typedef struct {
CommonJob common;
GList *trash_dirs;
@@ -153,7 +160,8 @@ typedef enum {
OP_KIND_MOVE,
OP_KIND_DELETE,
OP_KIND_TRASH,
- OP_KIND_COMPRESS
+ OP_KIND_COMPRESS,
+ OP_KIND_RENAME
} OpKind;
typedef struct {
@@ -243,7 +251,8 @@ is_all_button_text (const char *button_text)
static void scan_sources (GList *files,
SourceInfo *source_info,
CommonJob *job,
- OpKind kind);
+ OpKind kind,
+ gboolean recursive);
static void empty_trash_thread_func (GTask *task,
@@ -1793,7 +1802,7 @@ delete_files (CommonJob *job, GList *files, int *files_skipped)
SourceInfo source_info;
TransferInfo transfer_info;
DeleteData data;
-
+
if (job_aborted (job)) {
return;
}
@@ -1801,7 +1810,8 @@ delete_files (CommonJob *job, GList *files, int *files_skipped)
scan_sources (files,
&source_info,
job,
- OP_KIND_DELETE);
+ OP_KIND_DELETE,
+ TRUE);
if (job_aborted (job)) {
return;
}
@@ -2088,7 +2098,8 @@ trash_files (CommonJob *job,
scan_sources (files,
&source_info,
job,
- OP_KIND_TRASH);
+ OP_KIND_TRASH,
+ TRUE);
if (job_aborted (job)) {
return;
}
@@ -2281,6 +2292,334 @@ nautilus_file_operations_delete (GList *files,
done_callback, done_callback_data);
}
+static gchar*
+can_rename_file (GFile *file,
+ const char *new_name)
+{
+ GError *error;
+ gboolean is_renameable_desktop_file;
+ gboolean success;
+ gboolean name_changed;
+ gchar *new_file_name;
+ gchar *uri;
+ gchar *old_name;
+ g_autoptr (GFileInfo) info;
+ g_autofree gchar *content_type;
+
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE","
+ G_FILE_COPY_NOFOLLOW_SYMLINKS,
+ job->common.cancellable,
+ NULL);
+
+ content_type = g_file_info_get_content_type (info);
+ is_desktop_file = g_content_type_is_a (content_type, );
+ is_renameable_desktop_file =
+ is_desktop_file (file) && can_rename_desktop_file (file);
+
+ /* Return an error for incoming names containing path separators.
+ * But not for .desktop files as '/' are allowed for them */
+ if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Slashes are not allowed in filenames"));
+ if (callback != NULL)
+ (* callback) (file, NULL, error, callback_data);
+ g_error_free (error);
+ return NULL;
+ }
+
+ /* Can't rename a file that's already gone.
+ * We need to check this here because there may be a new
+ * file with the same name.
+ */
+ if (nautilus_file_rename_handle_file_gone (file, callback, callback_data)) {
+ return NULL;
+ }
+
+ /* Test the name-hasn't-changed case explicitly, for two reasons.
+ * (1) rename returns an error if new & old are same.
+ * (2) We don't want to send file-changed signal if nothing changed.
+ */
+ if (!is_renameable_desktop_file &&
+ name_is (file, new_name)) {
+ if (callback != NULL)
+ (* callback) (file, NULL, NULL, callback_data);
+ return NULL;
+ }
+
+ /* Self-owned files can't be renamed. Test the name-not-actually-changing
+ * case before this case.
+ */
+ if (nautilus_file_is_self_owned (file)) {
+ /* Claim that something changed even if the rename
+ * failed. This makes it easier for some clients who
+ * see the "reverting" to the old name as "changing
+ * back".
+ */
+ nautilus_file_changed (file);
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Toplevel files cannot be renamed"));
+
+ if (callback != NULL)
+ (* callback) (file, NULL, error, callback_data);
+ g_error_free (error);
+
+ return NULL;
+ }
+
+ if (is_renameable_desktop_file) {
+ /* Don't actually change the name if the new name is the same.
+ * This helps for the vfolder method where this can happen and
+ * we want to minimize actual changes
+ */
+ uri = nautilus_file_get_uri (file);
+ old_name = nautilus_link_local_get_text (uri);
+ if (old_name != NULL && strcmp (new_name, old_name) == 0) {
+ success = TRUE;
+ name_changed = FALSE;
+ } else {
+ success = nautilus_link_local_set_text (uri, new_name);
+ name_changed = TRUE;
+ }
+ g_free (old_name);
+ g_free (uri);
+
+ if (!success) {
+ error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Probably the content of the file is an invalid desktop file
format"));
+ if (callback != NULL)
+ (* callback) (file, NULL, error, callback_data);
+ g_error_free (error);
+ return NULL;
+ }
+ new_file_name = g_strdup_printf ("%s.desktop", new_name);
+ new_file_name = g_strdelimit (new_file_name, "/", '-');
+
+ if (name_is (file, new_file_name)) {
+ if (name_changed) {
+ nautilus_file_invalidate_attributes (file,
+ NAUTILUS_FILE_ATTRIBUTE_INFO |
+ NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
+ }
+
+ if (callback != NULL)
+ (* callback) (file, NULL, NULL, callback_data);
+ g_free (new_file_name);
+ return NULL;
+ }
+ } else {
+ new_file_name = g_strdup (new_name);
+ }
+
+ return new_file_name;
+}
+
+static void
+rename_files (CommonJob *job,
+ GList *files,
+ GList *new_names)
+{
+
+}
+static void
+report_rename_progress (CommonJob *job,
+ SourceInfo *source_info,
+ TransferInfo *transfer_info)
+{
+ int files_left;
+ char *details;
+ char *status;
+ RenameJob *delete_job;
+ GFile *current_file;
+ gchar *new_file_name;
+
+ rename_job = (RenameJob *) job;
+ files_left = source_info->num_files - transfer_info->num_files;
+
+ /* Races and whatnot could cause this to be negative... */
+ if (files_left < 0) {
+ files_left = 0;
+ }
+
+ if (source_info->num_files == 1) {
+ if (files_left > 0) {
+ status = _("Renaming “%B”");
+ } else {
+ status = _("Renamed “%B”");
+ }
+ nautilus_progress_info_take_status (job->progress,
+ f (status,
+ (GFile*) rename_job->files->data));
+
+ } else {
+ if (files_left > 0) {
+ status = ngettext ("Renaming %'d file",
+ "Renaming %'d files",
+ source_info->num_files);
+ } else {
+ status = ngettext ("Renamed %'d file",
+ "Renamed %'d files",
+ source_info->num_files);
+ }
+ nautilus_progress_info_take_status (job->progress,
+ f (status,
+ source_info->num_files));
+ }
+
+ current_file = g_list_nth_data (source_info->files, transfer->num_files);
+ new_file_name = g_list_nth_data (source_info->new_names);
+ details = f (_("“%B” to “%s”"),
+ current_file,
+ new_file_name);
+
+ nautilus_progress_info_set_details (job->progress, details);
+
+ if (source_info->num_files != 0) {
+ nautilus_progress_info_set_progress (job->progress, transfer_info->num_files,
source_info->num_files);
+ }
+}
+
+
+static void
+rename_task_thread_func (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ RenameJob *job = task_data;
+ SourceInfo source_info;
+ GList *l;
+ GList *to_rename_files;
+ gchar *valid_new_name;
+ GList *valid_new_names;
+ GFile *file;
+ gboolean confirmed;
+ CommonJob *common;
+ int files_skipped;
+
+ common = (CommonJob *)job;
+
+ nautilus_progress_info_start (job->common.progress);
+
+ scan_sources (job->files,
+ &source_info,
+ common,
+ OP_KIND_RENAME,
+ FALSE);
+
+ if (job_aborted (common)) {
+ return;
+ }
+
+ files_skipped = 0;
+
+ for (l = job->source_files, i = 0;
+ l != NULL && !job_aborted ((CommonJob *)job);
+ l = l->next, i++) {
+ GFile *source_file;
+ g_autoptr (GFileInfo) info;
+
+ source_file = G_FILE (l->data);
+ info = g_file_query_info (source_file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE","
+ G_FILE_COPY_NOFOLLOW_SYMLINKS,
+ job->common.cancellable,
+ NULL);
+
+ if (info) {
+ archive_compressed_sizes[i] = g_file_info_get_size (info);
+ extract_job->total_compressed_size += archive_compressed_sizes[i];
+ }
+ }
+
+ for (l = job->files; l != NULL; l = l->next) {
+ file = l->data;
+ valid_new_name = can_rename_file (file, new_name)
+ if (valid_new_name) {
+ valid_new_names = g_list_prepend (valid_new_names,
+ valid_new_name);
+ to_rename_files = g_list_prepend (to_rename_files,
+ file);
+ } else {
+ files_skipped++;
+ transfer_add_file_to_count (file, common, transfer_info);
+ report_rename_progress (job, &source_info, &transfer_info);
+ }
+ }
+
+ if (files_skipped == g_list_length (job->files)) {
+ /* User has skipped all files, report user cancel */
+ job->user_cancel = TRUE;
+ }
+}
+
+void
+nautilus_file_operations_rename_file (GFile *file,
+ const gchar *new_name,
+ GtkWindow *parent_window,
+ NautilusRenameCallback done_callback,
+ gpointer done_callback_data)
+{
+ GTask *task;
+ RenameJob *job;
+
+ job = op_job_new (RenameJob, parent_window);
+ job->files = g_list_append (NULL, g_object_ref (file));
+ job->new_names = g_list_append (NULL, g_strdup (new_name));
+ job->done_callback = done_callback;
+ job->done_callback_data = done_callback_data;
+
+ inhibit_power_manager ((CommonJob *)job, _("Renaming File"));
+
+ if (!nautilus_file_undo_manager_is_operating () && try_trash) {
+ job->common.undo_info = nautilus_file_undo_info_rename_new ();
+ }
+
+ task = g_task_new (NULL, NULL, rename_task_done, job);
+ g_task_set_task_data (task, job, NULL);
+ g_task_run_in_thread (task, rename_task_thread_func);
+ g_object_unref (task);
+
+}
+
+void
+nautilus_file_operations_rename (GList *files,
+ GList *new_names,
+ GtkWindow *parent_window,
+ NautilusRenameCallback done_callback,
+ gpointer done_callback_data)
+{
+ GTask *task;
+ RenameJob *job;
+
+ job = op_job_new (RenameJob, parent_window);
+ job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL);
+ job->new_names = g_list_copy_deep (new_names, (GCopyFunc) g_strdup, NULL);
+ job->done_callback = done_callback;
+ job->done_callback_data = done_callback_data;
+
+ inhibit_power_manager ((CommonJob *)job, _("Renaming Files"));
+
+ if (!nautilus_file_undo_manager_is_operating () && try_trash) {
+ job->common.undo_info = nautilus_file_undo_info_batch_rename_new (g_list_length (new_files));
+ nautilus_file_undo_info_batch_rename_set_data_pre (NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME
(job->common.undo_info),
+ files);
+
+ nautilus_file_undo_info_batch_rename_set_data_post (NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME
(job->common.undo_info),
+ new_files);
+
+ nautilus_file_undo_manager_set_action (op->undo_info);
+ }
+
+ task = g_task_new (NULL, NULL, rename_task_done, job);
+ g_task_set_task_data (task, job, NULL);
+ g_task_run_in_thread (task, rename_task_thread_func);
+ g_object_unref (task);
+}
+
typedef struct {
@@ -2493,7 +2832,7 @@ prompt_empty_trash (GtkWindow *parent_window)
"the trash must be emptied. "
"All trashed items on the volume "
"will be permanently lost."));
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("Do _not Empty Trash"), GTK_RESPONSE_REJECT,
CANCEL, GTK_RESPONSE_CANCEL,
_("Empty _Trash"), GTK_RESPONSE_ACCEPT, NULL);
@@ -2560,7 +2899,7 @@ nautilus_file_operations_unmount_mount_full (GtkWindow *par
if (response == GTK_RESPONSE_ACCEPT) {
GTask *task;
EmptyTrashJob *job;
-
+
job = op_job_new (EmptyTrashJob, parent_window);
job->should_confirm = FALSE;
job->trash_dirs = get_trash_dirs_for_mount (mount);
@@ -2581,7 +2920,7 @@ nautilus_file_operations_unmount_mount_full (GtkWindow *par
return;
}
}
-
+
do_unmount (data);
}
@@ -2767,6 +3106,8 @@ get_scan_primary (OpKind kind)
return f (_("Error while moving files to trash."));
case OP_KIND_COMPRESS:
return f (_("Error while compressing files."));
+ case OP_KIND_RENAME:
+ return f (_("Error while renaming files."));
}
}
@@ -2894,9 +3235,10 @@ scan_dir (GFile *dir,
}
static void
-scan_file (GFile *file,
- SourceInfo *source_info,
- CommonJob *job)
+scan_file (GFile *file,
+ SourceInfo *source_info,
+ CommonJob *job,
+ gboolean recursive)
{
GFileInfo *info;
GError *error;
@@ -2969,22 +3311,25 @@ scan_file (GFile *file,
}
}
- while (!job_aborted (job) &&
- (dir = g_queue_pop_head (dirs)) != NULL) {
- scan_dir (dir, source_info, job, dirs);
- g_object_unref (dir);
- }
-
+ if (recursive)
+ {
+ while (!job_aborted (job) &&
+ (dir = g_queue_pop_head (dirs)) != NULL) {
+ scan_dir (dir, source_info, job, dirs);
+ g_object_unref (dir);
+ }
+ }
/* Free all from queue if we exited early */
g_queue_foreach (dirs, (GFunc)g_object_unref, NULL);
g_queue_free (dirs);
}
static void
-scan_sources (GList *files,
- SourceInfo *source_info,
- CommonJob *job,
- OpKind kind)
+scan_sources (GList *files,
+ SourceInfo *source_info,
+ CommonJob *job,
+ OpKind kind,
+ gboolean recursive)
{
GList *l;
GFile *file;
@@ -2999,7 +3344,8 @@ scan_sources (GList *files,
scan_file (file,
source_info,
- job);
+ job,
+ recursive);
}
/* Make sure we report the final count */
@@ -4850,7 +5196,7 @@ copy_files (CopyMoveJob *job,
point = NULL;
}
-
+
same_fs = FALSE;
if (dest_fs_id) {
same_fs = has_fs_id (src, dest_fs_id);
@@ -4939,7 +5285,8 @@ copy_task_thread_func (GTask *task,
scan_sources (job->files,
&source_info,
common,
- OP_KIND_COPY);
+ OP_KIND_COPY,
+ TRUE);
if (job_aborted (common)) {
goto aborted;
}
@@ -5186,12 +5533,12 @@ move_file_prepare (CopyMoveJob *move_job,
}
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,
@@ -5525,7 +5872,8 @@ move_task_thread_func (GTask *task,
scan_sources (fallback_files,
&source_info,
common,
- OP_KIND_MOVE);
+ OP_KIND_MOVE,
+ TRUE);
g_list_free (fallback_files);
@@ -7643,7 +7991,8 @@ compress_task_thread_func (GTask *task,
scan_sources (compress_job->source_files,
&source_info,
(CommonJob *)compress_job,
- OP_KIND_COMPRESS);
+ OP_KIND_COMPRESS,
+ TRUE);
compress_job->total_files = source_info.num_files;
compress_job->total_size = source_info.num_bytes;
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
index 31b782d..9c94eb2 100644
--- a/src/nautilus-file-operations.h
+++ b/src/nautilus-file-operations.h
@@ -42,6 +42,9 @@ typedef void (* NautilusOpCallback) (gboolean success,
typedef void (* NautilusDeleteCallback) (GHashTable *debuting_uris,
gboolean user_cancel,
gpointer callback_data);
+typedef void (* NautilusRenameCallback) (GHashTable *debuting_uris,
+ gboolean success,
+ gpointer callback_data);
typedef void (* NautilusMountCallback) (GVolume *volume,
gboolean success,
GObject *callback_data_object);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]