[nautilus/wip/alexpandelea/batchRename] Improve conflict handling



commit 50f0b77e805d237ac7303dfbe1c1039edc43717d
Author: Alexandru Pandelea <alexandru pandelea gmail com>
Date:   Tue Jul 19 16:40:51 2016 +0300

    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 082a56e..c8efc08 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 967e347..087098f 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 54025ab..8bfaeb2 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 4aa36f3..2198489 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]