[nautilus/wip/alexpandelea/batchRename] Handle conflicts



commit 1186d98fce1250dfbb58715bd202f1c2c16c67e6
Author: Alexandru Pandelea <alexandru pandelea gmail com>
Date:   Sat Jun 11 12:06:14 2016 +0300

    Handle conflicts
    
    If there are any conflicts, instead of the usual label there is used
    an expander with a scrollable listbox as child. Inside the listbox are
    displayed all the conflicts.

 src/nautilus-batch-rename-utilities.c            |   40 +++++
 src/nautilus-batch-rename-utilities.h            |    7 +
 src/nautilus-batch-rename.c                      |  194 +++++++++++++++++++++-
 src/nautilus-files-view.c                        |   14 ++
 src/nautilus-files-view.h                        |    3 +
 src/resources/ui/nautilus-batch-rename-dialog.ui |   52 ++++++-
 6 files changed, 302 insertions(+), 8 deletions(-)
---
diff --git a/src/nautilus-batch-rename-utilities.c b/src/nautilus-batch-rename-utilities.c
index 85a6ae1..2572807 100644
--- a/src/nautilus-batch-rename-utilities.c
+++ b/src/nautilus-batch-rename-utilities.c
@@ -1,5 +1,6 @@
 #include "nautilus-batch-rename.h"
 #include "nautilus-batch-rename-utilities.h"
+#include "nautilus-files-view.h"
 
 #include <glib.h>
 #include <gtk/gtk.h>
@@ -160,4 +161,43 @@ get_new_display_name (NautilusBatchRenameModes    mode,
         result = get_new_name (mode, file_name, entry_text, replace_text);
 
         return result;
+}
+
+GList*
+list_has_duplicates (NautilusFilesView *view,
+                     GList             *new_names,
+                     GList             *old_names)
+{
+        GList *l1, *l2;
+        GList *result;
+        NautilusFile *file;
+        gchar *file_name;
+
+        result = NULL;
+
+        for (l1 = new_names, l2 = old_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next) {
+                file = NAUTILUS_FILE (l2->data);
+                file_name = strdup (nautilus_file_get_name (file));
+
+                if (strcmp (l1->data, file_name) != 0 && file_with_name_exists (view, l1->data) == TRUE) {
+                        result = g_list_prepend (result,
+                                                 (gpointer) (l1->data));
+                }
+
+                g_free (file_name);
+        }
+        return result;
+}
+
+gchar*
+concat(gchar *s1, gchar *s2)
+{
+    gchar *result;
+
+    result = malloc (strlen(s1) + strlen(s2) + 1);
+
+    memcpy(result, s1, strlen(s1));
+    memcpy(result + strlen(s1), s2, strlen(s2) + 1);
+
+    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 68aa1ad..33e916f 100644
--- a/src/nautilus-batch-rename-utilities.h
+++ b/src/nautilus-batch-rename-utilities.h
@@ -19,4 +19,11 @@ gchar* get_new_display_name     (NautilusBatchRenameModes    mode,
                                  gchar                       *entry_text,
                                  gchar                       *replace_text);
 
+GList* list_has_duplicates      (NautilusFilesView           *view,
+                                 GList                       *names,
+                                 GList                       *old_names);
+
+gchar* concat                   (gchar                       *s1,
+                                 gchar                       *s2);
+
 #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 14994e6..01912fc 100644
--- a/src/nautilus-batch-rename.c
+++ b/src/nautilus-batch-rename.c
@@ -37,21 +37,27 @@ struct _NautilusBatchRename
 
         GtkWidget               *add_text_options;
         GtkWidget               *cancel_button;
+        GtkWidget               *conflict_listbox;
         GtkWidget               *error_label;
+        GtkWidget               *expander;
         GtkWidget               *name_entry;
         GtkWidget               *rename_button;
         GtkWidget               *rename_modes;
         GtkWidget               *find_label;
         GtkWidget               *left_stack;
+        GtkWidget               *label_stack;
         GtkWidget               *right_stack;
         GtkWidget               *replace_entry;
         GtkWidget               *replace_label;
         GtkWidget               *replace_box;
 
+        GList                   *listbox_rows;//adauga aici rows de la listbox pt a fi sterse
 
         GList                   *selection;
         NautilusBatchRenameModes mode;
         NautilusFilesView       *view;
+
+        GtkWidget               *expander_label;
 };
 
 static void     batch_rename_dialog_on_closed           (GtkDialog              *dialog);
@@ -188,17 +194,171 @@ batch_rename_mode_changed (GtkComboBoxText *widget,
 }
 
 static void
+activate_expander (GtkExpander *expander,
+                   NautilusBatchRename *dialog)
+{
+        GValue width = G_VALUE_INIT;
+
+        g_value_init (&width, G_TYPE_INT);
+
+        if (gtk_expander_get_expanded (GTK_EXPANDER (expander))) {
+
+                g_value_set_int (&width, 8);
+                gtk_container_child_set_property (GTK_CONTAINER (dialog->grid), dialog->label_stack, 
"width",&width);
+        } else {
+
+                g_value_set_int (&width, 5);
+                gtk_container_child_set_property (GTK_CONTAINER (dialog->grid), dialog->label_stack, 
"width",&width);
+        }
+}
+
+static void
+listbox_header_func (GtkListBoxRow         *row,
+                     GtkListBoxRow         *before,
+                     NautilusBatchRename   *dialog)
+{
+  gboolean show_separator;
+
+  show_separator = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "show-separator"));
+
+  if (show_separator)
+    {
+      GtkWidget *separator;
+
+      separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+      gtk_widget_show (separator);
+
+      gtk_list_box_row_set_header (row, separator);
+    }
+}
+
+static GtkWidget*
+create_row_for_label (const gchar *text,
+                      gboolean     show_separator)
+{
+        GtkWidget *row;
+        GtkWidget *label;
+
+        row = gtk_list_box_row_new ();
+
+        g_object_set_data (G_OBJECT (row), "show-separator", GINT_TO_POINTER (show_separator));
+
+        label = g_object_new (GTK_TYPE_LABEL,
+                              "label", text,
+                              "hexpand", TRUE,
+                              "xalign", 0.0,
+                              "margin-start", 6,
+                              NULL);
+
+        gtk_list_box_row_set_selectable (GTK_LIST_BOX_ROW (row), FALSE);
+
+        gtk_container_add (GTK_CONTAINER (row), label);
+        gtk_widget_show_all (row);
+
+        return row;
+}
+
+static void
+fill_conflict_listbox (NautilusBatchRename *dialog,
+                       GList               *conflict_list)
+{
+        GtkWidget *row;
+        GList *l;
+
+        /* clear rows from listbox (if there are any) */
+        if (dialog->listbox_rows != NULL)
+                for (l = dialog->listbox_rows; l != NULL; l = l->next) {
+                        gtk_container_remove (GTK_CONTAINER (dialog->conflict_listbox),
+                                              GTK_WIDGET (l->data));
+                }
+
+        g_list_free (dialog->listbox_rows);
+        dialog->listbox_rows = NULL;
+
+        row = create_row_for_label ("These files already exist:", FALSE);
+
+        gtk_container_add (GTK_CONTAINER (dialog->conflict_listbox), row);
+
+        /* add rows to a list so that they can be removed when there appears
+         * a new conflict */
+        dialog->listbox_rows = g_list_prepend (dialog->listbox_rows,
+                                                 (gpointer) row);
+
+        for (l = conflict_list; l != NULL; l = l->next) {
+
+                row = create_row_for_label ((gchar*) l->data, l == conflict_list);
+
+                gtk_container_add (GTK_CONTAINER (dialog->conflict_listbox), row);
+
+                dialog->listbox_rows = g_list_prepend (dialog->listbox_rows,
+                                                 (gpointer) row);
+        }
+}
+
+static void
 file_names_widget_entry_on_changed (NautilusBatchRename *dialog)
 {
         gchar *entry_text;
         gchar *replace_text;
         gchar *file_name;
+        GList *new_names;
+        GList *duplicates;
         gchar *display_text = NULL;
         NautilusFile *file;
+        GValue width = G_VALUE_INIT;
 
         if(dialog->selection == NULL)
                 return;
 
+        new_names = batch_rename_get_new_names(dialog);
+        duplicates = list_has_duplicates (dialog->view, new_names, dialog->selection);
+
+        /* check if there are name conflicts and display them if they exist */
+        if (duplicates != NULL && gtk_widget_is_sensitive (dialog->rename_button)) {
+                gtk_widget_set_sensitive (dialog->rename_button, FALSE);
+
+                gtk_expander_set_expanded (GTK_EXPANDER (dialog->expander), FALSE);
+                gtk_stack_set_visible_child (GTK_STACK (dialog->label_stack), GTK_WIDGET (dialog->expander));
+
+                /* check if there is more than one conflict */
+                if (duplicates->next != NULL)
+                        gtk_expander_set_label (GTK_EXPANDER (dialog->expander),
+                                                "Multiple file conflicts");
+                else {
+                        file_name = concat ("File conflict: ", duplicates->data);
+
+                        gtk_label_set_label (GTK_LABEL (dialog->expander_label), file_name);
+
+                        gtk_expander_set_label_widget (GTK_EXPANDER (dialog->expander),
+                                                       dialog->expander_label);
+
+                        gtk_widget_show (dialog->expander_label);
+
+                        g_free (file_name);
+                }
+
+                /* add name conflicts to the listbox */
+                fill_conflict_listbox (dialog, duplicates);
+
+                return;
+        }
+        else
+                /* re-enable the rename button if there are no more name conflicts */
+                if (duplicates == NULL && !gtk_widget_is_sensitive (dialog->rename_button)) {
+                        gtk_expander_set_expanded (GTK_EXPANDER (dialog->expander), FALSE);
+
+                        gtk_widget_set_sensitive (dialog->rename_button, TRUE);
+
+                        gtk_stack_set_visible_child (GTK_STACK (dialog->label_stack), GTK_WIDGET 
(dialog->error_label));
+
+                        g_value_init (&width, G_TYPE_INT);
+                        g_value_set_int (&width, 8);
+                        gtk_container_child_set_property (GTK_CONTAINER (dialog->grid), dialog->label_stack, 
"width",&width);
+
+
+                }
+
+        /* Update label that shows an example of the renaming result */
         file = NAUTILUS_FILE (dialog->selection->data);
 
         file_name = g_strdup (nautilus_file_get_name (file));
@@ -206,16 +366,20 @@ file_names_widget_entry_on_changed (NautilusBatchRename *dialog)
         replace_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->replace_entry)));
 
         if (entry_text == NULL ) {
-              gtk_label_set_label (GTK_LABEL (dialog->error_label), file_name);
-              g_free (file_name);
 
-              return;
+                gtk_label_set_label (GTK_LABEL (dialog->error_label), file_name);
+                g_free (file_name);
+
+                return;
         }
-        
+
         display_text = get_new_display_name (dialog->mode, file_name, entry_text, replace_text);
 
         gtk_label_set_label (GTK_LABEL (dialog->error_label), display_text);
 
+        g_list_free (new_names);
+        g_list_free (duplicates);
+
         g_free (entry_text);
         g_free (file_name);
         g_free (replace_text);
@@ -226,6 +390,7 @@ static void
 batch_rename_dialog_on_closed (GtkDialog *dialog)
 {
         gtk_window_close (GTK_WINDOW (dialog));
+        g_message("closed this");
 
 }
 
@@ -233,7 +398,9 @@ static void
 file_names_widget_on_activate (NautilusBatchRename *dialog)
 {
         GList *new_names;
-        /* check if all names are all right i.e no conflicts, valid name, etc...*/
+
+        if (!gtk_widget_is_sensitive (dialog->rename_button))
+                return;
 
         new_names = batch_rename_get_new_names(dialog);
 
@@ -255,12 +422,15 @@ nautilus_batch_rename_class_init (NautilusBatchRenameClass *klass)
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, grid);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, add_text_options);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, cancel_button);
+        gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, conflict_listbox);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, error_label);
+        gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, expander);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, name_entry);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, rename_button);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, rename_modes);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, find_label);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, left_stack);
+        gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, label_stack);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, right_stack);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, replace_label);
         gtk_widget_class_bind_template_child (widget_class, NautilusBatchRename, replace_entry);
@@ -291,6 +461,11 @@ nautilus_batch_rename_new (NautilusFilesView *view)
         gtk_label_set_ellipsize (GTK_LABEL (dialog->error_label), PANGO_ELLIPSIZE_END);
         gtk_label_set_max_width_chars (GTK_LABEL (dialog->error_label), MAX_DISPLAY_LEN);
 
+        gtk_label_set_ellipsize (GTK_LABEL (dialog->expander_label), PANGO_ELLIPSIZE_END);
+        gtk_label_set_max_width_chars (GTK_LABEL (dialog->expander_label), MAX_DISPLAY_LEN - 1);
+
+        gtk_widget_set_vexpand (dialog->rename_button, FALSE);
+
         /* update display text */
         file_names_widget_entry_on_changed (dialog);
 
@@ -305,5 +480,14 @@ nautilus_batch_rename_init (NautilusBatchRename *self)
         gtk_combo_box_set_active (GTK_COMBO_BOX (self->add_text_options), 1);      
         gtk_combo_box_set_active (GTK_COMBO_BOX (self->rename_modes), 0);
 
+        gtk_list_box_set_header_func (GTK_LIST_BOX (self->conflict_listbox),
+                                (GtkListBoxUpdateHeaderFunc) listbox_header_func,
+                                self,
+                                NULL);
+
+        g_signal_connect (self->expander, "activate", G_CALLBACK (activate_expander), self);
+
+        self->expander_label = gtk_label_new ("");
+
         self->mode = NAUTILUS_BATCH_RENAME_PREPEND;
 }
\ No newline at end of file
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
index c23f97c..cda409f 100644
--- a/src/nautilus-files-view.c
+++ b/src/nautilus-files-view.c
@@ -1801,6 +1801,20 @@ file_name_widget_entry_on_changed (gpointer user_data)
         g_free (name);
 }
 
+gboolean
+file_with_name_exists (NautilusFilesView *view,
+                       gchar             *name)
+{
+        NautilusFile *existing_file;
+
+        existing_file = nautilus_directory_get_file_by_name (view->details->model, name);
+
+        if (existing_file == NULL)
+                return FALSE;
+
+        return TRUE;
+}
+
 static void
 create_folder_dialog_on_response (GtkDialog *dialog,
                                   gint       response_id,
diff --git a/src/nautilus-files-view.h b/src/nautilus-files-view.h
index 9b5a28b..89b2a46 100644
--- a/src/nautilus-files-view.h
+++ b/src/nautilus-files-view.h
@@ -367,4 +367,7 @@ void              nautilus_files_view_action_show_hidden_files   (NautilusFilesV
 GActionGroup *    nautilus_files_view_get_action_group           (NautilusFilesView      *view);
 GtkWidget*        nautilus_files_view_get_content_widget         (NautilusFilesView      *view);
 
+gboolean          file_with_name_exists                          (NautilusFilesView      *view,
+                                                                  gchar                  *name);
+
 #endif /* NAUTILUS_FILES_VIEW_H */
diff --git a/src/resources/ui/nautilus-batch-rename-dialog.ui 
b/src/resources/ui/nautilus-batch-rename-dialog.ui
index f0dfa27..8d7704e 100644
--- a/src/resources/ui/nautilus-batch-rename-dialog.ui
+++ b/src/resources/ui/nautilus-batch-rename-dialog.ui
@@ -58,9 +58,12 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="use_underline">True</property>
+                <property name="height_request">10</property>
                 <signal name="clicked" handler="batch_rename_dialog_on_closed" swapped="yes" />
               </object>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
                 <property name="left-attach">5</property>
                 <property name="top-attach">2</property>
                 <property name="width">1</property>
@@ -72,22 +75,65 @@
                 <property name="visible">True</property>
                 <property name="use_underline">True</property>
                 <property name="can_default">True</property>
+                <property name="height_request">10</property>
                 <signal name="clicked" handler="file_names_widget_on_activate" swapped="yes" />
                 <style>
                   <class name="suggested-action"/>
                 </style>
               </object>
               <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
                 <property name="left-attach">6</property>
                 <property name="top-attach">2</property>
                 <property name="width">1</property>
               </packing>
             </child>
+
             <child>
-              <object class="GtkLabel" id="error_label">
+              <object class="GtkStack" id="label_stack">
                 <property name="visible">True</property>
-                <property name="halign">start</property>
                 <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkLabel" id="error_label">
+                    <property name="visible">True</property>
+                    <property name="halign">start</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                </child>
+
+                <child>
+                  <object class="GtkExpander" id="expander">
+                    <property name="visible">True</property>
+                    <property name="valign">center</property>
+                    <child type="label">
+                      <object class="GtkLabel" id="expander-label"/>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow">
+                        <property name="height_request">100</property>
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">False</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkViewport">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <child>
+                              <object class="GtkListBox" id="conflict_listbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+
               </object>
               <packing>
                 <property name="left-attach">0</property>
@@ -95,6 +141,7 @@
                 <property name="width">8</property>
               </packing>
             </child>
+
             <child>
               <object class="GtkStack" id="left_stack">
                 <property name="visible">True</property>
@@ -153,7 +200,6 @@
                     <signal name="activate" handler="file_names_widget_on_activate" swapped="yes" />
                   </object>
                 </child>
-
                   </object>
                 </child>
               </object>


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