mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-06-30 23:46:35 +00:00
Compare commits
11 Commits
48b6653658
...
bd6f9a13ae
Author | SHA1 | Date | |
---|---|---|---|
|
bd6f9a13ae | ||
|
8f98ecbb44 | ||
|
04ca495429 | ||
|
7b460d79ae | ||
|
3cd96ff99c | ||
|
9c1c0bc032 | ||
|
c7c16d5ac2 | ||
|
4a10fbf791 | ||
|
20281558de | ||
|
9e5135057f | ||
|
b8881bb946 |
|
@ -422,9 +422,6 @@ static void
|
|||
begin_batch_rename (NautilusBatchRenameDialog *dialog,
|
||||
GList *new_names)
|
||||
{
|
||||
batch_rename_sort_lists_for_rename (&dialog->selection, &new_names, NULL, NULL, NULL, FALSE);
|
||||
|
||||
/* do the actual rename here */
|
||||
nautilus_file_batch_rename (dialog->selection, new_names, NULL, NULL);
|
||||
|
||||
gtk_widget_set_cursor (GTK_WIDGET (dialog->window), NULL);
|
||||
|
|
|
@ -142,124 +142,6 @@ batch_rename_replace (gchar *string,
|
|||
return new_string;
|
||||
}
|
||||
|
||||
void
|
||||
batch_rename_sort_lists_for_rename (GList **selection,
|
||||
GList **new_names,
|
||||
GList **old_names,
|
||||
GList **new_files,
|
||||
GList **old_files,
|
||||
gboolean is_undo_redo)
|
||||
{
|
||||
GList *new_names_list;
|
||||
GList *new_names_list2;
|
||||
GList *files;
|
||||
GList *files2;
|
||||
GList *old_names_list = NULL;
|
||||
GList *new_files_list = NULL;
|
||||
GList *old_files_list = NULL;
|
||||
GList *old_names_list2 = NULL;
|
||||
GList *new_files_list2 = NULL;
|
||||
GList *old_files_list2 = NULL;
|
||||
GString *new_file_name;
|
||||
GString *new_name;
|
||||
GString *old_name;
|
||||
GFile *new_file;
|
||||
GFile *old_file;
|
||||
NautilusFile *file;
|
||||
gboolean order_changed = TRUE;
|
||||
|
||||
/* in the following case:
|
||||
* file1 -> file2
|
||||
* file2 -> file3
|
||||
* file2 must be renamed first, so because of that, the list has to be reordered
|
||||
*/
|
||||
while (order_changed)
|
||||
{
|
||||
order_changed = FALSE;
|
||||
|
||||
if (is_undo_redo)
|
||||
{
|
||||
old_names_list = *old_names;
|
||||
new_files_list = *new_files;
|
||||
old_files_list = *old_files;
|
||||
}
|
||||
|
||||
for (new_names_list = *new_names, files = *selection;
|
||||
new_names_list != NULL && files != NULL;
|
||||
new_names_list = new_names_list->next, files = files->next)
|
||||
{
|
||||
g_autoptr (NautilusFile) parent = NULL;
|
||||
|
||||
new_file_name = new_names_list->data;
|
||||
parent = nautilus_file_get_parent (NAUTILUS_FILE (files->data));
|
||||
|
||||
if (is_undo_redo)
|
||||
{
|
||||
old_names_list2 = old_names_list;
|
||||
new_files_list2 = new_files_list;
|
||||
old_files_list2 = old_files_list;
|
||||
}
|
||||
|
||||
for (files2 = files, new_names_list2 = new_names_list;
|
||||
files2 != NULL && new_names_list2 != NULL;
|
||||
files2 = files2->next, new_names_list2 = new_names_list2->next)
|
||||
{
|
||||
const char *file_name;
|
||||
g_autoptr (NautilusFile) parent2 = NULL;
|
||||
|
||||
file_name = nautilus_file_get_name (NAUTILUS_FILE (files2->data));
|
||||
new_name = new_names_list2->data;
|
||||
|
||||
parent2 = nautilus_file_get_parent (NAUTILUS_FILE (files2->data));
|
||||
|
||||
if (files2 != files && g_strcmp0 (file_name, new_file_name->str) == 0 &&
|
||||
parent == parent2)
|
||||
{
|
||||
file = NAUTILUS_FILE (files2->data);
|
||||
|
||||
*selection = g_list_remove_link (*selection, files2);
|
||||
*new_names = g_list_remove_link (*new_names, new_names_list2);
|
||||
|
||||
*selection = g_list_prepend (*selection, file);
|
||||
*new_names = g_list_prepend (*new_names, new_name);
|
||||
|
||||
if (is_undo_redo)
|
||||
{
|
||||
old_name = old_names_list2->data;
|
||||
new_file = new_files_list2->data;
|
||||
old_file = old_files_list2->data;
|
||||
|
||||
*old_names = g_list_remove_link (*old_names, old_names_list2);
|
||||
*new_files = g_list_remove_link (*new_files, new_files_list2);
|
||||
*old_files = g_list_remove_link (*old_files, old_files_list2);
|
||||
|
||||
*old_names = g_list_prepend (*old_names, old_name);
|
||||
*new_files = g_list_prepend (*new_files, new_file);
|
||||
*old_files = g_list_prepend (*old_files, old_file);
|
||||
}
|
||||
|
||||
order_changed = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_undo_redo)
|
||||
{
|
||||
old_names_list2 = old_names_list2->next;
|
||||
new_files_list2 = new_files_list2->next;
|
||||
old_files_list2 = old_files_list2->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_undo_redo)
|
||||
{
|
||||
old_names_list = old_names_list->next;
|
||||
new_files_list = new_files_list->next;
|
||||
old_files_list = old_files_list->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This function changes the background color of the replaced part of the name */
|
||||
GString *
|
||||
batch_rename_replace_label_text (const char *label,
|
||||
|
|
|
@ -61,10 +61,3 @@ GString* batch_rename_replace_label_text (const char *label,
|
|||
const gchar *substr);
|
||||
|
||||
gchar* batch_rename_get_tag_text_representation (TagConstants tag_constants);
|
||||
|
||||
void batch_rename_sort_lists_for_rename (GList **selection,
|
||||
GList **new_names,
|
||||
GList **old_names,
|
||||
GList **new_files,
|
||||
GList **old_files,
|
||||
gboolean is_undo_redo);
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include "nautilus-file.h"
|
||||
#include "nautilus-file-undo-manager.h"
|
||||
#include "nautilus-batch-rename-dialog.h"
|
||||
#include "nautilus-batch-rename-utilities.h"
|
||||
#include "nautilus-scheme.h"
|
||||
#include "nautilus-tag-manager.h"
|
||||
|
||||
|
@ -1199,7 +1198,8 @@ batch_rename_redo_func (NautilusFileUndoInfo *info,
|
|||
{
|
||||
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
|
||||
|
||||
GList *l, *files;
|
||||
GList *l;
|
||||
g_autolist (NautilusFile) files = NULL;
|
||||
NautilusFile *file;
|
||||
GFile *old_file;
|
||||
|
||||
|
@ -1215,13 +1215,6 @@ batch_rename_redo_func (NautilusFileUndoInfo *info,
|
|||
|
||||
files = g_list_reverse (files);
|
||||
|
||||
batch_rename_sort_lists_for_rename (&files,
|
||||
&self->new_display_names,
|
||||
&self->old_display_names,
|
||||
&self->new_files,
|
||||
&self->old_files,
|
||||
TRUE);
|
||||
|
||||
nautilus_file_batch_rename (files, self->new_display_names, file_undo_info_operation_callback, self);
|
||||
}
|
||||
|
||||
|
@ -1232,7 +1225,8 @@ batch_rename_undo_func (NautilusFileUndoInfo *info,
|
|||
{
|
||||
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
|
||||
|
||||
GList *l, *files;
|
||||
GList *l;
|
||||
g_autolist (NautilusFile) files = NULL;
|
||||
NautilusFile *file;
|
||||
GFile *new_file;
|
||||
|
||||
|
@ -1248,13 +1242,6 @@ batch_rename_undo_func (NautilusFileUndoInfo *info,
|
|||
|
||||
files = g_list_reverse (files);
|
||||
|
||||
batch_rename_sort_lists_for_rename (&files,
|
||||
&self->old_display_names,
|
||||
&self->new_display_names,
|
||||
&self->old_files,
|
||||
&self->new_files,
|
||||
TRUE);
|
||||
|
||||
nautilus_file_batch_rename (files, self->old_display_names, file_undo_info_operation_callback, self);
|
||||
}
|
||||
|
||||
|
|
|
@ -1581,8 +1581,6 @@ nautilus_file_poll_for_media (NautilusFile *file)
|
|||
gboolean
|
||||
nautilus_file_can_rename (NautilusFile *file)
|
||||
{
|
||||
gboolean can_rename;
|
||||
|
||||
g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
|
||||
|
||||
/* Nonexistent files can't be renamed. */
|
||||
|
@ -1602,13 +1600,6 @@ nautilus_file_can_rename (NautilusFile *file)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
can_rename = TRUE;
|
||||
|
||||
if (!can_rename)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return file->details->can_rename;
|
||||
}
|
||||
|
||||
|
@ -2019,96 +2010,29 @@ nautilus_file_rename_handle_file_gone (NautilusFile *file,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
NautilusFileOperation *op;
|
||||
NautilusFile *file;
|
||||
} BatchRenameData;
|
||||
|
||||
static void
|
||||
batch_rename_get_info_callback (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer callback_data)
|
||||
{
|
||||
NautilusFileOperation *op;
|
||||
NautilusDirectory *directory;
|
||||
NautilusFile *existing_file;
|
||||
char *old_uri;
|
||||
char *new_uri;
|
||||
const char *new_name;
|
||||
GFileInfo *new_info;
|
||||
GError *error;
|
||||
BatchRenameData *data;
|
||||
|
||||
data = callback_data;
|
||||
|
||||
op = data->op;
|
||||
op->file = data->file;
|
||||
|
||||
error = NULL;
|
||||
new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
|
||||
if (new_info != NULL)
|
||||
{
|
||||
old_uri = nautilus_file_get_uri (op->file);
|
||||
|
||||
new_name = g_file_info_get_name (new_info);
|
||||
|
||||
directory = op->file->details->directory;
|
||||
|
||||
/* If there was another file by the same name in this
|
||||
* directory and it is not the same file that we are
|
||||
* renaming, mark it gone.
|
||||
*/
|
||||
existing_file = nautilus_directory_find_file_by_name (directory, new_name);
|
||||
if (existing_file != NULL && existing_file != op->file)
|
||||
{
|
||||
nautilus_file_mark_gone (existing_file);
|
||||
nautilus_file_changed (existing_file);
|
||||
}
|
||||
|
||||
update_info_and_name (op->file, new_info);
|
||||
|
||||
new_uri = nautilus_file_get_uri (op->file);
|
||||
nautilus_directory_moved (old_uri, new_uri);
|
||||
g_free (new_uri);
|
||||
g_free (old_uri);
|
||||
g_object_unref (new_info);
|
||||
}
|
||||
|
||||
op->renamed_files++;
|
||||
|
||||
if (op->files == NULL ||
|
||||
op->renamed_files + op->skipped_files == g_list_length (op->files))
|
||||
{
|
||||
nautilus_file_operation_complete (op, NULL, error);
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
real_batch_rename (GList *files,
|
||||
GList *new_names,
|
||||
NautilusFileOperationCallback callback,
|
||||
gpointer callback_data)
|
||||
{
|
||||
GList *l1, *l2, *old_files, *new_files;
|
||||
GList *l1, *l2;
|
||||
g_autolist (GFile) old_files = NULL, new_files = NULL;
|
||||
NautilusFileOperation *op;
|
||||
GFile *location;
|
||||
GString *new_name;
|
||||
NautilusFile *file;
|
||||
GError *error;
|
||||
GFile *new_file;
|
||||
BatchRenameData *data;
|
||||
|
||||
error = NULL;
|
||||
old_files = NULL;
|
||||
new_files = NULL;
|
||||
gsize len = 0;
|
||||
g_autoptr (GHashTable) staged_names = g_hash_table_new_full (NULL, NULL, NULL, g_free);
|
||||
g_autoptr (GHashTable) staged_files = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
g_autoptr (GHashTable) stub_files = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, g_object_unref);
|
||||
g_autoptr (GHashTable) unchained_files = g_hash_table_new_full (NULL, NULL,
|
||||
NULL, g_object_unref);
|
||||
g_autoptr (GHashTable) modified_files = g_hash_table_new (NULL, NULL);
|
||||
GHashTableIter hash_iter;
|
||||
GFile *key;
|
||||
gchar *value;
|
||||
GFile *fallback;
|
||||
g_autoptr (GError) skip_error = NULL;
|
||||
|
||||
/* Set up a batch renaming operation. */
|
||||
op = nautilus_file_operation_new (files->data, callback, callback_data);
|
||||
|
@ -2116,88 +2040,239 @@ real_batch_rename (GList *files,
|
|||
op->renamed_files = 0;
|
||||
op->skipped_files = 0;
|
||||
|
||||
for (l1 = files->next; l1 != NULL; l1 = l1->next)
|
||||
{
|
||||
file = NAUTILUS_FILE (l1->data);
|
||||
|
||||
file->details->operations_in_progress = g_list_prepend (file->details->operations_in_progress,
|
||||
op);
|
||||
}
|
||||
|
||||
for (l1 = files, l2 = new_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next)
|
||||
{
|
||||
const char *new_file_name;
|
||||
file = NAUTILUS_FILE (l1->data);
|
||||
new_name = l2->data;
|
||||
NautilusFile *file = NAUTILUS_FILE (l1->data);
|
||||
GString *new_name = l2->data;
|
||||
GFile *location = nautilus_file_get_location (file);
|
||||
const char *new_file_name = nautilus_file_can_rename_file (file,
|
||||
new_name->str,
|
||||
NULL, NULL);
|
||||
|
||||
location = nautilus_file_get_location (file);
|
||||
|
||||
new_file_name = nautilus_file_can_rename_file (file,
|
||||
new_name->str,
|
||||
callback,
|
||||
callback_data);
|
||||
len++;
|
||||
file->details->operations_in_progress = g_list_prepend (file->details->operations_in_progress,
|
||||
op);
|
||||
|
||||
if (new_file_name == NULL)
|
||||
{
|
||||
op->skipped_files++;
|
||||
name_is (file, new_name->str) ? op->renamed_files++ : op->skipped_files++;
|
||||
|
||||
g_hash_table_insert (stub_files, g_strdup (file->details->name), location);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
g_assert (G_IS_FILE (location));
|
||||
g_assert (g_hash_table_insert (staged_names, location, g_strdup (new_file_name)));
|
||||
g_assert (g_hash_table_insert (staged_files, g_strdup (file->details->name), location));
|
||||
}
|
||||
|
||||
/* Do the renaming. */
|
||||
new_file = g_file_set_display_name (location,
|
||||
new_file_name,
|
||||
op->cancellable,
|
||||
&error);
|
||||
g_hash_table_iter_init (&hash_iter, staged_names);
|
||||
g_hash_table_iter_next (&hash_iter, (gpointer *) &key, (gpointer *) &value);
|
||||
while (g_hash_table_size (staged_names) > 0)
|
||||
{
|
||||
GFile *chain_file = key;
|
||||
GFile *conflicting_staged_file = g_hash_table_lookup (staged_files, value);
|
||||
gboolean is_chain_start = TRUE;
|
||||
|
||||
data = g_new0 (BatchRenameData, 1);
|
||||
data->op = op;
|
||||
data->file = file;
|
||||
|
||||
g_file_query_info_async (new_file,
|
||||
NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
|
||||
0,
|
||||
G_PRIORITY_DEFAULT,
|
||||
op->cancellable,
|
||||
batch_rename_get_info_callback,
|
||||
data);
|
||||
|
||||
if (error != NULL)
|
||||
if (conflicting_staged_file != NULL)
|
||||
{
|
||||
g_warning ("Batch rename for file \"%s\" failed", nautilus_file_get_name (file));
|
||||
g_error_free (error);
|
||||
error = NULL;
|
||||
g_autoptr (GFile) conflicting_staged_file_parent = g_file_get_parent (conflicting_staged_file);
|
||||
|
||||
op->skipped_files++;
|
||||
is_chain_start = !g_file_has_parent (chain_file, conflicting_staged_file_parent);
|
||||
}
|
||||
|
||||
if (is_chain_start)
|
||||
{
|
||||
/* Process the chain leading to this file */
|
||||
gboolean skip_files = FALSE;
|
||||
|
||||
while (chain_file != NULL)
|
||||
{
|
||||
g_autofree gchar *chain_file_old_name = g_file_get_basename (chain_file);
|
||||
gchar *chain_file_new_name = g_hash_table_lookup (staged_names, chain_file);
|
||||
GFile *conflicting_stub_file = g_hash_table_lookup (stub_files,
|
||||
chain_file_new_name);
|
||||
|
||||
if (!skip_files && conflicting_stub_file != NULL)
|
||||
{
|
||||
g_autoptr (GFile) conflicting_stub_file_parent = g_file_get_parent (conflicting_stub_file);
|
||||
|
||||
skip_files = g_file_has_parent (chain_file, conflicting_stub_file_parent);
|
||||
}
|
||||
|
||||
/* Rename and skip the chain on error */
|
||||
if (!skip_files)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
/* Do the renaming. */
|
||||
g_autoptr (GFile) renamed_file = g_file_set_display_name (chain_file,
|
||||
chain_file_new_name,
|
||||
op->cancellable,
|
||||
&error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Batch rename for file \"%s\" failed: %s",
|
||||
chain_file_old_name, error->message);
|
||||
|
||||
/* We need to skip the rest of the files in the chain. */
|
||||
skip_files = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
op->renamed_files++;
|
||||
|
||||
if (g_hash_table_steal_extended (unchained_files, chain_file,
|
||||
NULL, (gpointer *) &fallback))
|
||||
{
|
||||
g_hash_table_add (modified_files, fallback);
|
||||
old_files = g_list_append (old_files, fallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_add (modified_files, chain_file);
|
||||
old_files = g_list_append (old_files, g_object_ref (chain_file));
|
||||
}
|
||||
|
||||
g_hash_table_add (modified_files, renamed_file);
|
||||
new_files = g_list_append (new_files, g_steal_pointer (&renamed_file));
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_remove (staged_names, chain_file);
|
||||
g_hash_table_remove (staged_files, chain_file_old_name);
|
||||
|
||||
if (skip_files)
|
||||
{
|
||||
op->skipped_files++;
|
||||
|
||||
g_hash_table_insert (stub_files, g_strdup (chain_file_old_name),
|
||||
g_steal_pointer (&chain_file));
|
||||
}
|
||||
|
||||
g_set_object (&chain_file, g_hash_table_lookup (staged_files, chain_file_old_name));
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, staged_names);
|
||||
g_hash_table_iter_next (&hash_iter, (gpointer *) &key, (gpointer *) &value);
|
||||
}
|
||||
else
|
||||
{
|
||||
old_files = g_list_append (old_files, location);
|
||||
new_files = g_list_append (new_files, new_file);
|
||||
/* Iterate to find out if it's a chain or a cycle. */
|
||||
GFile *iter_start_file = NULL;
|
||||
|
||||
while (chain_file != NULL)
|
||||
{
|
||||
gchar *chain_file_new_name = g_hash_table_lookup (staged_names, chain_file);
|
||||
GFile *prev_chain_file = g_hash_table_lookup (staged_files, chain_file_new_name);
|
||||
gboolean reached_chain_start = TRUE;
|
||||
|
||||
if (prev_chain_file != NULL)
|
||||
{
|
||||
g_autoptr (GFile) prev_chain_file_parent = g_file_get_parent (prev_chain_file);
|
||||
|
||||
reached_chain_start = !g_file_has_parent (chain_file, prev_chain_file_parent);
|
||||
}
|
||||
|
||||
if (reached_chain_start)
|
||||
{
|
||||
key = chain_file;
|
||||
value = chain_file_new_name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (iter_start_file == chain_file)
|
||||
{
|
||||
/* We found a cycle, break it with a temporary name. */
|
||||
g_autofree gchar *random_string = g_uuid_string_random ();
|
||||
gchar *prev_chain_file_old_name = chain_file_new_name;
|
||||
g_autofree gchar *prev_chain_file_new_name = NULL;
|
||||
GFile *renamed_file = g_file_set_display_name (prev_chain_file,
|
||||
random_string,
|
||||
op->cancellable,
|
||||
NULL);
|
||||
|
||||
g_hash_table_remove (staged_files, prev_chain_file_old_name);
|
||||
g_hash_table_steal_extended (staged_names, prev_chain_file,
|
||||
NULL, (gpointer *) &prev_chain_file_new_name);
|
||||
|
||||
if (renamed_file != NULL)
|
||||
{
|
||||
g_hash_table_insert (staged_files, g_strdup (random_string), renamed_file);
|
||||
g_hash_table_insert (staged_names,
|
||||
renamed_file,
|
||||
g_steal_pointer (&prev_chain_file_new_name));
|
||||
|
||||
g_hash_table_insert (unchained_files, renamed_file, prev_chain_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unlikely to be a name conflict, stub the file. */
|
||||
op->skipped_files++;
|
||||
|
||||
g_hash_table_insert (stub_files,
|
||||
g_strdup (prev_chain_file_old_name), prev_chain_file);
|
||||
}
|
||||
|
||||
key = chain_file;
|
||||
value = chain_file_new_name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (iter_start_file == NULL)
|
||||
{
|
||||
iter_start_file = chain_file;
|
||||
}
|
||||
|
||||
chain_file = prev_chain_file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to rename back the files that were renamed to temporary names
|
||||
* but weren't restored. Don't handle any errors though, it's likely
|
||||
* futile.
|
||||
*/
|
||||
g_hash_table_iter_init (&hash_iter, unchained_files);
|
||||
while (g_hash_table_iter_next (&hash_iter, (gpointer *) &key, (gpointer *) &fallback))
|
||||
{
|
||||
g_file_move (key, fallback, G_FILE_COPY_NONE, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, modified_files);
|
||||
while (g_hash_table_iter_next (&hash_iter, (gpointer *) &key, NULL))
|
||||
{
|
||||
NautilusFile *file = nautilus_file_get_existing (key);
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell the undo manager a batch rename is taking place if at least
|
||||
* a file has been renamed*/
|
||||
if (!nautilus_file_undo_manager_is_operating () && op->skipped_files != g_list_length (files))
|
||||
if (!nautilus_file_undo_manager_is_operating () && op->skipped_files != len)
|
||||
{
|
||||
op->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 (op->undo_info),
|
||||
old_files);
|
||||
g_steal_pointer (&old_files));
|
||||
|
||||
nautilus_file_undo_info_batch_rename_set_data_post (NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (op->undo_info),
|
||||
new_files);
|
||||
g_steal_pointer (&new_files));
|
||||
|
||||
nautilus_file_undo_manager_set_action (op->undo_info);
|
||||
}
|
||||
|
||||
if (op->skipped_files == g_list_length (files))
|
||||
if (op->skipped_files > 1)
|
||||
{
|
||||
nautilus_file_operation_complete (op, NULL, error);
|
||||
skip_error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Skipped %d file(s)", op->skipped_files);
|
||||
}
|
||||
|
||||
nautilus_file_operation_complete (op, NULL, skip_error);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <nautilus-file.h>
|
||||
#include <nautilus-file-private.h>
|
||||
#include <nautilus-file-utilities.h>
|
||||
#include <test-utilities.h>
|
||||
|
||||
|
||||
static void
|
||||
|
@ -87,10 +88,167 @@ test_file_sort_with_self (void)
|
|||
g_assert_cmpint (order, ==, 0);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gsize len;
|
||||
GStrv expected_names;
|
||||
GStrv expected_content;
|
||||
gboolean *success;
|
||||
} NautilusFileBatchRenameTestData;
|
||||
|
||||
static void
|
||||
batch_rename_callback (NautilusFile *file,
|
||||
GFile *result_location,
|
||||
GError *error,
|
||||
gpointer callback_data)
|
||||
{
|
||||
NautilusFileBatchRenameTestData *data = callback_data;
|
||||
g_autoptr (GFile) root = g_file_new_for_path (test_get_tmp_dir ());
|
||||
g_autoptr (GStrvBuilder) name_builder = g_strv_builder_new ();
|
||||
g_autoptr (GStrvBuilder) content_builder = g_strv_builder_new ();
|
||||
g_auto (GStrv) result_names = NULL, result_content = NULL;
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpint (data->len, ==, g_strv_length (data->expected_names));
|
||||
g_assert_cmpint (data->len, ==, g_strv_length (data->expected_content));
|
||||
|
||||
for (guint i = 0; i < data->len; i++)
|
||||
{
|
||||
g_autoptr (GFile) location = g_file_get_child (root, data->expected_names[i]);
|
||||
g_autoptr (GFileInfo) info = g_file_query_info (location, NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
|
||||
G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
g_autoptr (GFileInputStream) stream = g_file_read (location, NULL, NULL);
|
||||
gchar content[1024];
|
||||
|
||||
g_assert_nonnull (stream);
|
||||
g_assert_true (g_input_stream_read_all (G_INPUT_STREAM (stream), content, sizeof (content),
|
||||
NULL, NULL, NULL));
|
||||
g_assert_true (g_input_stream_close (G_INPUT_STREAM (stream), NULL, NULL));
|
||||
|
||||
g_strv_builder_add (name_builder, g_file_info_get_display_name (info));
|
||||
g_strv_builder_add (content_builder, content);
|
||||
}
|
||||
|
||||
result_names = g_strv_builder_end (name_builder);
|
||||
result_content = g_strv_builder_end (content_builder);
|
||||
|
||||
for (guint i = 0; i < data->len; i++)
|
||||
{
|
||||
g_assert_cmpstr (result_names[i], ==, data->expected_names[i]);
|
||||
g_assert_cmpstr (result_content[i], ==, data->expected_content[i]);
|
||||
}
|
||||
|
||||
*data->success = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
batch_rename_test (const GStrv original_names,
|
||||
const GStrv expected_names)
|
||||
{
|
||||
g_autoptr (GFile) root = g_file_new_for_path (test_get_tmp_dir ());
|
||||
g_autolist (NautilusFile) files = NULL;
|
||||
g_autolist (GString) new_names = NULL;
|
||||
const gsize len = g_strv_length (expected_names);
|
||||
gboolean success = FALSE;
|
||||
NautilusFileBatchRenameTestData data = { len, expected_names, original_names, &success };
|
||||
|
||||
create_hierarchy_from_template (original_names, "");
|
||||
|
||||
for (gint i = len - 1; i >= 0; i--)
|
||||
{
|
||||
g_autoptr (GFile) location = g_file_get_child (root, original_names[i]);
|
||||
NautilusFile *file = nautilus_file_get (location);
|
||||
GString *new_name = g_string_new (expected_names[i]);
|
||||
|
||||
files = g_list_prepend (files, file);
|
||||
new_names = g_list_prepend (new_names, new_name);
|
||||
}
|
||||
|
||||
nautilus_file_batch_rename (files, new_names, batch_rename_callback, &data);
|
||||
|
||||
g_assert_true (success);
|
||||
|
||||
/* Test undo by changing the expected names */
|
||||
data.expected_names = original_names;
|
||||
success = FALSE;
|
||||
|
||||
test_operation_undo ();
|
||||
|
||||
batch_rename_callback (NULL, NULL, NULL, &data);
|
||||
|
||||
g_assert_true (success);
|
||||
|
||||
test_clear_tmp_dir ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_file_batch_rename_cycles (void)
|
||||
{
|
||||
char *test_cases[][2][10] =
|
||||
{
|
||||
/* Small cycle */
|
||||
{{"file_1", "file_2", NULL},
|
||||
{"file_2", "file_1", NULL}},
|
||||
/* Medium cycle */
|
||||
{{"file_1", "file_2", "file_3", "file_4", "file_5", "file_6", "file_7", "file_8", "file_9", NULL},
|
||||
{"file_9", "file_1", "file_2", "file_3", "file_4", "file_5", "file_6", "file_7", "file_8", NULL}},
|
||||
/* Multi-cycle */
|
||||
{{"file_1", "file_2", "file_3", "file_4", "file_5", "file_6", "file_7", "file_8", NULL},
|
||||
{"file_8", "file_3", "file_4", "file_5", "file_6", "file_7", "file_2", "file_1", NULL}},
|
||||
};
|
||||
|
||||
g_test_bug ("https://gitlab.gnome.org/GNOME/nautilus/-/issues/1443");
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (test_cases); i++)
|
||||
{
|
||||
batch_rename_test (test_cases[i][0], test_cases[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_file_batch_rename_chains (void)
|
||||
{
|
||||
char *test_cases[][2][10] =
|
||||
{
|
||||
/* Medium chain */
|
||||
{{"file_1", "file_2", "file_3", "file_4", "file_5", "file_6", "file_7", "file_8", "file_9", NULL},
|
||||
{"file_2", "file_3", "file_4", "file_5", "file_6", "file_7", "file_8", "file_9", "file_10", NULL}},
|
||||
};
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (test_cases); i++)
|
||||
{
|
||||
batch_rename_test (test_cases[i][0], test_cases[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_file_batch_rename_replace (void)
|
||||
{
|
||||
char *test_cases[][2][10] =
|
||||
{
|
||||
/* File Extension replacement */
|
||||
{{
|
||||
"file_1.jpg", "file_2.jpeg", "file_3.gif", "file_4.png", "file_5.webm",
|
||||
"file_6.avif", "file_7.jxl", "file_8.jpeg", "file_9.bmp", NULL
|
||||
},
|
||||
{
|
||||
"file_1.jpg", "file_2.jpg", "file_3.gif", "file_4.png", "file_5.webm",
|
||||
"file_6.avif", "file_7.jxl", "file_8.jpg", "file_9.bmp", NULL
|
||||
}},
|
||||
};
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (test_cases); i++)
|
||||
{
|
||||
batch_rename_test (test_cases[i][0], test_cases[i][1]);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_autoptr (NautilusFileUndoManager) undo_manager = nautilus_file_undo_manager_new ();
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_set_nonfatal_assertions ();
|
||||
nautilus_ensure_extension_points ();
|
||||
|
@ -107,6 +265,12 @@ main (int argc,
|
|||
test_file_sort_order);
|
||||
g_test_add_func ("/file-sort/with-self",
|
||||
test_file_sort_with_self);
|
||||
g_test_add_func ("/file-batch-rename/cycles",
|
||||
test_file_batch_rename_cycles);
|
||||
g_test_add_func ("/file-batch-rename/chains",
|
||||
test_file_batch_rename_chains);
|
||||
g_test_add_func ("/file-batch-rename/replace",
|
||||
test_file_batch_rename_replace);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ empty_directory_by_prefix (GFile *parent,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
create_hierarchy_from_template (const GStrv hier,
|
||||
const gchar *substitution)
|
||||
{
|
||||
|
@ -82,6 +82,10 @@ create_hierarchy_from_template (const GStrv hier,
|
|||
{
|
||||
g_autoptr (GFileOutputStream) stream = g_file_create (file, G_FILE_CREATE_NONE,
|
||||
NULL, NULL);
|
||||
g_autofree gchar *name = g_file_get_basename (file);
|
||||
|
||||
g_output_stream_write_all (G_OUTPUT_STREAM (stream), name, strlen (name) + 1,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ void test_clear_tmp_dir (void);
|
|||
void empty_directory_by_prefix (GFile *parent,
|
||||
gchar *prefix);
|
||||
|
||||
void create_hierarchy_from_template (const GStrv hier,
|
||||
const gchar *substitution);
|
||||
|
||||
void create_search_file_hierarchy (gchar *search_engine);
|
||||
void delete_search_file_hierarchy (gchar *search_engine);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user