From 50f0b77e805d237ac7303dfbe1c1039edc43717d Mon Sep 17 00:00:00 2001 From: Alexandru Pandelea Date: Tue, 19 Jul 2016 16:40:51 +0300 Subject: Improve conflict handling Now there are also handled conflicts for files with different parents, case which occurs in search. file_name_changed manages the following case: if there is a file that generates a conflict, there is needed an extra check, because the conflicting file may also be in the batch rename. There was also a problem with navigating between conflicts. If in a search there were renamed two files with the same name, the arrows would always select the first one. --- src/nautilus-batch-rename-utilities.c | 131 +++++++++++++++++++++---- src/nautilus-batch-rename-utilities.h | 11 ++- src/nautilus-batch-rename.c | 176 ++++++++++++++++++++++++++++------ src/nautilus-batch-rename.h | 4 + 4 files changed, 278 insertions(+), 44 deletions(-) diff --git a/src/nautilus-batch-rename-utilities.c b/src/nautilus-batch-rename-utilities.c index 082a56e38..c8efc0863 100644 --- a/src/nautilus-batch-rename-utilities.c +++ b/src/nautilus-batch-rename-utilities.c @@ -13,12 +13,12 @@ typedef struct { NautilusFile *file; - gint *position; + gint *position; } CreateDateElem; typedef struct { NautilusBatchRename *dialog; - GHashTable *hash_table; + GHashTable *hash_table; } QueryData; static void cursor_callback (GObject *object, @@ -151,29 +151,95 @@ get_new_names_list (NautilusBatchRenameMode mode, return result; } -GList* -list_has_duplicates (NautilusDirectory *model, - GList *new_names, - GList *selection, - gboolean same_parent) +/* If there is a file that generates a conflict, there is a case where that isn't + * actually a conflict. This case is when the file that generates the conflict is + * in the selection and this file changed it's name */ +gboolean +file_name_changed (GList *selection, + GList *new_names, + GString *old_name, + gchar *parent_uri) { - /* handling conflicts for files in different directories is missing */ - if (!same_parent) - return NULL; + GList *l1, *l2; + NautilusFile *selection_file; + gchar *name1; + GString *new_name; + gchar *selection_parent_uri; + + l2 = new_names; + + for (l1 = selection; l1 != NULL; l1 = l1->next) { + selection_file = NAUTILUS_FILE (l1->data); + name1 = nautilus_file_get_name (selection_file); + + selection_parent_uri = nautilus_file_get_parent_uri (selection_file); - GList *directory_files, *l1, *l2, *result; + if (g_strcmp0 (name1, old_name->str) == 0) { + new_name = l2->data; + + /* if the name didn't change, then there's a conflict */ + if (g_string_equal (old_name, new_name) && + (parent_uri == NULL || g_strcmp0 (parent_uri, selection_parent_uri) == 0)) + return FALSE; + + + /* if this file exists and it changed it's name, then there's no + * conflict */ + return TRUE; + } + + l2 = l2->next; + } + + /* such a file doesn't exist so there actually is a conflict */ + return FALSE; +} + +static void +got_files_callback (NautilusDirectory *directory, GList *files, gpointer callback_data) +{ + check_conflict_for_file (NAUTILUS_BATCH_RENAME (callback_data), + directory, + files); +} + +GList* +list_has_duplicates (NautilusBatchRename *dialog, + NautilusDirectory *model, + GList *new_names, + GList *selection, + GList *parents_list, + gboolean same_parent) +{ + GList *directory_files, *l1, *l2, *l3, *result; NautilusFile *file1, *file2; GString *file_name1, *file_name2, *new_name; + NautilusDirectory *parent; - directory_files = nautilus_directory_get_file_list (model); + result = NULL; file_name1 = g_string_new (""); file_name2 = g_string_new (""); - result = NULL; + if (!same_parent) { + for (l1 = parents_list; l1 != NULL; l1 = l1->next) { + parent = nautilus_directory_get_by_uri (l1->data); + + nautilus_directory_call_when_ready (parent, + NAUTILUS_FILE_ATTRIBUTE_INFO, + TRUE, + got_files_callback, + dialog); + + } + return NULL; + } + + directory_files = nautilus_directory_get_file_list (model); + l3 = selection; for (l1 = new_names; l1 != NULL; l1 = l1->next) { - file1 = NAUTILUS_FILE (selection->data); + file1 = NAUTILUS_FILE (l3->data); new_name = l1->data; g_string_erase (file_name1, 0, -1); @@ -187,14 +253,15 @@ list_has_duplicates (NautilusDirectory *model, g_string_erase (file_name2, 0, -1); g_string_append (file_name2, nautilus_file_get_name (file2)); - if (g_string_equal (new_name, file_name2)) { + if (g_string_equal (new_name, file_name2) && + !file_name_changed (selection, new_names, new_name, NULL)) { result = g_list_prepend (result, strdup (new_name->str)); break; } } } - selection = selection->next; + l3 = l3->next; } g_string_free (file_name1, TRUE); @@ -524,4 +591,36 @@ selection_has_single_parent (GList *selection) g_string_free (parent_name2, TRUE); return TRUE; +} + +GList* +distinct_file_parents (GList *selection) +{ + GList *result, *l1, *l2; + NautilusFile *file; + gboolean exists; + gchar *parent_uri; + + result = NULL; + + for (l1 = selection; l1 != NULL; l1 = l1->next) { + exists = FALSE; + + file = NAUTILUS_FILE (l1->data); + parent_uri = nautilus_file_get_parent_uri (file); + + for (l2 = result; l2 != NULL; l2 = l2->next) + if (g_strcmp0 (parent_uri, l2->data) == 0) { + exists = TRUE; + break; + } + + if (!exists) { + result = g_list_prepend (result, parent_uri); + } else { + g_free (parent_uri); + } + } + + return result; } \ No newline at end of file diff --git a/src/nautilus-batch-rename-utilities.h b/src/nautilus-batch-rename-utilities.h index 967e34737..087098ff6 100644 --- a/src/nautilus-batch-rename-utilities.h +++ b/src/nautilus-batch-rename-utilities.h @@ -10,9 +10,11 @@ GList* get_new_names_list (NautilusBatchRenameMode mo gchar *entry_text, gchar *replace_text); -GList* list_has_duplicates (NautilusDirectory *model, +GList* list_has_duplicates (NautilusBatchRename *dialog, + NautilusDirectory *model, GList *names, GList *selection, + GList *parents_list, gboolean same_parent); GList* nautilus_batch_rename_sort (GList *selection, @@ -44,4 +46,11 @@ gboolean selection_has_single_parent (GList *selection); void string_free (gpointer mem); +GList* distinct_file_parents (GList *selection); + +gboolean file_name_changed (GList *selection, + GList *new_names, + GString *old_name, + gchar *parent_uri); + #endif /* NAUTILUS_BATCH_RENAME_UTILITIES_H */ \ No newline at end of file diff --git a/src/nautilus-batch-rename.c b/src/nautilus-batch-rename.c index 54025abe9..8bfaeb2fc 100644 --- a/src/nautilus-batch-rename.c +++ b/src/nautilus-batch-rename.c @@ -71,8 +71,14 @@ struct _NautilusBatchRename /* the number of the currently selected conflict */ gint selected_conflict; /* total conflicts number */ - gint conflcts_number; + gint conflicts_number; + + gint checked_parents; GList *duplicates; + GList *distinct_parents; + + GtkSizeGroup *size_group1; + GtkSizeGroup *size_group2; }; static void file_names_widget_entry_on_changed (NautilusBatchRename *dialog); @@ -219,9 +225,10 @@ listbox_header_func (GtkListBoxRow *row, } static GtkWidget* -create_row_for_label (const gchar *new_text, - const gchar *old_text, - gboolean show_separator) +create_row_for_label (NautilusBatchRename *dialog, + const gchar *new_text, + const gchar *old_text, + gboolean show_separator) { GtkWidget *row; GtkWidget *label_new; @@ -257,6 +264,9 @@ create_row_for_label (const gchar *new_text, gtk_label_set_ellipsize (GTK_LABEL (label_new), PANGO_ELLIPSIZE_END); gtk_label_set_ellipsize (GTK_LABEL (label_old), PANGO_ELLIPSIZE_END); + gtk_size_group_add_widget (dialog->size_group1, label_new); + gtk_size_group_add_widget (dialog->size_group2, label_old); + gtk_box_pack_end (GTK_BOX (box), label_new, TRUE, FALSE, 0); gtk_box_pack_end (GTK_BOX (box), icon, TRUE, FALSE, 0); gtk_box_pack_end (GTK_BOX (box), label_old, TRUE, FALSE, 0); @@ -288,6 +298,8 @@ fill_display_listbox (NautilusBatchRename *dialog, g_list_free (dialog->listbox_rows); dialog->listbox_rows = NULL; + dialog->size_group1 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + dialog->size_group2 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); /* add rows to a list so that they can be removed when the renaming * result changes */ @@ -295,7 +307,7 @@ fill_display_listbox (NautilusBatchRename *dialog, file = NAUTILUS_FILE (l2->data); new_name = l1->data; - row = create_row_for_label (new_name->str, nautilus_file_get_name (file), TRUE); + row = create_row_for_label (dialog, new_name->str, nautilus_file_get_name (file), TRUE); gtk_container_add (GTK_CONTAINER (dialog->conflict_listbox), row); @@ -304,15 +316,33 @@ fill_display_listbox (NautilusBatchRename *dialog, } } +static gboolean +file_has_conflict (NautilusBatchRename *dialog, + GString *new_name) +{ + GList *l; + + for (l = dialog->duplicates; l != NULL; l = l->next) { + if (g_strcmp0 (l->data, new_name->str) == 0) + return TRUE; + } + + return FALSE; +} + static void select_nth_conflict (NautilusBatchRename *dialog) { GList *l, *new_names, *l2; GString *file_name, *display_text, *new_name; - gint n; + gint n, nth_conflict; + gint selected_row; NautilusFile *file; - n = dialog->selected_conflict; + selected_row = 0; + + nth_conflict = dialog->selected_conflict; + n = nth_conflict; l = g_list_nth (dialog->duplicates, n); file_name = g_string_new (l->data); @@ -330,8 +360,13 @@ select_nth_conflict (NautilusBatchRename *dialog) /* g_strcmp0 is used for not selecting a file that doesn't change * it's name */ if (g_strcmp0 (new_name->str, nautilus_file_get_name (file)) && - g_string_equal (file_name, new_name)) + g_string_equal (file_name, new_name) && + nth_conflict == 0) break; + + if (file_has_conflict (dialog, new_name)) + nth_conflict--; + n++; l2 = l2->next; } @@ -358,7 +393,7 @@ move_next_conflict_down (NautilusBatchRename *dialog) if (dialog->selected_conflict == 1) gtk_widget_set_sensitive (dialog->conflict_up, TRUE); - if (dialog->selected_conflict == dialog->conflcts_number - 1) + if (dialog->selected_conflict == dialog->conflicts_number - 1) gtk_widget_set_sensitive (dialog->conflict_down, FALSE); select_nth_conflict (dialog); @@ -372,29 +407,16 @@ move_next_conflict_up (NautilusBatchRename *dialog) if (dialog->selected_conflict == 0) gtk_widget_set_sensitive (dialog->conflict_up, FALSE); - if (dialog->selected_conflict == dialog->conflcts_number - 2) + if (dialog->selected_conflict == dialog->conflicts_number - 2) gtk_widget_set_sensitive (dialog->conflict_down, TRUE); select_nth_conflict (dialog); } static void -file_names_widget_entry_on_changed (NautilusBatchRename *dialog) +update_conflicts (NautilusBatchRename *dialog, + GList *new_names) { - GList *new_names; - - if(dialog->selection == NULL) - return; - - if (dialog->duplicates != NULL) - g_list_free_full (dialog->duplicates, g_free); - - new_names = batch_rename_get_new_names(dialog); - dialog->duplicates = list_has_duplicates (dialog->model, - new_names, - dialog->selection, - dialog->same_parent); - /* Update listbox that shows the result of the renaming for each file */ fill_display_listbox (dialog, new_names); @@ -405,12 +427,16 @@ file_names_widget_entry_on_changed (NautilusBatchRename *dialog) gtk_widget_show (dialog->conflict_box); dialog->selected_conflict = 0; - dialog->conflcts_number = g_list_length (dialog->duplicates); + dialog->conflicts_number = g_list_length (dialog->duplicates); select_nth_conflict (dialog); gtk_widget_set_sensitive (dialog->conflict_up, FALSE); - gtk_widget_set_sensitive (dialog->conflict_down, TRUE); + + if (g_list_length (dialog->duplicates) == 1) + gtk_widget_set_sensitive (dialog->conflict_down, FALSE); + else + gtk_widget_set_sensitive (dialog->conflict_down, TRUE); } else { gtk_widget_hide (dialog->conflict_box); @@ -418,6 +444,96 @@ file_names_widget_entry_on_changed (NautilusBatchRename *dialog) if (dialog->duplicates == NULL && !gtk_widget_is_sensitive (dialog->rename_button)) gtk_widget_set_sensitive (dialog->rename_button, TRUE); } +} + + +void +check_conflict_for_file (NautilusBatchRename *dialog, + NautilusDirectory *directory, + GList *files) +{ + gchar *current_directory, *parent_uri, *name; + NautilusFile *file1, *file2; + GString *new_name, *file_name1, *file_name2; + GList *l1, *l2, *l3; + GList *new_names; + + new_names = batch_rename_get_new_names (dialog); + + file_name1 = g_string_new (""); + file_name2 = g_string_new (""); + + current_directory = nautilus_directory_get_uri (directory); + + for (l1 = dialog->selection, l2 = new_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next) { + file1 = NAUTILUS_FILE (l1->data); + + g_string_erase (file_name1, 0, -1); + name = nautilus_file_get_name (file1); + g_string_append (file_name1, name); + g_free (name); + + parent_uri = nautilus_file_get_parent_uri (file1); + + new_name = l2->data; + + /* check for duplicate only if the parent of the current file is + * the current directory and the name of the file has changed */ + if (g_strcmp0 (parent_uri, current_directory) == 0 && + !g_string_equal (new_name, file_name1)) + for (l3 = files; l3 != NULL; l3 = l3->next) { + file2 = NAUTILUS_FILE (l3->data); + + g_string_erase (file_name2, 0, -1); + name = nautilus_file_get_name (file2); + g_string_append (file_name2, name); + g_free (name); + + if (g_string_equal (new_name, file_name2) && + !file_name_changed (dialog->selection, new_names, new_name, parent_uri)) { + dialog->duplicates = g_list_prepend (dialog->duplicates, + strdup (new_name->str)); + break; + } + } + } + + /* check if this is the last call of the callback. Update + * the listbox with the conflicts if it is. */ + if (dialog->checked_parents == g_list_length (dialog->distinct_parents) - 1) { + dialog->duplicates = g_list_reverse (dialog->duplicates); + + update_conflicts (dialog, new_names); + } + + dialog->checked_parents++; + + g_free (current_directory); +} + +static void +file_names_widget_entry_on_changed (NautilusBatchRename *dialog) +{ + GList *new_names; + + if(dialog->selection == NULL) + return; + + if (dialog->duplicates != NULL) { + g_list_free_full (dialog->duplicates, g_free); + dialog->duplicates = NULL; + } + + new_names = batch_rename_get_new_names(dialog); + dialog->checked_parents = 0; + dialog->duplicates = list_has_duplicates (dialog, + dialog->model, + new_names, + dialog->selection, + dialog->distinct_parents, + dialog->same_parent); + + update_conflicts (dialog, new_names); g_list_free_full (new_names, string_free); } @@ -556,6 +672,8 @@ nautilus_batch_rename_finalize (GObject *object) if (dialog->create_date != NULL) g_hash_table_destroy (dialog->create_date); + g_list_free_full (dialog->distinct_parents, g_free); + G_OBJECT_CLASS (nautilus_batch_rename_parent_class)->finalize (object); } @@ -633,6 +751,10 @@ nautilus_batch_rename_new (GList *selection, NautilusDirectory *model, NautilusW nautilus_batch_rename_initialize_actions (dialog); dialog->same_parent = selection_has_single_parent (dialog->selection); + if (!dialog->same_parent) + dialog->distinct_parents = distinct_file_parents (dialog->selection); + else + dialog->distinct_parents = NULL; /* update display text */ file_names_widget_entry_on_changed (dialog); diff --git a/src/nautilus-batch-rename.h b/src/nautilus-batch-rename.h index 4aa36f3f2..219848976 100644 --- a/src/nautilus-batch-rename.h +++ b/src/nautilus-batch-rename.h @@ -36,6 +36,10 @@ GtkWidget* nautilus_batch_rename_new (GList *selecti void query_finished (NautilusBatchRename *dialog, GHashTable *hash_table); +void check_conflict_for_file (NautilusBatchRename *dialog, + NautilusDirectory *directory, + GList *files); + G_END_DECLS #endif \ No newline at end of file -- cgit v1.2.1