[nautilus/wip/alexpandelea/batchRename] Code improvements



commit 01e4314dfcfad4c8b6ecb2dde97022321510d89a
Author: Alexandru Pandelea <alexandru pandelea gmail com>
Date:   Fri Aug 26 14:25:05 2016 +0300

    Code improvements
    
    Add review changes mentioned in comments 41 to 46
    
    https://bugzilla.gnome.org/show_bug.cgi?id=768311

 src/nautilus-batch-rename-dialog.c               |  794 ++++++++++++++--------
 src/nautilus-batch-rename-dialog.h               |   28 +-
 src/nautilus-batch-rename-utilities.c            |  210 ++++---
 src/nautilus-batch-rename-utilities.h            |   42 +-
 src/nautilus-file-undo-operations.c              |  103 +++
 src/nautilus-file.c                              |    4 +-
 src/resources/css/Adwaita.css                    |    1 +
 src/resources/ui/nautilus-batch-rename-dialog.ui |   10 +-
 8 files changed, 787 insertions(+), 405 deletions(-)
---
diff --git a/src/nautilus-batch-rename-dialog.c b/src/nautilus-batch-rename-dialog.c
index 7faab4c..bd5e5f8 100644
--- a/src/nautilus-batch-rename-dialog.c
+++ b/src/nautilus-batch-rename-dialog.c
@@ -28,11 +28,6 @@
 #include <string.h>
 #include <glib/gi18n.h>
 
-#define ADD_TEXT_ENTRY_SIZE 550
-#define REPLACE_ENTRY_SIZE  275
-#define TAG_UNAVAILABLE -2
-#define HAVE_CONFLICT 1
-
 struct _NautilusBatchRenameDialog
 {
         GtkDialog                        parent;
@@ -115,6 +110,7 @@ typedef struct
         gboolean available;
         gboolean set;
         gint position;
+        gint original_position;
 } TagData;
 
 static void     update_display_text     (NautilusBatchRenameDialog *dialog);
@@ -202,7 +198,7 @@ add_original_file_name_tag (GSimpleAction       *action,
 
         gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                   ORIGINAL_FILE_NAME,
-                                  strlen (ORIGINAL_FILE_NAME),
+                                  g_utf8_strlen (ORIGINAL_FILE_NAME, -1),
                                   &cursor_position);
 
         gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
@@ -245,7 +241,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           CREATION_DATE,
-                                          strlen (CREATION_DATE),
+                                          g_utf8_strlen (CREATION_DATE, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-creation-date-tag");
@@ -258,7 +254,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           CAMERA_MODEL,
-                                          strlen (CAMERA_MODEL),
+                                          g_utf8_strlen (CAMERA_MODEL, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-equipment-tag");
@@ -271,7 +267,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           SEASON_NUMBER,
-                                          strlen (SEASON_NUMBER),
+                                          g_utf8_strlen (SEASON_NUMBER, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-season-tag");
@@ -284,7 +280,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           EPISODE_NUMBER,
-                                          strlen (EPISODE_NUMBER),
+                                          g_utf8_strlen (EPISODE_NUMBER, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-episode-tag");
@@ -297,7 +293,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           TRACK_NUMBER,
-                                          strlen (TRACK_NUMBER),
+                                          g_utf8_strlen (TRACK_NUMBER, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-track-number-tag");
@@ -310,7 +306,7 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           ARTIST_NAME,
-                                          strlen (ARTIST_NAME),
+                                          g_utf8_strlen (ARTIST_NAME, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-artist-name-tag");
@@ -323,12 +319,25 @@ add_metadata_tag (GSimpleAction       *action,
 
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           TITLE,
-                                          strlen (TITLE),
+                                          g_utf8_strlen (TITLE, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
                 disable_action (dialog, "add-title-tag");
         }
 
+        if (g_strrstr (action_name, "album")) {
+                tag_data = g_hash_table_lookup (dialog->tag_info_table, ALBUM_NAME);
+                tag_data->available = TRUE;
+                tag_data->set = FALSE;
+
+                gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
+                                          ALBUM_NAME,
+                                          g_utf8_strlen (ALBUM_NAME, -1),
+                                          &cursor_position);
+                gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
+                disable_action (dialog, "add-album-name-tag");
+        }
+
         gtk_entry_grab_focus_without_selecting (GTK_ENTRY (dialog->name_entry));
 }
 
@@ -350,7 +359,7 @@ add_numbering_tag (GSimpleAction       *action,
         if (g_strrstr (action_name, "zero")) {
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           NUMBERING,
-                                          strlen (NUMBERING),
+                                          g_utf8_strlen (NUMBERING, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
         }
@@ -358,7 +367,7 @@ add_numbering_tag (GSimpleAction       *action,
         if (g_strrstr (action_name, "one")) {
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           NUMBERING0,
-                                          strlen (NUMBERING0),
+                                          g_utf8_strlen (NUMBERING0, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
         }
@@ -366,7 +375,7 @@ add_numbering_tag (GSimpleAction       *action,
         if (g_strrstr (action_name, "two")) {
                 gtk_editable_insert_text (GTK_EDITABLE (dialog->name_entry),
                                           NUMBERING00,
-                                          strlen (NUMBERING00),
+                                          g_utf8_strlen (NUMBERING00, -1),
                                           &cursor_position);
                 gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), cursor_position);
         }
@@ -399,6 +408,7 @@ const GActionEntry dialog_entries[] = {
         { "add-track-number-tag", add_metadata_tag },
         { "add-artist-name-tag", add_metadata_tag },
         { "add-title-tag", add_metadata_tag },
+        { "add-album-name-tag", add_metadata_tag },
 
 };
 
@@ -445,8 +455,9 @@ row_selected (GtkListBox    *box,
         }
 }
 
-gint compare_int (gconstpointer a,
-                  gconstpointer b)
+static gint
+compare_tag_position (gconstpointer a,
+                      gconstpointer b)
 {
         int *number1 = (int*) a;
         int *number2 = (int*) b;
@@ -461,11 +472,12 @@ static GList*
 split_entry_text (NautilusBatchRenameDialog *dialog,
                   gchar                     *entry_text)
 {
-        GString *string;
+        GString *normal_text;
         GString *tag;
         GArray *tag_positions;
         gint tags;
         gint i;
+        gchar *substring;
         gint tag_end_position;
         GList *result = NULL;
         TagData *tag_data;
@@ -540,97 +552,107 @@ split_entry_text (NautilusBatchRenameDialog *dialog,
                 tags++;
         }
 
-        g_array_sort (tag_positions, compare_int);
+        tag_data = g_hash_table_lookup (dialog->tag_info_table, ALBUM_NAME);
+        if (tag_data->set) {
+                g_array_append_val (tag_positions, tag_data->position);
+                tags++;
+        }
+
+        g_array_sort (tag_positions, compare_tag_position);
 
         for (i = 0; i < tags; i++) {
                 tag = g_string_new ("");
 
-                string = g_string_new ("");
-
-                string = g_string_append_len (string,
-                                              entry_text + tag_end_position,
-                                              g_array_index (tag_positions, gint, i) - tag_end_position);
+                substring = g_utf8_substring (entry_text, tag_end_position,
+                                              g_array_index (tag_positions, gint, i));
+                normal_text = g_string_new (substring);
+                g_free (substring);
 
-                if (g_strcmp0 (string->str, ""))
-                        result = g_list_prepend (result, string);
+                if (g_strcmp0 (normal_text->str, ""))
+                        result = g_list_prepend (result, normal_text);
 
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, ORIGINAL_FILE_NAME);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (ORIGINAL_FILE_NAME);
+                                           g_utf8_strlen (ORIGINAL_FILE_NAME, -1);
                         tag = g_string_append (tag, ORIGINAL_FILE_NAME);
                 }
 
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, NUMBERING);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (NUMBERING);
+                                           g_utf8_strlen (NUMBERING, -1);
                         tag = g_string_append (tag, NUMBERING);
                 }
 
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, NUMBERING0);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (NUMBERING0);
+                                           g_utf8_strlen (NUMBERING0, -1);
                         tag = g_string_append (tag, NUMBERING0);
                 }
 
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, NUMBERING00);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (NUMBERING00);
+                                           g_utf8_strlen (NUMBERING00, -1);
                         tag = g_string_append (tag, NUMBERING00);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, CREATION_DATE);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (CREATION_DATE);
+                                           g_utf8_strlen (CREATION_DATE, -1);
                         tag = g_string_append (tag, CREATION_DATE);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, CAMERA_MODEL);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (CAMERA_MODEL);
+                                           g_utf8_strlen (CAMERA_MODEL, -1);
                         tag = g_string_append (tag, CAMERA_MODEL);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, SEASON_NUMBER);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (SEASON_NUMBER);
+                                           g_utf8_strlen (SEASON_NUMBER, -1);
                         tag = g_string_append (tag, SEASON_NUMBER);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, EPISODE_NUMBER);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (EPISODE_NUMBER);
+                                           g_utf8_strlen (EPISODE_NUMBER, -1);
                         tag = g_string_append (tag, EPISODE_NUMBER);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, TRACK_NUMBER);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (TRACK_NUMBER);
+                                           g_utf8_strlen (TRACK_NUMBER, -1);
                         tag = g_string_append (tag, TRACK_NUMBER);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, ARTIST_NAME);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (ARTIST_NAME);
+                                           g_utf8_strlen (ARTIST_NAME, -1);
                         tag = g_string_append (tag, ARTIST_NAME);
                 }
                 tag_data = g_hash_table_lookup (dialog->tag_info_table, TITLE);
-                if (g_array_index (tag_positions, gint, i) == tag_data->position && tag_data->set) {
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
                         tag_end_position = g_array_index (tag_positions, gint, i) +
-                                           strlen (TITLE);
+                                           g_utf8_strlen (TITLE, -1);
                         tag = g_string_append (tag, TITLE);
                 }
+                tag_data = g_hash_table_lookup (dialog->tag_info_table, ALBUM_NAME);
+                if (tag_data->set && g_array_index (tag_positions, gint, i) == tag_data->position) {
+                        tag_end_position = g_array_index (tag_positions, gint, i) +
+                                           g_utf8_strlen (ALBUM_NAME, -1);
+                        tag = g_string_append (tag, ALBUM_NAME);
+                }
 
                 result = g_list_prepend (result, tag);
         }
-        string = g_string_new ("");
-        string = g_string_append (string, entry_text + tag_end_position);
+        normal_text = g_string_new (g_utf8_offset_to_pointer (entry_text, tag_end_position));
 
-        if (g_strcmp0 (string->str, ""))
-                result = g_list_prepend (result, string);
+        if (g_strcmp0 (normal_text->str, "") != 0)
+                result = g_list_prepend (result, normal_text);
 
         result = g_list_reverse (result);
 
@@ -682,30 +704,39 @@ batch_rename_dialog_get_new_names (NautilusBatchRenameDialog *dialog)
 }
 
 static void
-begin_batch_rename_dialog (NautilusBatchRenameDialog *dialog,
-                           GList                     *new_names)
+begin_batch_rename (NautilusBatchRenameDialog *dialog,
+                    GList                     *new_names)
 {
-        GList *l1;
-        GList *l2;
-        GList *l3;
+        GList *new_names_list;
+        GList *files;
+        GList *files2;
+        GList *new_names_list2;
         gchar *file_name;
         gchar *old_file_name;
         GString *new_file_name;
-        GList *new_name;
+        GString *new_name;
         NautilusFile *file;
 
-        for (l1 = new_names, l2 = dialog->selection; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next) 
{
-                old_file_name = nautilus_file_get_name (NAUTILUS_FILE (l2->data));
-                new_file_name = l1->data;
-
-                for (l3 = dialog->selection; l3 != NULL; l3 = l3->next) {
-                        file_name = nautilus_file_get_name (NAUTILUS_FILE (l3->data));
-                        if (l3 != l2 && g_strcmp0 (file_name, new_file_name->str) == 0) {
-                                file = NAUTILUS_FILE (l3->data);
-                                new_name = l1->data;
-
-                                dialog->selection = g_list_remove_link (dialog->selection, l3);
-                                new_names = g_list_remove_link (new_names, l1);
+        /* in the following case:
+         * file1 -> file2
+         * file2 -> file3
+         * file2 must be renamed first, so because of that, the list has to be reordered */
+        for (new_names_list = new_names, files = dialog->selection;
+             new_names_list != NULL && files != NULL;
+             new_names_list = new_names_list->next, files = files->next) {
+                old_file_name = nautilus_file_get_name (NAUTILUS_FILE (files->data));
+                new_file_name = new_names_list->data;
+
+                for (files2 = dialog->selection, new_names_list2 = new_names;
+                     files2 != NULL && new_names_list2 != NULL;
+                     files2 = files2->next, new_names_list2 = new_names_list2->next) {
+                        file_name = nautilus_file_get_name (NAUTILUS_FILE (files2->data));
+                        if (files2 != files && g_strcmp0 (file_name, new_file_name->str) == 0) {
+                                file = NAUTILUS_FILE (files2->data);
+                                new_name = new_names_list2->data;
+
+                                dialog->selection = g_list_remove_link (dialog->selection, files2);
+                                new_names = g_list_remove_link (new_names, new_names_list2);
 
                                 dialog->selection = g_list_prepend (dialog->selection, file);
                                 new_names = g_list_prepend (new_names, new_name);
@@ -748,51 +779,50 @@ listbox_header_func (GtkListBoxRow               *row,
         }
 }
 
-/* This is manually done instead of using GtkSizeGroup because of the complexity of
- * the later.*/
+/* This is manually done instead of using GtkSizeGroup because of the computational
+ * complexity of the later.*/
 static void
 update_rows_height (NautilusBatchRenameDialog *dialog)
 {
         GList *l;
-        gint minimum_height;
-        gint natural_height;
-        gint new_maximum_height;
+        gint current_row_natural_height;
+        gint maximum_height;
 
-        new_maximum_height = -1;
+        maximum_height = -1;
 
         /* check if maximum height has changed */
         for (l = dialog->listbox_labels_new; l != NULL; l = l->next) {
                 gtk_widget_get_preferred_height (GTK_WIDGET (l->data),
-                                                 &minimum_height,
-                                                 &natural_height);
+                                                 NULL,
+                                                 &current_row_natural_height);
 
-                if (minimum_height > new_maximum_height) {
-                        new_maximum_height = minimum_height;
+                if (current_row_natural_height > maximum_height) {
+                        maximum_height = current_row_natural_height;
                 }
         }
 
         for (l = dialog->listbox_labels_old; l != NULL; l = l->next) {
                 gtk_widget_get_preferred_height (GTK_WIDGET (l->data),
-                                                 &minimum_height,
-                                                 &natural_height);
+                                                 NULL,
+                                                 &current_row_natural_height);
 
-                if (minimum_height > new_maximum_height) {
-                        new_maximum_height = minimum_height;
+                if (current_row_natural_height > maximum_height) {
+                        maximum_height = current_row_natural_height;
                 }
         }
 
         for (l = dialog->listbox_icons; l != NULL; l = l->next) {
                 gtk_widget_get_preferred_height (GTK_WIDGET (l->data),
-                                                 &minimum_height,
-                                                 &natural_height);
+                                                 NULL,
+                                                 &current_row_natural_height);
 
-                if (minimum_height > new_maximum_height) {
-                        new_maximum_height = minimum_height;
+                if (current_row_natural_height > maximum_height) {
+                        maximum_height = current_row_natural_height;
                 }
         }
 
-        if (new_maximum_height != dialog->row_height) {
-                dialog->row_height = new_maximum_height;
+        if (maximum_height != dialog->row_height) {
+                dialog->row_height = maximum_height;
 
                 for (l = dialog->listbox_icons; l != NULL; l = l->next) {
                         g_object_set (G_OBJECT (l->data), "height-request", dialog->row_height, NULL);
@@ -893,39 +923,35 @@ create_arrow_row_for_label (NautilusBatchRenameDialog *dialog,
 }
 
 static void
-batch_rename_dialog_on_response (NautilusBatchRenameDialog *dialog,
-                                 gint                       response_id,
-                                 gpointer                   user_data)
+prepare_batch_rename (NautilusBatchRenameDialog *dialog)
 {
-        if (response_id == GTK_RESPONSE_OK) {
-                /* wait for checking conflicts to finish, to be sure that
-                 * the rename can actually take place */
-                if (dialog->checking_conflicts) {
-                        dialog->rename_clicked = TRUE;
-                        return;
-                }
+        GdkCursor *cursor;
+        GdkDisplay *display;
 
-                if (!gtk_widget_is_sensitive (dialog->rename_button))
-                        return;
+        /* wait for checking conflicts to finish, to be sure that
+         * the rename can actually take place */
+        if (dialog->checking_conflicts) {
+                dialog->rename_clicked = TRUE;
+                return;
+        }
 
-                GdkCursor *cursor;
-                GdkDisplay *display;
+        if (!gtk_widget_is_sensitive (dialog->rename_button))
+                return;
 
-                display = gtk_widget_get_display (GTK_WIDGET (dialog->window));
-                cursor = gdk_cursor_new_from_name (display, "progress");
-                gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (dialog->window)),
-                                       cursor);
-                g_object_unref (cursor);
+        display = gtk_widget_get_display (GTK_WIDGET (dialog->window));
+        cursor = gdk_cursor_new_from_name (display, "progress");
+        gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (dialog->window)),
+                               cursor);
+        g_object_unref (cursor);
 
-                display = gtk_widget_get_display (GTK_WIDGET (dialog));
-                cursor = gdk_cursor_new_from_name (display, "progress");
-                gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (dialog)),
-                                       cursor);
-                g_object_unref (cursor);
+        display = gtk_widget_get_display (GTK_WIDGET (dialog));
+        cursor = gdk_cursor_new_from_name (display, "progress");
+        gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (dialog)),
+                               cursor);
+        g_object_unref (cursor);
 
-                gtk_widget_hide (GTK_WIDGET (dialog));
-                begin_batch_rename_dialog (dialog, dialog->new_names);
-        }
+        gtk_widget_hide (GTK_WIDGET (dialog));
+        begin_batch_rename (dialog, dialog->new_names);
 
         if (dialog->conflict_cancellable)
                 g_cancellable_cancel (dialog->conflict_cancellable);
@@ -934,6 +960,21 @@ batch_rename_dialog_on_response (NautilusBatchRenameDialog *dialog,
 }
 
 static void
+batch_rename_dialog_on_response (NautilusBatchRenameDialog *dialog,
+                                 gint                       response_id,
+                                 gpointer                   user_data)
+{
+        if (response_id == GTK_RESPONSE_OK) {
+                prepare_batch_rename (dialog);
+        } else {
+                if (dialog->conflict_cancellable)
+                        g_cancellable_cancel (dialog->conflict_cancellable);
+
+                gtk_widget_destroy (GTK_WIDGET (dialog));
+        }
+}
+
+static void
 fill_display_listbox (NautilusBatchRenameDialog *dialog)
 {
         GtkWidget *row;
@@ -950,8 +991,6 @@ fill_display_listbox (NautilusBatchRenameDialog *dialog)
         gtk_size_group_add_widget (dialog->size_group, dialog->result_listbox);
         gtk_size_group_add_widget (dialog->size_group, dialog->original_name_listbox);
 
-        /* add rows to a list so that they can be removed when the renaming
-         * result changes */
         for (l1 = dialog->new_names, l2 = dialog->selection; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = 
l2->next) {
                 file = NAUTILUS_FILE (l2->data);
                 new_name = l1->data;
@@ -987,7 +1026,7 @@ static void
 select_nth_conflict (NautilusBatchRenameDialog *dialog)
 {
         GList *l;
-        GString *file_name;
+        GString *conflict_file_name;
         GString *display_text;
         GString *new_name;
         gint nth_conflict_index;
@@ -995,17 +1034,17 @@ select_nth_conflict (NautilusBatchRenameDialog *dialog)
         gint name_occurences;
         GtkAdjustment *adjustment;
         GtkAllocation allocation;
-        ConflictData *data;
+        ConflictData *conflict_data;
 
         nth_conflict = dialog->selected_conflict;
         l = g_list_nth (dialog->duplicates, nth_conflict);
-        data = l->data;
+        conflict_data = l->data;
 
         /* the conflict that has to be selected */
-        file_name = g_string_new (data->name);
+        conflict_file_name = g_string_new (conflict_data->name);
         display_text = g_string_new ("");
 
-        nth_conflict_index = data->index;
+        nth_conflict_index = conflict_data->index;
 
         l = g_list_nth (dialog->original_name_listbox_rows, nth_conflict_index);
         gtk_list_box_select_row (GTK_LIST_BOX (dialog->original_name_listbox),
@@ -1027,22 +1066,22 @@ select_nth_conflict (NautilusBatchRenameDialog *dialog)
         name_occurences = 0;
         for (l = dialog->new_names; l != NULL; l = l->next) {
                 new_name = l->data;
-                if (g_string_equal (new_name, file_name))
+                if (g_string_equal (new_name, conflict_file_name))
                         name_occurences++;
         }
         if (name_occurences > 1)
                 g_string_append_printf (display_text,
                                         _("\"%s\" would not be a unique new name"),
-                                        file_name->str);
+                                        conflict_file_name->str);
         else
                 g_string_append_printf (display_text,
                                         _("\"%s\" would conflict with an existing file."),
-                                        file_name->str);
+                                        conflict_file_name->str);
 
         gtk_label_set_label (GTK_LABEL (dialog->conflict_label),
                              display_text->str);
 
-        g_string_free (file_name, TRUE);
+        g_string_free (conflict_file_name, TRUE);
 }
 
 static void
@@ -1079,13 +1118,15 @@ update_conflict_row_background (NautilusBatchRenameDialog *dialog)
         GList *l1;
         GList *l2;
         GList *l3;
-        GList *l;
+        GList *duplicates;
         gint index;
         GtkStyleContext *context;
-        ConflictData *data;
+        ConflictData *conflict_data;
 
         index = 0;
 
+        duplicates = dialog->duplicates;
+
         for (l1 = dialog->original_name_listbox_rows,
              l2 = dialog->arrow_listbox_rows,
              l3 = dialog->result_listbox_rows;
@@ -1104,21 +1145,21 @@ update_conflict_row_background (NautilusBatchRenameDialog *dialog)
 
                 }
 
-                for (l = dialog->duplicates; l != NULL; l = l->next) {
-                        data = l->data;
+                if (duplicates != NULL) {
+                        conflict_data = duplicates->data;
+                        if (conflict_data->index == index) {
+                                        context = gtk_widget_get_style_context (GTK_WIDGET (l1->data));
+                                        gtk_style_context_add_class (context, "conflict-row");
 
-                        if (data->index == index) {
-                                context = gtk_widget_get_style_context (GTK_WIDGET (l1->data));
-                                gtk_style_context_add_class (context, "conflict-row");
+                                        context = gtk_widget_get_style_context (GTK_WIDGET (l2->data));
+                                        gtk_style_context_add_class (context, "conflict-row");
 
-                                context = gtk_widget_get_style_context (GTK_WIDGET (l2->data));
-                                gtk_style_context_add_class (context, "conflict-row"); 
+                                        context = gtk_widget_get_style_context (GTK_WIDGET (l3->data));
+                                        gtk_style_context_add_class (context, "conflict-row");
 
-                                context = gtk_widget_get_style_context (GTK_WIDGET (l3->data));
-                                gtk_style_context_add_class (context, "conflict-row"); 
+                                        duplicates = duplicates->next;
                         }
                 }
-
                 index++;
         } 
 }
@@ -1149,8 +1190,8 @@ update_listbox (NautilusBatchRenameDialog *dialog)
                 if (dialog->mode == NAUTILUS_BATCH_RENAME_DIALOG_FORMAT) {
                         gtk_label_set_label (label, old_name);
                 } else {
-                        new_name = batch_rename_dialog_replace_label_text (old_name,
-                                                                           gtk_entry_get_text (GTK_ENTRY 
(dialog->find_entry)));
+                        new_name = batch_rename_replace_label_text (old_name,
+                                                                    gtk_entry_get_text (GTK_ENTRY 
(dialog->find_entry)));
                         gtk_label_set_markup (GTK_LABEL (label), new_name->str);
 
                         g_string_free (new_name, TRUE);
@@ -1192,7 +1233,7 @@ update_listbox (NautilusBatchRenameDialog *dialog)
 
         /* if the rename button was clicked and there's no conflict, then start renaming */
         if (dialog->rename_clicked && dialog->duplicates == NULL) {
-                batch_rename_dialog_on_response (dialog, GTK_RESPONSE_OK, NULL);
+                prepare_batch_rename (dialog);
         }
 
         if (dialog->rename_clicked && dialog->duplicates != NULL) {
@@ -1202,13 +1243,12 @@ update_listbox (NautilusBatchRenameDialog *dialog)
 
 
 void
-check_conflict_for_file (NautilusBatchRenameDialog *dialog,
-                         NautilusDirectory         *directory,
-                         GList                     *files)
+check_conflict_for_files (NautilusBatchRenameDialog *dialog,
+                          NautilusDirectory         *directory,
+                          GList                     *files)
 {
         gchar *current_directory;
         gchar *parent_uri;
-        gchar *table_parent_uri;
         gchar *name;
         NautilusFile *file;
         GString *new_name;
@@ -1219,7 +1259,9 @@ check_conflict_for_file (NautilusBatchRenameDialog *dialog,
         GHashTable *names_conflicts_table;
         gboolean exists;
         gboolean have_conflict;
-        ConflictData *data;
+        gboolean tag_present;
+        gboolean same_parent_directory;
+        ConflictData *conflict_data;
 
         current_directory = nautilus_directory_get_uri (directory);
 
@@ -1243,17 +1285,19 @@ check_conflict_for_file (NautilusBatchRenameDialog *dialog,
                 file = NAUTILUS_FILE (l2->data);
                 parent_uri = nautilus_file_get_parent_uri (file);
 
-                table_parent_uri = g_hash_table_lookup (new_names_table, new_name->str);
-
-                if (g_strcmp0 (parent_uri, current_directory) == 0)
-                        g_hash_table_insert (new_names_table,
-                                             g_strdup (new_name->str),
-                                             nautilus_file_get_parent_uri (file));
-
-                if (table_parent_uri != NULL  && g_strcmp0 (current_directory, parent_uri) == 0) {
-                        g_hash_table_insert (names_conflicts_table,
-                                             g_strdup (new_name->str),
-                                             nautilus_file_get_parent_uri (file));
+                tag_present = g_hash_table_lookup (new_names_table, new_name->str) != NULL;
+                same_parent_directory = g_strcmp0 (parent_uri, current_directory) == 0;
+
+                if (same_parent_directory) {
+                        if (!tag_present) {
+                                g_hash_table_insert (new_names_table,
+                                                     g_strdup (new_name->str),
+                                                     nautilus_file_get_parent_uri (file));
+                        } else {
+                                g_hash_table_insert (names_conflicts_table,
+                                                     g_strdup (new_name->str),
+                                                     nautilus_file_get_parent_uri (file));
+                        }
                 }
 
                 g_free (parent_uri);
@@ -1263,15 +1307,14 @@ check_conflict_for_file (NautilusBatchRenameDialog *dialog,
                 file = NAUTILUS_FILE (l1->data);
                 g_hash_table_insert (directory_files_table,
                                      nautilus_file_get_name (file),
-                                     GINT_TO_POINTER (HAVE_CONFLICT));
+                                     GINT_TO_POINTER (TRUE));
         }
 
         for (l1 = dialog->selection, l2 = dialog->new_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = 
l2->next) {
                 file = NAUTILUS_FILE (l1->data);
 
-                file_name = g_string_new ("");
                 name = nautilus_file_get_name (file);
-                g_string_append (file_name, name);
+                file_name = g_string_new (name);
                 g_free (name);
 
                 parent_uri = nautilus_file_get_parent_uri (file);
@@ -1286,26 +1329,27 @@ check_conflict_for_file (NautilusBatchRenameDialog *dialog,
                     !g_string_equal (new_name, file_name)) {
                         exists = GPOINTER_TO_INT (g_hash_table_lookup (directory_files_table, 
new_name->str));
 
-                        if (exists == HAVE_CONFLICT &&
+                        if (exists == TRUE &&
                             !file_name_conflicts_with_results (dialog->selection, dialog->new_names, 
new_name, parent_uri)) {
-                                data = g_new (ConflictData, 1);
-                                data->name = g_strdup (new_name->str);
-                                data->index = g_list_index (dialog->selection, l1->data);
+                                conflict_data = g_new (ConflictData, 1);
+                                conflict_data->name = g_strdup (new_name->str);
+                                conflict_data->index = g_list_index (dialog->selection, l1->data);
                                 dialog->duplicates = g_list_prepend (dialog->duplicates,
-                                                                     data);
+                                                                     conflict_data);
 
                                 have_conflict = TRUE;
                         }
                 }
                 if (!have_conflict) {
-                        table_parent_uri = g_hash_table_lookup (names_conflicts_table, new_name->str);
+                        tag_present = g_hash_table_lookup (names_conflicts_table, new_name->str) != NULL;
+                        same_parent_directory = g_strcmp0 (nautilus_file_get_parent_uri (file), 
current_directory) == 0;
 
-                        if (table_parent_uri != NULL && g_strcmp0 (nautilus_file_get_parent_uri (file), 
current_directory) == 0) {
-                                data = g_new (ConflictData, 1);
-                                data->name = g_strdup (new_name->str);
-                                data->index = g_list_index (dialog->selection, l1->data);
+                        if (tag_present && same_parent_directory) {
+                                conflict_data = g_new (ConflictData, 1);
+                                conflict_data->name = g_strdup (new_name->str);
+                                conflict_data->index = g_list_index (dialog->selection, l1->data);
                                 dialog->duplicates = g_list_prepend (dialog->duplicates,
-                                                                     data);
+                                                                     conflict_data);
 
                                 have_conflict = TRUE;
                         }
@@ -1354,9 +1398,9 @@ on_call_when_ready (NautilusDirectory *directory,
                     GList             *files,
                     gpointer           callback_data)
 {
-        check_conflict_for_file (NAUTILUS_BATCH_RENAME_DIALOG (callback_data),
-                                 directory,
-                                 files);
+        check_conflict_for_files (NAUTILUS_BATCH_RENAME_DIALOG (callback_data),
+                                  directory,
+                                  files);
 }
 
 static void
@@ -1381,7 +1425,7 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
         GHashTable *new_names_table;
         GHashTable *names_conflicts_table;
         gint exists;
-        ConflictData *data;
+        ConflictData *conflict_data;
 
         dialog = NAUTILUS_BATCH_RENAME_DIALOG (object);
 
@@ -1433,12 +1477,12 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
                 new_name = l1->data;
                 hash_table_insertion = g_hash_table_insert (new_names_table,
                                                             g_strdup (new_name->str),
-                                                            GINT_TO_POINTER (HAVE_CONFLICT));
+                                                            GINT_TO_POINTER (TRUE));
 
                 if (!hash_table_insertion) {
                         g_hash_table_insert (names_conflicts_table,
                                              g_strdup (new_name->str),
-                                             GINT_TO_POINTER (HAVE_CONFLICT));
+                                             GINT_TO_POINTER (TRUE));
                 }
         }
 
@@ -1446,7 +1490,7 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
                 file = NAUTILUS_FILE (l1->data);
                 g_hash_table_insert (directory_names_table,
                                      nautilus_file_get_name (file),
-                                     GINT_TO_POINTER (HAVE_CONFLICT));
+                                     GINT_TO_POINTER (TRUE));
         }
 
         for (l1 = new_names, l2 = dialog->selection; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next) 
{
@@ -1470,13 +1514,13 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
                         /* check with already existing files */
                         exists = GPOINTER_TO_INT (g_hash_table_lookup (directory_names_table, 
new_name->str));
 
-                        if (exists == HAVE_CONFLICT &&
+                        if (exists == TRUE &&
                             !file_name_conflicts_with_results (dialog->selection, new_names, new_name, 
NULL)) {
-                                        data = g_new (ConflictData, 1);
-                                        data->name = g_strdup (new_name->str);
-                                        data->index = g_list_index (dialog->selection, l2->data);
+                                        conflict_data = g_new (ConflictData, 1);
+                                        conflict_data->name = g_strdup (new_name->str);
+                                        conflict_data->index = g_list_index (dialog->selection, l2->data);
                                         dialog->duplicates = g_list_prepend (dialog->duplicates,
-                                                                             data);
+                                                                             conflict_data);
                                         have_conflict = TRUE;
                         }
 
@@ -1485,12 +1529,12 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
                         if (!have_conflict) {
                                 exists = GPOINTER_TO_INT (g_hash_table_lookup (names_conflicts_table, 
new_name->str));
 
-                                if (exists == HAVE_CONFLICT) {
-                                        data = g_new (ConflictData, 1);
-                                        data->name = g_strdup (new_name->str);
-                                        data->index = g_list_index (dialog->selection, l2->data);
+                                if (exists == TRUE) {
+                                        conflict_data = g_new (ConflictData, 1);
+                                        conflict_data->name = g_strdup (new_name->str);
+                                        conflict_data->index = g_list_index (dialog->selection, l2->data);
                                         dialog->duplicates = g_list_prepend (dialog->duplicates,
-                                                                             data);
+                                                                             conflict_data);
                                 }
                         }
                 }
@@ -1514,8 +1558,8 @@ file_names_list_has_duplicates_async_thread (GTask        *task,
 
 static void
 file_names_list_has_duplicates_async (NautilusBatchRenameDialog *dialog,
-                                     GAsyncReadyCallback         callback,
-                                     gpointer                    user_data)
+                                      GAsyncReadyCallback        callback,
+                                      gpointer                   user_data)
 {
         if (dialog->checking_conflicts == TRUE)
                 g_cancellable_cancel (dialog->conflict_cancellable);
@@ -1525,7 +1569,6 @@ file_names_list_has_duplicates_async (NautilusBatchRenameDialog *dialog,
         dialog->checking_conflicts = TRUE;
         dialog->conflicts_task = g_task_new (dialog, dialog->conflict_cancellable, callback, user_data);
 
-        g_task_set_priority (dialog->conflicts_task, G_PRIORITY_DEFAULT);
         g_task_run_in_thread (dialog->conflicts_task, file_names_list_has_duplicates_async_thread);
 
         g_object_unref (dialog->conflicts_task);
@@ -1544,7 +1587,7 @@ check_if_tag_is_used (NautilusBatchRenameDialog *dialog,
 
         tag_data = g_hash_table_lookup (dialog->tag_info_table, tag_name);
 
-        if (g_strrstr (entry_text->str, tag_name) && tag_data->set == FALSE) {
+        if (tag_data->set == FALSE && g_strrstr (entry_text->str, tag_name)) {
                 action = g_action_map_lookup_action (G_ACTION_MAP (dialog->action_group),
                                                      action_name);
                 g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
@@ -1559,8 +1602,8 @@ check_if_tag_is_used (NautilusBatchRenameDialog *dialog,
         }
 
         if (g_strrstr (entry_text->str, tag_name)) {
-                tag_data->position = g_strrstr (entry_text->str, tag_name) -
-                                     entry_text->str;
+                tag_data->position = g_utf8_pointer_to_offset(entry_text->str,
+                                                              g_strrstr (entry_text->str, tag_name));
                 tag_data->set = TRUE;
         }
 
@@ -1628,14 +1671,18 @@ check_numbering_tags (NautilusBatchRenameDialog *dialog)
         }
 
         if (g_strrstr (entry_text->str, NUMBERING)) {
-                tag_data->position = g_strrstr (entry_text->str, NUMBERING) - entry_text->str;
+                tag_data->position = g_utf8_pointer_to_offset(entry_text->str,
+                                                              g_strrstr (entry_text->str, NUMBERING));
+
         }
 
         if (g_strrstr (entry_text->str, NUMBERING0)) {
-                tag_data0->position = g_strrstr (entry_text->str, NUMBERING0) - entry_text->str;
+                tag_data0->position = g_utf8_pointer_to_offset(entry_text->str,
+                                                              g_strrstr (entry_text->str, NUMBERING0));
         }
         if (g_strrstr (entry_text->str, NUMBERING00)) {
-                tag_data00->position = g_strrstr (entry_text->str, NUMBERING00) - entry_text->str;
+                tag_data00->position = g_utf8_pointer_to_offset(entry_text->str,
+                                                              g_strrstr (entry_text->str, NUMBERING00));
         }
         g_string_free (entry_text, TRUE);
 }
@@ -1687,6 +1734,12 @@ update_tags (NautilusBatchRenameDialog *dialog)
                                       TITLE,
                                       "add-title-tag");
 
+        tag_data = g_hash_table_lookup (dialog->tag_info_table, ALBUM_NAME);
+        if (tag_data->available)
+                check_if_tag_is_used (dialog,
+                                      ALBUM_NAME,
+                                      "add-album-name-tag");
+
         check_numbering_tags (dialog);
 }
 
@@ -1694,28 +1747,51 @@ static gboolean
 have_unallowed_character (NautilusBatchRenameDialog *dialog)
 {
         const gchar *entry_text;
-        gboolean have_unallowed_character;
+        gboolean have_unallowed_character_slash;
+        gboolean have_unallowed_character_dot;
+        gboolean have_unallowed_character_dotdot;
+
+        have_unallowed_character_slash = FALSE;
+        have_unallowed_character_dot = FALSE;
+        have_unallowed_character_dotdot = FALSE;
+
 
-        have_unallowed_character = FALSE;
 
         if (dialog->mode == NAUTILUS_BATCH_RENAME_DIALOG_FORMAT) {
                 entry_text = gtk_entry_get_text (GTK_ENTRY (dialog->name_entry));
 
-                if (strstr (entry_text, "/") != NULL) {
-                        have_unallowed_character = TRUE;
-                }
         } else {
                 entry_text = gtk_entry_get_text (GTK_ENTRY (dialog->replace_entry));
+        }
 
-                if (strstr (entry_text, "/") != NULL) {
-                        have_unallowed_character = TRUE;
-                }
+        if (strstr (entry_text, "/") != NULL) {
+                have_unallowed_character_slash = TRUE;
+        }
+
+        if (g_strcmp0 (entry_text, ".") == 0) {
+                have_unallowed_character_dot = TRUE;
+        }
+
+        if (g_strcmp0 (entry_text, "..") == 0) {
+                have_unallowed_character_dotdot = TRUE;
         }
 
-        if (have_unallowed_character) {
+        if (have_unallowed_character_slash) {
                 gtk_label_set_label (GTK_LABEL (dialog->conflict_label),
                                     "\"/\" is an unallowed character");
+        }
 
+        if (have_unallowed_character_dot) {
+                gtk_label_set_label (GTK_LABEL (dialog->conflict_label),
+                                    "\".\" is an unallowed file name");
+        }
+
+        if (have_unallowed_character_dotdot) {
+                gtk_label_set_label (GTK_LABEL (dialog->conflict_label),
+                                    "\"..\" is an unallowed file name");
+        }
+
+        if (have_unallowed_character_slash || have_unallowed_character_dot || 
have_unallowed_character_dotdot) {
                 gtk_widget_set_sensitive (dialog->rename_button, FALSE);
                 gtk_widget_set_sensitive (dialog->conflict_down, FALSE);
                 gtk_widget_set_sensitive (dialog->conflict_up, FALSE);
@@ -1731,7 +1807,7 @@ have_unallowed_character (NautilusBatchRenameDialog *dialog)
 }
 
 static void
-file_names_widget_entry_on_changed (NautilusBatchRenameDialog *dialog)
+update_display_text (NautilusBatchRenameDialog *dialog)
 {
         TagData *tag_data;
         TagData *tag_data0;
@@ -1777,9 +1853,9 @@ file_names_widget_entry_on_changed (NautilusBatchRenameDialog *dialog)
 }
 
 static void
-update_display_text (NautilusBatchRenameDialog *dialog)
+file_names_widget_entry_on_changed (NautilusBatchRenameDialog *dialog)
 {
-        file_names_widget_entry_on_changed (dialog);
+        update_display_text (dialog);
 }
 
 static void
@@ -1801,7 +1877,6 @@ batch_rename_dialog_mode_changed (NautilusBatchRenameDialog *dialog)
         }
 
         update_display_text (dialog);
-
 }
 
 static void
@@ -1927,6 +2002,14 @@ nautilus_batch_rename_dialog_query_finished (NautilusBatchRenameDialog *dialog,
         } else {
                 tag_data->set = FALSE;
         }
+
+        tag_data = g_hash_table_lookup (dialog->tag_info_table, ALBUM_NAME);
+        if (metadata->album_name == NULL || g_strcmp0 (metadata->album_name->str, "") == 0) {
+               disable_action (dialog, "add-album-name-tag");
+               tag_data->available = FALSE;
+        } else {
+                tag_data->set = FALSE;
+        }
 }
 
 static void
@@ -2043,7 +2126,7 @@ nautilus_batch_rename_dialog_initialize_actions (NautilusBatchRenameDialog *dial
 static void
 file_names_widget_on_activate (NautilusBatchRenameDialog *dialog)
 {
-        batch_rename_dialog_on_response (dialog, GTK_RESPONSE_OK, NULL);
+        prepare_batch_rename (dialog);
 }
 
 static gboolean
@@ -2056,6 +2139,9 @@ remove_tag (NautilusBatchRenameDialog *dialog,
         gint cursor_position;
         GString *new_entry_text;
         GString *entry_text;
+        gboolean delete_tag;
+
+        delete_tag = FALSE;
 
         g_object_get (dialog->name_entry, "cursor-position", &cursor_position, NULL);
 
@@ -2063,86 +2149,101 @@ remove_tag (NautilusBatchRenameDialog *dialog,
 
         entry_text = g_string_new (gtk_entry_get_text (GTK_ENTRY (dialog->name_entry)));
 
-        if (gtk_editable_get_selection_bounds (GTK_EDITABLE (dialog->name_entry), NULL, NULL) &&
-            cursor_position == tag_data->position + strlen (tag_name) &&
-            g_strcmp0(keyval_name, "BackSpace") == 0)
+        if (!tag_data->set)
                 return FALSE;
 
-        if (gtk_editable_get_selection_bounds (GTK_EDITABLE (dialog->name_entry), NULL, NULL) &&
-            cursor_position == tag_data->position &&
-            g_strcmp0(keyval_name, "Delete") == 0)
-                return FALSE;
-
-        if (g_strcmp0(keyval_name, "BackSpace") == 0 && tag_data->set) {
+        if (g_strcmp0(keyval_name, "BackSpace") == 0) {
                 if (cursor_position > tag_data->position &&
-                    cursor_position <= tag_data->position + strlen (tag_name)) {
-                        new_entry_text = g_string_new ("");
-                        new_entry_text = g_string_append_len (new_entry_text,
-                                                              entry_text->str,
-                                                              tag_data->position);
-                        new_entry_text = g_string_append (new_entry_text,
-                                                          entry_text->str + tag_data->position + strlen 
(tag_name));
-
-                        gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), new_entry_text->str);
-                        gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), tag_data->position);
-
-                        tag_data->set = FALSE;
+                    cursor_position <= tag_data->position + g_utf8_strlen (tag_name, -1)) {
+                        delete_tag = TRUE;
+                }
+        }
 
-                        g_string_free (new_entry_text, TRUE);
-                        g_string_free (entry_text, TRUE);
+        if (g_strcmp0(keyval_name, "Delete") == 0) {
+                if (cursor_position >= tag_data->position &&
+                    cursor_position < tag_data->position + g_utf8_strlen (tag_name, -1)) {
+                        delete_tag = TRUE;
+                }
+        }
 
-                        return TRUE;
+        if (!is_modifier &&
+            g_strcmp0 (keyval_name, "Left") != 0 &&
+            g_strcmp0 (keyval_name, "Right") != 0 &&
+            g_strcmp0 (keyval_name, "Return") != 0 &&
+            g_strcmp0 (keyval_name, "Escape") != 0 &&
+            g_strcmp0 (keyval_name, "Tab") != 0) {
+                if (cursor_position > tag_data->position &&
+                    cursor_position < tag_data->position + g_utf8_strlen (tag_name, -1)) {
+                        delete_tag = TRUE;
                 }
         }
 
-        if (g_strcmp0(keyval_name, "Delete") == 0 && tag_data->set) {
-                if (cursor_position >= tag_data->position &&
-                    cursor_position < tag_data->position + strlen (tag_name)) {
-                        new_entry_text = g_string_new ("");
-                        new_entry_text = g_string_append_len (new_entry_text,
-                                                              entry_text->str,
-                                                              tag_data->position);
-                        new_entry_text = g_string_append (new_entry_text,
-                                                          entry_text->str + tag_data->position + strlen 
(tag_name));
+        if (delete_tag) {
+                new_entry_text = g_string_new ("");
+                new_entry_text = g_string_append_len (new_entry_text,
+                                                      entry_text->str,
+                                                      tag_data->position);
+                new_entry_text = g_string_append (new_entry_text,
+                                                  g_utf8_offset_to_pointer (entry_text->str,
+                                                                            tag_data->position + 
g_utf8_strlen (tag_name, -1)));
 
-                        gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), new_entry_text->str);
-                        gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), tag_data->position);
+                gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), new_entry_text->str);
+                gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), tag_data->position);
 
-                        tag_data->set = FALSE;
+                tag_data->set = FALSE;
 
-                        g_string_free (new_entry_text, TRUE);
-                        g_string_free (entry_text, TRUE);
+                g_string_free (new_entry_text, TRUE);
+                g_string_free (entry_text, TRUE);
 
-                        return TRUE;
-                }
+                return TRUE;
         }
 
-        if (!is_modifier && tag_data->set &&
-            g_strcmp0(keyval_name, "Left") != 0 &&
-            g_strcmp0(keyval_name, "Right") != 0 &&
-            g_strcmp0(keyval_name, "Return") != 0) {
-                if (cursor_position > tag_data->position &&
-                    cursor_position < tag_data->position + strlen (tag_name)) {
-                        new_entry_text = g_string_new ("");
-                        new_entry_text = g_string_append_len (new_entry_text,
-                                                              entry_text->str,
-                                                              tag_data->position);
-                        new_entry_text = g_string_append (new_entry_text,
-                                                          entry_text->str + tag_data->position + strlen 
(tag_name));
+        return FALSE;
+}
 
-                        gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), new_entry_text->str);
-                        gtk_editable_set_position (GTK_EDITABLE (dialog->name_entry), tag_data->position);
+static GString*
+remove_tag_selection (NautilusBatchRenameDialog *dialog,
+                      GString                   *old_entry_text,
+                      gchar                     *tag_name,
+                      gint                       start,
+                      gint                       end)
+{
+        TagData *tag_data;
+        GString *new_entry_text;
 
-                        tag_data->set = FALSE;
+        new_entry_text = NULL;
 
-                        g_string_free (new_entry_text, TRUE);
-                        g_string_free (entry_text, TRUE);
+        tag_data = g_hash_table_lookup (dialog->tag_info_table, tag_name);
+        if (tag_data->set && tag_data->original_position <= end &&
+            tag_data->original_position + g_utf8_strlen (tag_name, -1) >= start) {
+                new_entry_text = g_string_new ("");
+                new_entry_text = g_string_append_len (new_entry_text,
+                                                      old_entry_text->str,
+                                                      tag_data->position);
+                new_entry_text = g_string_append (new_entry_text,
+                                                  g_utf8_offset_to_pointer (old_entry_text->str,
+                                                                            tag_data->position + 
g_utf8_strlen (tag_name, -1)));
+        }
+
+        if (new_entry_text == NULL)
+                return g_string_new (old_entry_text->str);
+        return new_entry_text;
+}
 
-                        return TRUE;
-                }
-        }
+static void
+update_tag_position (NautilusBatchRenameDialog *dialog,
+                     gchar                     *tag_name,
+                     GString                   *new_entry_text)
+{
+        TagData *tag_data;
 
-        return FALSE;
+        tag_data = g_hash_table_lookup (dialog->tag_info_table, tag_name);
+
+        if (g_strrstr (new_entry_text->str, tag_name)) {
+                tag_data->original_position = tag_data->position;
+                tag_data->position = g_utf8_pointer_to_offset(new_entry_text->str,
+                                                              g_strrstr (new_entry_text->str, tag_name));
+        }
 }
 
 static gboolean
@@ -2153,6 +2254,12 @@ on_key_press_event (GtkWidget    *widget,
         NautilusBatchRenameDialog *dialog;
         gchar* keyval_name;
         GdkEvent *gdk_event;
+        GString *old_entry_text;
+        GString *new_entry_text;
+        gboolean entry_has_selection;
+        gint start;
+        gint end;
+        gboolean tag_removed;
 
         gdk_event = (GdkEvent *) event;
 
@@ -2160,40 +2267,141 @@ on_key_press_event (GtkWidget    *widget,
 
         keyval_name = gdk_keyval_name (event->keyval);
 
-        if (remove_tag (dialog, ORIGINAL_FILE_NAME, keyval_name, gdk_event->key.is_modifier))
+        entry_has_selection =  (gtk_editable_get_selection_bounds (GTK_EDITABLE (dialog->name_entry),
+                                                                   &start,
+                                                                   &end));
+
+        if (event->state & GDK_CONTROL_MASK)
+                return GDK_EVENT_PROPAGATE;
+
+        if (entry_has_selection &&
+            ((g_strcmp0 (keyval_name, "Delete") == 0 || g_strcmp0 (keyval_name, "BackSpace") == 0) ||
+            (!gdk_event->key.is_modifier &&
+            g_strcmp0(keyval_name, "Left") != 0 &&
+            g_strcmp0(keyval_name, "Right") != 0 &&
+            g_strcmp0(keyval_name, "Return") != 0 &&
+            g_strcmp0 (keyval_name, "Escape") != 0 &&
+            g_strcmp0 (keyval_name, "Tab") != 0))) {
+                old_entry_text = g_string_new (gtk_entry_get_text (GTK_ENTRY (dialog->name_entry)));
+
+                update_tag_position (dialog, ORIGINAL_FILE_NAME, old_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, ORIGINAL_FILE_NAME, start, 
end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, NUMBERING, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, NUMBERING, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, NUMBERING0, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, NUMBERING0, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, NUMBERING00, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, NUMBERING00, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, CREATION_DATE, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, CREATION_DATE, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, CAMERA_MODEL, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, CAMERA_MODEL, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, TRACK_NUMBER, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, TRACK_NUMBER, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, SEASON_NUMBER, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, SEASON_NUMBER, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, EPISODE_NUMBER, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, EPISODE_NUMBER, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, ARTIST_NAME, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, ARTIST_NAME, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, TITLE, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, TITLE, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                update_tag_position (dialog, ALBUM_NAME, new_entry_text);
+                new_entry_text = remove_tag_selection (dialog, old_entry_text, ALBUM_NAME, start, end);
+                g_string_free (old_entry_text, TRUE);
+                old_entry_text = new_entry_text;
+
+                gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), new_entry_text->str);
+                g_string_free (new_entry_text, TRUE);
+
+                if (!gdk_event->key.is_modifier &&
+                    g_strcmp0(keyval_name, "Left") != 0 &&
+                    g_strcmp0(keyval_name, "Right") != 0 &&
+                    g_strcmp0(keyval_name, "Return") != 0 &&
+                    g_strcmp0 (keyval_name, "Escape") != 0)
+                        return GDK_EVENT_PROPAGATE;
                 return TRUE;
+        }
+
+        tag_removed = FALSE;
+
+        if (remove_tag (dialog, ORIGINAL_FILE_NAME, keyval_name, gdk_event->key.is_modifier))
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, NUMBERING, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, NUMBERING0, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, NUMBERING00, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, CAMERA_MODEL, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, CREATION_DATE, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, SEASON_NUMBER, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, EPISODE_NUMBER, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, TRACK_NUMBER, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, ARTIST_NAME, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
         if (remove_tag (dialog, TITLE, keyval_name, gdk_event->key.is_modifier))
-                return TRUE;
+                tag_removed = TRUE;
 
-        return FALSE;
+        if (remove_tag (dialog, ALBUM_NAME, keyval_name, gdk_event->key.is_modifier))
+                tag_removed = TRUE;
+
+        if (tag_removed) {
+                if (g_strcmp0 (keyval_name, "Delete") == 0 || g_strcmp0 (keyval_name, "BackSpace") == 0)
+                        return TRUE;
+
+                return GDK_EVENT_PROPAGATE;
+        }
+
+        return GDK_EVENT_PROPAGATE;
 }
 
 static void
@@ -2235,6 +2443,8 @@ nautilus_batch_rename_dialog_finalize (GObject *object)
                         g_string_free (metadata->track_number, TRUE);
                 if (metadata->artist_name != NULL)
                         g_string_free (metadata->artist_name, TRUE);
+                if (metadata->album_name != NULL)
+                        g_string_free (metadata->album_name, TRUE);
         }
 
         if (dialog->create_date != NULL)
@@ -2324,7 +2534,7 @@ nautilus_batch_rename_dialog_new (GList             *selection,
                 files_number++;
 
         dialog_title = g_string_new ("");
-        g_string_append_printf (dialog_title, "Renaming %d files", files_number);
+        g_string_append_printf (dialog_title, "Rename %d Files", files_number);
         gtk_window_set_title (GTK_WINDOW (dialog), dialog_title->str);
 
         nautilus_batch_rename_dialog_initialize_actions (dialog);
@@ -2332,7 +2542,7 @@ nautilus_batch_rename_dialog_new (GList             *selection,
         dialog->same_parent = !NAUTILUS_IS_SEARCH_DIRECTORY (directory);
 
         if (!dialog->same_parent)
-                dialog->distinct_parents = distinct_file_parents (dialog->selection);
+                dialog->distinct_parents = batch_rename_files_get_distinct_parents (dialog->selection);
         else
                 dialog->distinct_parents = NULL;
 
@@ -2458,6 +2668,12 @@ nautilus_batch_rename_dialog_init (NautilusBatchRenameDialog *self)
         tag_data->position = 0;
         g_hash_table_insert (self->tag_info_table, g_strdup (TITLE), tag_data);
 
+        tag_data = g_new (TagData, 1);
+        tag_data->available = FALSE;
+        tag_data->set = FALSE;
+        tag_data->position = 0;
+        g_hash_table_insert (self->tag_info_table, g_strdup (ALBUM_NAME), tag_data);
+
         gtk_entry_set_text (GTK_ENTRY (self->name_entry),ORIGINAL_FILE_NAME);
 
         self->row_height = -1;
diff --git a/src/nautilus-batch-rename-dialog.h b/src/nautilus-batch-rename-dialog.h
index c9dd45a..e1e7c3d 100644
--- a/src/nautilus-batch-rename-dialog.h
+++ b/src/nautilus-batch-rename-dialog.h
@@ -1,3 +1,20 @@
+/* nautilus-batch-rename-utilities.c
+ *
+ * Copyright (C) 2016 Alexandru Pandelea <alexandru pandelea gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #ifndef NAUTILUS_BATCH_RENAME_DIALOG_H
 #define NAUTILUS_BATCH_RENAME_DIALOG_H
@@ -20,6 +37,7 @@ G_BEGIN_DECLS
 #define TRACK_NUMBER "[Track number]"
 #define ARTIST_NAME "[Artist name]"
 #define TITLE "[Title]"
+#define ALBUM_NAME "[Album name]"
 
 typedef enum {
         NAUTILUS_BATCH_RENAME_DIALOG_APPEND = 0,
@@ -58,6 +76,7 @@ typedef struct {
         GString *track_number;
         GString *artist_name;
         GString *title;
+        GString *album_name;
 } FileMetadata;
 
 #define NAUTILUS_TYPE_BATCH_RENAME_DIALOG (nautilus_batch_rename_dialog_get_type())
@@ -72,12 +91,9 @@ void            nautilus_batch_rename_dialog_query_finished           (NautilusB
                                                                        GHashTable                *hash_table,
                                                                        GList                     
*selection_metadata);
 
-void            check_conflict_for_file                               (NautilusBatchRenameDialog *dialog,
-                                                                       NautilusDirectory         *directory,
-                                                                       GList                     *files);
-
-gint            compare_int                                           (gconstpointer              a,
-                                                                       gconstpointer              b);
+void            check_conflict_for_files                               (NautilusBatchRenameDialog *dialog,
+                                                                        NautilusDirectory         *directory,
+                                                                        GList                     *files);
 
 G_END_DECLS
 
diff --git a/src/nautilus-batch-rename-utilities.c b/src/nautilus-batch-rename-utilities.c
index a1f59bf..ae45896 100644
--- a/src/nautilus-batch-rename-utilities.c
+++ b/src/nautilus-batch-rename-utilities.c
@@ -46,11 +46,12 @@ typedef struct {
         gboolean have_track_number;
         gboolean have_artist_name;
         gboolean have_title;
+        gboolean have_album_name;
 } QueryData;
 
-static void cursor_callback (GObject      *object,
-                             GAsyncResult *result,
-                             gpointer      user_data);
+static void on_cursor_callback (GObject      *object,
+                                GAsyncResult *result,
+                                gpointer      user_data);
 
 void
 string_free (gpointer mem)
@@ -62,10 +63,10 @@ string_free (gpointer mem)
 void
 conflict_data_free (gpointer mem)
 {
-        ConflictData *data = mem;
+        ConflictData *conflict_data = mem;
 
-        g_free (data->name);
-        g_free (data);
+        g_free (conflict_data->name);
+        g_free (conflict_data);
 }
 
 static GString*
@@ -113,44 +114,44 @@ batch_rename_dialog_replace (gchar *string,
 }
 
 GString*
-batch_rename_dialog_replace_label_text (gchar       *string,
-                                        const gchar *substring)
+batch_rename_replace_label_text (gchar       *label,
+                                 const gchar *substring)
 {
-        GString *new_string;
+        GString *new_label;
         gchar **splitted_string;
         gchar *token;
         gint i, n_splits;
 
-        new_string = g_string_new ("");
+        new_label = g_string_new ("");
 
         if (substring == NULL || g_strcmp0 (substring, "") == 0) {
-                token = g_markup_escape_text (string, strlen (string));
-                new_string = g_string_append (new_string, token);
+                token = g_markup_escape_text (label, g_utf8_strlen (label, -1));
+                new_label = g_string_append (new_label, token);
                 g_free (token);
 
-                return new_string;
+                return new_label;
         }
 
-        splitted_string = g_strsplit (string, substring, -1);
+        splitted_string = g_strsplit (label, substring, -1);
         if (splitted_string == NULL) {
-                token = g_markup_escape_text (string, strlen (string));
-                new_string = g_string_append (new_string, token);
+                token = g_markup_escape_text (label, g_utf8_strlen (label, -1));
+                new_label = g_string_append (new_label, token);
                 g_free (token);
 
-                return new_string;
+                return new_label;
         }
 
         n_splits = g_strv_length (splitted_string);
 
         for (i = 0; i < n_splits; i++) {
                 token = g_markup_escape_text (splitted_string[i], strlen (splitted_string[i]));
-                new_string = g_string_append (new_string, token);
+                new_label = g_string_append (new_label, token);
 
                 g_free (token);
 
                 if (i != n_splits - 1) {
-                        token = g_markup_escape_text (substring, strlen (substring));
-                        g_string_append_printf (new_string,
+                        token = g_markup_escape_text (substring, g_utf8_strlen (substring, -1));
+                        g_string_append_printf (new_label,
                                                 "<span background=\'#f57900\' color='white'>%s</span>",
                                                 token);
 
@@ -160,7 +161,7 @@ batch_rename_dialog_replace_label_text (gchar       *string,
 
         g_strfreev (splitted_string);
 
-        return new_string;
+        return new_label;
 }
 
 static gchar*
@@ -208,6 +209,11 @@ get_metadata (GList *selection_metadata,
                             file_metadata->title != NULL &&
                             file_metadata->title->len != 0)
                                 return file_metadata->title->str;
+
+                        if (g_strcmp0 (metadata, "album_name") == 0 &&
+                            file_metadata->album_name != NULL &&
+                            file_metadata->album_name->len != 0)
+                                return file_metadata->album_name->str;
                 }
         }
 
@@ -365,6 +371,15 @@ batch_rename_dialog_format (NautilusFile *file,
                         }
                 }
 
+                if (!added_tag && g_strcmp0 (tag->str, ALBUM_NAME) == 0) {
+                        metadata = get_metadata (selection_metadata, file_name, "album_name");
+
+                        if (metadata != NULL) {
+                                new_name = g_string_append (new_name, metadata);
+                                added_tag = TRUE;
+                        }
+                }
+
                 if (!added_tag)
                         new_name = g_string_append (new_name, tag->str);
         }
@@ -417,8 +432,8 @@ batch_rename_dialog_get_new_names_list (NautilusBatchRenameDialogMode mode,
 
                 if (mode == NAUTILUS_BATCH_RENAME_DIALOG_REPLACE) {
                         new_name = batch_rename_dialog_replace (file_name->str,
-                                                         entry_text,
-                                                         replace_text);
+                                                                entry_text,
+                                                                replace_text);
                         result = g_list_prepend (result, new_name);
                 }
                 
@@ -472,7 +487,7 @@ file_name_conflicts_with_results (GList        *selection,
         return FALSE;
 }
 
-gint
+static gint
 compare_files_by_name_ascending (gconstpointer a,
                                  gconstpointer b)
 {
@@ -487,7 +502,7 @@ compare_files_by_name_ascending (gconstpointer a,
                                                FALSE, FALSE);
 }
 
-gint
+static gint
 compare_files_by_name_descending (gconstpointer a,
                                   gconstpointer b)
 {
@@ -502,7 +517,7 @@ compare_files_by_name_descending (gconstpointer a,
                                                FALSE, TRUE);
 }
 
-gint
+static gint
 compare_files_by_first_modified (gconstpointer a,
                                  gconstpointer b)
 {
@@ -517,7 +532,7 @@ compare_files_by_first_modified (gconstpointer a,
                                                FALSE, FALSE);
 }
 
-gint
+static gint
 compare_files_by_last_modified (gconstpointer a,
                                 gconstpointer b)
 {
@@ -532,7 +547,7 @@ compare_files_by_last_modified (gconstpointer a,
                                                FALSE, TRUE);
 }
 
-gint
+static gint
 compare_files_by_first_created (gconstpointer a,
                                 gconstpointer b)
 {
@@ -545,7 +560,7 @@ compare_files_by_first_created (gconstpointer a,
         return elem1->position - elem2->position;
 }
 
-gint
+static gint
 compare_files_by_last_created (gconstpointer a,
                                gconstpointer b)
 {
@@ -620,24 +635,24 @@ nautilus_batch_rename_dialog_sort (GList       *selection,
 }
 
 static void
-cursor_next (QueryData           *data,
+cursor_next (QueryData           *query_data,
              TrackerSparqlCursor *cursor)
 {
         tracker_sparql_cursor_next_async (cursor,
                                           NULL,
-                                          cursor_callback,
-                                          data);
+                                          on_cursor_callback,
+                                          query_data);
 }
 
 static void
-cursor_callback (GObject      *object,
-                 GAsyncResult *result,
-                 gpointer      user_data)
+on_cursor_callback (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
 {
         GHashTable *hash_table;
         TrackerSparqlCursor *cursor;
         gboolean success;
-        QueryData *data;
+        QueryData *query_data;
         GError *error;
         GList *l;
         FileMetadata *metadata;
@@ -650,20 +665,23 @@ cursor_callback (GObject      *object,
         const gchar *track_number;
         const gchar *artist_name;
         const gchar *title;
+        const gchar *album_name;
 
         error = NULL;
         metadata = NULL;
 
         cursor = TRACKER_SPARQL_CURSOR (object);
-        data = user_data;
-        hash_table = data->hash_table;
+        query_data = user_data;
+        hash_table = query_data->hash_table;
 
         success = tracker_sparql_cursor_next_finish (cursor, result, &error);
         if (!success) {
                 g_clear_error (&error);
                 g_clear_object (&cursor);
 
-                nautilus_batch_rename_dialog_query_finished (data->dialog, data->hash_table, 
data->selection_metadata);
+                nautilus_batch_rename_dialog_query_finished (query_data->dialog,
+                                                             query_data->hash_table,
+                                                             query_data->selection_metadata);
 
                 return;
         }
@@ -675,23 +693,24 @@ cursor_callback (GObject      *object,
         track_number = tracker_sparql_cursor_get_string (cursor, 5, NULL);
         artist_name = tracker_sparql_cursor_get_string (cursor, 6, NULL);
         title = tracker_sparql_cursor_get_string (cursor, 7, NULL);
+        album_name = tracker_sparql_cursor_get_string (cursor, 8, NULL);
 
         /* creation date used for sorting criteria */
         if (creation_date == NULL) {
                 if (hash_table != NULL)
                         g_hash_table_destroy (hash_table);
 
-                data->hash_table = NULL;
-                data->have_creation_date = FALSE;
+                query_data->hash_table = NULL;
+                query_data->have_creation_date = FALSE;
         } else {
-                if (data->have_creation_date){
+                if (query_data->have_creation_date){
                         g_hash_table_insert (hash_table,
                         g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)),
                         GINT_TO_POINTER (g_hash_table_size (hash_table)));
                 }
         }
         file_name = tracker_sparql_cursor_get_string (cursor, 0, NULL);
-        for (l = data->selection_metadata; l != NULL; l = l->next) {
+        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                 metadata = l->data;
 
                 if (g_strcmp0 (file_name, metadata->file_name->str) == 0)
@@ -700,11 +719,11 @@ cursor_callback (GObject      *object,
 
         /* Metadata to be used in file name
          * creation date */
-        if (data->have_creation_date) {
+        if (query_data->have_creation_date) {
                 if (creation_date == NULL) {
-                        data->have_creation_date = FALSE;
+                        query_data->have_creation_date = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->creation_date, TRUE);
@@ -717,11 +736,11 @@ cursor_callback (GObject      *object,
         }
 
         /* equipment */
-        if (data->have_equipment) {
+        if (query_data->have_equipment) {
                 if (equipment == NULL) {
-                        data->have_equipment = FALSE;
+                        query_data->have_equipment = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->equipment, TRUE);
@@ -734,11 +753,11 @@ cursor_callback (GObject      *object,
         }
 
         /* season number */
-        if (data->have_season) {
+        if (query_data->have_season) {
                 if (season_number == NULL) {
-                        data->have_season = FALSE;
+                        query_data->have_season = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->season, TRUE);
@@ -751,11 +770,11 @@ cursor_callback (GObject      *object,
         }
 
         /* episode number */
-        if (data->have_episode_number) {
+        if (query_data->have_episode_number) {
                 if (episode_number == NULL) {
-                        data->have_episode_number = FALSE;
+                        query_data->have_episode_number = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->episode_number, TRUE);
@@ -768,10 +787,10 @@ cursor_callback (GObject      *object,
         }
 
         /* track number */
-        if (data->have_track_number) {
+        if (query_data->have_track_number) {
                 if (track_number == NULL) {
-                        data->have_track_number = FALSE;
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        query_data->have_track_number = FALSE;
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->track_number, TRUE);
@@ -784,11 +803,11 @@ cursor_callback (GObject      *object,
         }
 
         /* artist name */
-        if (data->have_artist_name) {
+        if (query_data->have_artist_name) {
                 if (artist_name == NULL) {
-                        data->have_artist_name = FALSE;
+                        query_data->have_artist_name = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->artist_name, TRUE);
@@ -801,11 +820,11 @@ cursor_callback (GObject      *object,
         }
 
         /* title */
-        if (data->have_title) {
+        if (query_data->have_title) {
                 if (title == NULL) {
-                        data->have_title = FALSE;
+                        query_data->have_title = FALSE;
 
-                        for (l = data->selection_metadata; l != NULL; l = l->next) {
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
                                 metadata_clear = l->data;
 
                                 g_string_free (metadata_clear->title, TRUE);
@@ -817,8 +836,25 @@ cursor_callback (GObject      *object,
                 }
         }
 
+        /* album name */
+        if (query_data->have_album_name) {
+                if (album_name == NULL) {
+                        query_data->have_album_name = FALSE;
+
+                        for (l = query_data->selection_metadata; l != NULL; l = l->next) {
+                                metadata_clear = l->data;
+
+                                g_string_free (metadata_clear->album_name, TRUE);
+                                metadata_clear->album_name = NULL;
+                        }
+                } else {
+                        g_string_append (metadata->album_name,
+                                         album_name);
+                }
+        }
+
         /* Get next */
-        cursor_next (data, cursor);
+        cursor_next (query_data, cursor);
 }
 
 static void
@@ -828,26 +864,27 @@ batch_rename_dialog_query_callback (GObject      *object,
 {
         TrackerSparqlConnection *connection;
         TrackerSparqlCursor *cursor;
-        QueryData *data;
+        QueryData *query_data;
         GError *error;
 
         error = NULL;
 
         connection = TRACKER_SPARQL_CONNECTION (object);
-        data = user_data;
+        query_data = user_data;
 
         cursor = tracker_sparql_connection_query_finish (connection,
                                                          result,
                                                          &error);
 
         if (error != NULL) {
+                g_warning ("Error on batch rename query for metadata");
                 g_error_free (error);
 
-                nautilus_batch_rename_dialog_query_finished (data->dialog,
-                                                             data->hash_table,
-                                                             data->selection_metadata);
+                nautilus_batch_rename_dialog_query_finished (query_data->dialog,
+                                                             query_data->hash_table,
+                                                             query_data->selection_metadata);
         } else {
-                cursor_next (data, cursor);
+                cursor_next (query_data, cursor);
         }
 }
 
@@ -861,7 +898,7 @@ check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
         GList *l;
         NautilusFile *file;
         GError *error;
-        QueryData *data;
+        QueryData *query_data;
         gchar *file_name;
         FileMetadata *metadata;
         GList *selection_metadata;
@@ -878,6 +915,7 @@ check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
                               "nmm:trackNumber(?file) "
                               "nmm:artistName(nmm:performer(?file)) "
                               "nie:title(?file) "
+                              "nmm:albumTitle(nmm:musicAlbum(?file)) "
                               "WHERE { ?file a nfo:FileDataObject. ");
 
         g_string_append_printf (query,
@@ -906,6 +944,7 @@ check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
                 metadata->track_number = g_string_new ("");
                 metadata->artist_name = g_string_new ("");
                 metadata->title = g_string_new ("");
+                metadata->album_name = g_string_new ("");
 
                 selection_metadata = g_list_append (selection_metadata, metadata);
 
@@ -926,32 +965,33 @@ check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
                                             (GDestroyNotify) g_free,
                                             NULL);
 
-        data = g_new (QueryData, 1);
-        data->hash_table = hash_table;
-        data->dialog = dialog;
-        data->selection_metadata = selection_metadata;
+        query_data = g_new (QueryData, 1);
+        query_data->hash_table = hash_table;
+        query_data->dialog = dialog;
+        query_data->selection_metadata = selection_metadata;
 
-        data->have_season = TRUE;
-        data->have_creation_date = TRUE;
-        data->have_artist_name = TRUE;
-        data->have_track_number = TRUE;
-        data->have_equipment = TRUE;
-        data->have_episode_number = TRUE;
-        data->have_title = TRUE;
+        query_data->have_season = TRUE;
+        query_data->have_creation_date = TRUE;
+        query_data->have_artist_name = TRUE;
+        query_data->have_track_number = TRUE;
+        query_data->have_equipment = TRUE;
+        query_data->have_episode_number = TRUE;
+        query_data->have_title = TRUE;
+        query_data->have_album_name = TRUE;
 
         /* Make an asynchronous query to the store */
         tracker_sparql_connection_query_async (connection,
                                                query->str,
                                                NULL,
                                                batch_rename_dialog_query_callback,
-                                               data);
+                                               query_data);
 
         g_object_unref (connection);
         g_string_free (query, TRUE);
 }
 
 GList*
-distinct_file_parents (GList *selection)
+batch_rename_files_get_distinct_parents (GList *selection)
 {
         GList *result;
         GList *l1;
diff --git a/src/nautilus-batch-rename-utilities.h b/src/nautilus-batch-rename-utilities.h
index 5520890..e343b25 100644
--- a/src/nautilus-batch-rename-utilities.h
+++ b/src/nautilus-batch-rename-utilities.h
@@ -1,3 +1,21 @@
+/* nautilus-batch-rename-utilities.c
+ *
+ * Copyright (C) 2016 Alexandru Pandelea <alexandru pandelea gmail com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #ifndef NAUTILUS_BATCH_RENAME_UTILITIES_H
 #define NAUTILUS_BATCH_RENAME_UTILITIES_H
 
@@ -23,24 +41,6 @@ GList* nautilus_batch_rename_dialog_sort        (GList                       *se
                                                  SortingMode                  mode,
                                                  GHashTable                  *creation_date_table);
 
-gint compare_files_by_last_modified             (gconstpointer a,
-                                                 gconstpointer b);
-
-gint compare_files_by_first_modified            (gconstpointer a,
-                                                 gconstpointer b);
-
-gint compare_files_by_name_descending           (gconstpointer a,
-                                                 gconstpointer b);
-
-gint compare_files_by_name_ascending            (gconstpointer a,
-                                                 gconstpointer b);
-
-gint compare_files_by_first_created             (gconstpointer a,
-                                                 gconstpointer b);
-
-gint compare_files_by_last_created              (gconstpointer a,
-                                                 gconstpointer b);
-
 void check_metadata_for_selection               (NautilusBatchRenameDialog *dialog,
                                                  GList                     *selection);
 
@@ -50,14 +50,14 @@ void string_free                                (gpointer mem);
 
 void conflict_data_free                         (gpointer mem);
 
-GList* distinct_file_parents                    (GList *selection);
+GList* batch_rename_files_get_distinct_parents  (GList *selection);
 
 gboolean file_name_conflicts_with_results       (GList        *selection,
                                                  GList        *new_names,
                                                  GString      *old_name,
                                                  gchar        *parent_uri);
 
-GString* batch_rename_dialog_replace_label_text        (gchar             *string,
-                                                        const gchar       *substr);
+GString* batch_rename_replace_label_text        (gchar             *label,
+                                                 const gchar       *substr);
 
 #endif /* NAUTILUS_BATCH_RENAME_UTILITIES_H */
\ No newline at end of file
diff --git a/src/nautilus-file-undo-operations.c b/src/nautilus-file-undo-operations.c
index 0bcf281..623f433 100644
--- a/src/nautilus-file-undo-operations.c
+++ b/src/nautilus-file-undo-operations.c
@@ -1014,6 +1014,19 @@ batch_rename_redo_func (NautilusFileUndoInfo *info,
         GList *l, *files;
         NautilusFile *file;
         GFile *old_file;
+        GFile *new_file;
+        GList *l1;
+        GList *l2;
+        GList *l3;
+        GList *l4;
+        GList *l5;
+        GList *l6;
+        GList *l7;
+        gchar *file_name;
+        gchar *old_file_name;
+        GString *new_file_name;
+        GString *new_name;
+        GString *old_name;
 
         files = NULL;
 
@@ -1024,6 +1037,45 @@ batch_rename_redo_func (NautilusFileUndoInfo *info,
                 files = g_list_append (files, file);
         }
 
+        for (l1 = self->priv->new_display_names, l2 = files; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = 
l2->next) {
+                old_file_name = nautilus_file_get_name (NAUTILUS_FILE (l2->data));
+                new_file_name = l1->data;
+
+                for (l3 = files, l4 = self->priv->new_display_names, l5 = self->priv->old_display_names, l6 
= self->priv->old_files, l7 = self->priv->new_files;
+                     l3 != NULL && l4 != NULL && l5 != NULL && l6 != NULL && l7 != NULL;
+                     l3 = l3->next, l4 = l4->next, l5 = l5->next, l6 = l6->next, l7 = l7->next) {
+                        file_name = nautilus_file_get_name (NAUTILUS_FILE (l3->data));
+                        if (l3 != l2 && g_strcmp0 (file_name, new_file_name->str) == 0) {
+
+                                file = NAUTILUS_FILE (l3->data);
+                                new_name = l4->data;
+                                old_name = l5->data;
+                                old_file = l6->data;
+                                new_file = l7->data;
+
+                                files = g_list_remove_link (files, l3);
+                                self->priv->new_display_names = g_list_remove_link 
(self->priv->new_display_names, l4);
+                                self->priv->old_display_names = g_list_remove_link 
(self->priv->old_display_names, l5);
+                                self->priv->old_files = g_list_remove_link (self->priv->old_files, l6);
+                                self->priv->new_files = g_list_remove_link (self->priv->new_files, l7);
+
+                                files = g_list_prepend (files, file);
+                                self->priv->new_display_names = g_list_prepend 
(self->priv->new_display_names, new_name);
+                                self->priv->old_display_names = g_list_prepend 
(self->priv->old_display_names, old_name);
+                                self->priv->old_files = g_list_prepend (self->priv->old_files, old_file);
+                                self->priv->new_files = g_list_prepend (self->priv->new_files, new_file);
+
+                                g_free (file_name);
+
+                                break;
+                        }
+
+                        g_free (file_name);
+                }
+
+                g_free (old_file_name);
+        }
+
         nautilus_file_batch_rename (files, self->priv->new_display_names, file_undo_info_operation_callback, 
self);
 }
 
@@ -1036,6 +1088,19 @@ batch_rename_undo_func (NautilusFileUndoInfo *info,
         GList *l, *files;
         NautilusFile *file;
         GFile *new_file;
+        GFile *old_file;
+        GList *l1;
+        GList *l2;
+        GList *l3;
+        GList *l4;
+        GList *l5;
+        GList *l6;
+        GList *l7;
+        gchar *file_name;
+        gchar *old_file_name;
+        GString *new_file_name;
+        GString *new_name;
+        GString *old_name;
 
         files = NULL;
 
@@ -1046,6 +1111,44 @@ batch_rename_undo_func (NautilusFileUndoInfo *info,
                 files = g_list_append (files, file);
         }
 
+        for (l1 = self->priv->old_display_names, l2 = files; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = 
l2->next) {
+                old_file_name = nautilus_file_get_name (NAUTILUS_FILE (l2->data));
+                new_file_name = l1->data;
+
+                for (l3 = files, l4 = self->priv->old_display_names, l5 = self->priv->new_display_names, l6 
= self->priv->old_files, l7 = self->priv->new_files;
+                     l3 != NULL && l4 != NULL && l5 != NULL && l6 != NULL && l7 != NULL;
+                     l3 = l3->next, l4 = l4->next, l5 = l5->next, l6 = l6->next, l7 = l7->next) {
+                        file_name = nautilus_file_get_name (NAUTILUS_FILE (l3->data));
+                        if (l3 != l2 && g_strcmp0 (file_name, new_file_name->str) == 0) {
+                                file = NAUTILUS_FILE (l3->data);
+                                new_name = l4->data;
+                                old_name = l5->data;
+                                old_file = l6->data;
+                                new_file = l7->data;
+
+                                files = g_list_remove_link (files, l3);
+                                self->priv->old_display_names = g_list_remove_link 
(self->priv->old_display_names, l4);
+                                self->priv->new_display_names = g_list_remove_link 
(self->priv->new_display_names, l5);
+                                self->priv->old_files = g_list_remove_link (self->priv->old_files, l6);
+                                self->priv->new_files = g_list_remove_link (self->priv->new_files, l7);
+
+                                files = g_list_prepend (files, file);
+                                self->priv->old_display_names = g_list_prepend 
(self->priv->old_display_names, new_name);
+                                self->priv->new_display_names = g_list_prepend 
(self->priv->new_display_names, old_name);
+                                self->priv->old_files = g_list_prepend (self->priv->old_files, old_file);
+                                self->priv->new_files = g_list_prepend (self->priv->new_files, new_file);
+
+                                g_free (file_name);
+
+                                break;
+                        }
+
+                        g_free (file_name);
+                }
+
+                g_free (old_file_name);
+        }
+
         nautilus_file_batch_rename (files, self->priv->old_display_names, file_undo_info_operation_callback, 
self);
 }
 
diff --git a/src/nautilus-file.c b/src/nautilus-file.c
index b7927eb..c137dbc 100644
--- a/src/nautilus-file.c
+++ b/src/nautilus-file.c
@@ -1704,9 +1704,8 @@ nautilus_file_operation_complete (NautilusFileOperation *op,
         if (op->files == NULL)
                 nautilus_file_changed (op->file);
 
-       if (op->callback) {
+       if (op->callback)
                (* op->callback) (op->file, result_file, error, op->callback_data);
-       }
 
        if (error != NULL) {
                g_clear_object (&op->undo_info);
@@ -2105,6 +2104,7 @@ real_batch_rename (GList                         *files,
                                          data);
 
                 if (error != NULL) {
+                        g_warning ("Batch rename for file \"%s\" failed", nautilus_file_get_name (file));
                         g_error_free (error);
                         error = NULL;
                 }
diff --git a/src/resources/css/Adwaita.css b/src/resources/css/Adwaita.css
index ac97aa5..cb258a3 100644
--- a/src/resources/css/Adwaita.css
+++ b/src/resources/css/Adwaita.css
@@ -174,6 +174,7 @@ searchbar { border-top: 1px solid @borders; }
 
 .conflict-row {
     background: @conflict_bg;
+    color: black;
 }
 
 .conflict-row:hover {
diff --git a/src/resources/ui/nautilus-batch-rename-dialog.ui 
b/src/resources/ui/nautilus-batch-rename-dialog.ui
index bacce60..4e2de2f 100644
--- a/src/resources/ui/nautilus-batch-rename-dialog.ui
+++ b/src/resources/ui/nautilus-batch-rename-dialog.ui
@@ -3,6 +3,7 @@
   <template class="NautilusBatchRenameDialog" parent="GtkDialog">
     <property name="resizable">False</property>
     <property name="modal">True</property>
+    <property name="height-request">563</property>
     <property name="window_position">center-on-parent</property>
     <property name="destroy_with_parent">True</property>
     <signal name="response" handler="batch_rename_dialog_on_response"/>
@@ -49,7 +50,7 @@
                 <property name="margin">20</property>
                 <child>
                   <object class="GtkRadioButton" id="format_mode_button">
-                    <property name="label" translatable="yes">_Format mode</property>
+                    <property name="label" translatable="yes">Rename _using a template</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="receives_default">False</property>
@@ -289,7 +290,7 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="hexpand">False</property>
-                <property name="vexpand">False</property>
+                <property name="vexpand">True</property>
                 <property name="shadow_type">in</property>
                 <child>
                   <object class="GtkViewport">
@@ -446,6 +447,11 @@
         <attribute name="action">dialog.add-title-tag</attribute>
         <attribute name="hidden-when">action-disabled</attribute>
       </item>
+      <item>
+        <attribute name="label" translatable="yes">Album Name</attribute>
+        <attribute name="action">dialog.add-album-name-tag</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
     </section>
     <section>
       <item>


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