summaryrefslogtreecommitdiffstats
path: root/src/nautilus-batch-rename-utilities.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nautilus-batch-rename-utilities.c')
-rw-r--r--src/nautilus-batch-rename-utilities.c1180
1 files changed, 1180 insertions, 0 deletions
diff --git a/src/nautilus-batch-rename-utilities.c b/src/nautilus-batch-rename-utilities.c
new file mode 100644
index 0000000..49b9813
--- /dev/null
+++ b/src/nautilus-batch-rename-utilities.c
@@ -0,0 +1,1180 @@
+/* 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/>.
+ */
+
+#include "nautilus-batch-rename-dialog.h"
+#include "nautilus-batch-rename-utilities.h"
+#include "nautilus-file.h"
+#include "nautilus-tracker-utilities.h"
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <stdarg.h>
+#include <eel/eel-vfs-extensions.h>
+
+typedef struct
+{
+ NautilusFile *file;
+ gint position;
+} CreateDateElem;
+
+typedef struct
+{
+ NautilusBatchRenameDialog *dialog;
+ GHashTable *date_order_hash_table;
+
+ GList *selection_metadata;
+
+ gboolean has_metadata[G_N_ELEMENTS (metadata_tags_constants)];
+
+ GCancellable *cancellable;
+} QueryData;
+
+enum
+{
+ FILE_NAME_INDEX,
+ CREATION_DATE_INDEX,
+ YEAR_INDEX,
+ MONTH_INDEX,
+ DAY_INDEX,
+ HOURS_INDEX,
+ MINUTES_INDEX,
+ SECONDS_INDEX,
+ CAMERA_MODEL_INDEX,
+ SEASON_INDEX,
+ EPISODE_NUMBER_INDEX,
+ TRACK_NUMBER_INDEX,
+ ARTIST_NAME_INDEX,
+ TITLE_INDEX,
+ ALBUM_NAME_INDEX,
+} QueryMetadata;
+
+static void on_cursor_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data);
+
+void
+string_free (gpointer mem)
+{
+ if (mem != NULL)
+ {
+ g_string_free (mem, TRUE);
+ }
+}
+
+void
+conflict_data_free (gpointer mem)
+{
+ ConflictData *conflict_data = mem;
+
+ g_free (conflict_data->name);
+ g_free (conflict_data);
+}
+
+gchar *
+batch_rename_get_tag_text_representation (TagConstants tag_constants)
+{
+ return g_strdup_printf ("[%s]", gettext (tag_constants.label));
+}
+
+static GString *
+batch_rename_replace (gchar *string,
+ gchar *substring,
+ gchar *replacement)
+{
+ GString *new_string;
+ gchar **splitted_string;
+ gint i, n_splits;
+
+ new_string = g_string_new ("");
+
+ if (substring == NULL || replacement == NULL)
+ {
+ g_string_append (new_string, string);
+
+ return new_string;
+ }
+
+ if (g_utf8_strlen (substring, -1) == 0)
+ {
+ g_string_append (new_string, string);
+
+ return new_string;
+ }
+
+ splitted_string = g_strsplit (string, substring, -1);
+ if (splitted_string == NULL)
+ {
+ g_string_append (new_string, string);
+
+ return new_string;
+ }
+
+ n_splits = g_strv_length (splitted_string);
+
+ for (i = 0; i < n_splits; i++)
+ {
+ g_string_append (new_string, splitted_string[i]);
+
+ if (i != n_splits - 1)
+ {
+ g_string_append (new_string, replacement);
+ }
+ }
+
+ g_strfreev (splitted_string);
+
+ return new_string;
+}
+
+void
+batch_rename_sort_lists_for_rename (GList **selection,
+ GList **new_names,
+ GList **old_names,
+ GList **new_files,
+ GList **old_files,
+ gboolean is_undo_redo)
+{
+ GList *new_names_list;
+ GList *new_names_list2;
+ GList *files;
+ GList *files2;
+ GList *old_names_list = NULL;
+ GList *new_files_list = NULL;
+ GList *old_files_list = NULL;
+ GList *old_names_list2 = NULL;
+ GList *new_files_list2 = NULL;
+ GList *old_files_list2 = NULL;
+ GString *new_file_name;
+ GString *new_name;
+ GString *old_name;
+ GFile *new_file;
+ GFile *old_file;
+ NautilusFile *file;
+ gboolean order_changed = TRUE;
+
+ /* in the following case:
+ * file1 -> file2
+ * file2 -> file3
+ * file2 must be renamed first, so because of that, the list has to be reordered
+ */
+ while (order_changed)
+ {
+ order_changed = FALSE;
+
+ if (is_undo_redo)
+ {
+ old_names_list = *old_names;
+ new_files_list = *new_files;
+ old_files_list = *old_files;
+ }
+
+ for (new_names_list = *new_names, files = *selection;
+ new_names_list != NULL && files != NULL;
+ new_names_list = new_names_list->next, files = files->next)
+ {
+ g_autofree gchar *old_file_name = NULL;
+
+ old_file_name = nautilus_file_get_name (NAUTILUS_FILE (files->data));
+ new_file_name = new_names_list->data;
+
+ if (is_undo_redo)
+ {
+ old_names_list2 = old_names_list;
+ new_files_list2 = new_files_list;
+ old_files_list2 = old_files_list;
+ }
+
+ for (files2 = files, new_names_list2 = new_names_list;
+ files2 != NULL && new_names_list2 != NULL;
+ files2 = files2->next, new_names_list2 = new_names_list2->next)
+ {
+ g_autofree gchar *file_name = NULL;
+
+ file_name = nautilus_file_get_name (NAUTILUS_FILE (files2->data));
+ new_name = new_names_list2->data;
+
+ if (files2 != files && g_strcmp0 (file_name, new_file_name->str) == 0)
+ {
+ file = NAUTILUS_FILE (files2->data);
+
+ *selection = g_list_remove_link (*selection, files2);
+ *new_names = g_list_remove_link (*new_names, new_names_list2);
+
+ *selection = g_list_prepend (*selection, file);
+ *new_names = g_list_prepend (*new_names, new_name);
+
+ if (is_undo_redo)
+ {
+ old_name = old_names_list2->data;
+ new_file = new_files_list2->data;
+ old_file = old_files_list2->data;
+
+ *old_names = g_list_remove_link (*old_names, old_names_list2);
+ *new_files = g_list_remove_link (*new_files, new_files_list2);
+ *old_files = g_list_remove_link (*old_files, old_files_list2);
+
+ *old_names = g_list_prepend (*old_names, old_name);
+ *new_files = g_list_prepend (*new_files, new_file);
+ *old_files = g_list_prepend (*old_files, old_file);
+ }
+
+ order_changed = TRUE;
+ break;
+ }
+
+ if (is_undo_redo)
+ {
+ old_names_list2 = old_names_list2->next;
+ new_files_list2 = new_files_list2->next;
+ old_files_list2 = old_files_list2->next;
+ }
+ }
+
+ if (is_undo_redo)
+ {
+ old_names_list = old_names_list->next;
+ new_files_list = new_files_list->next;
+ old_files_list = old_files_list->next;
+ }
+ }
+ }
+}
+
+/* This function changes the background color of the replaced part of the name */
+GString *
+batch_rename_replace_label_text (gchar *label,
+ const gchar *substring)
+{
+ GString *new_label;
+ gchar **splitted_string;
+ gchar *token;
+ gint i, n_splits;
+
+ new_label = g_string_new ("");
+
+ if (substring == NULL || g_strcmp0 (substring, "") == 0)
+ {
+ token = g_markup_escape_text (label, -1);
+ new_label = g_string_append (new_label, token);
+ g_free (token);
+
+ return new_label;
+ }
+
+ splitted_string = g_strsplit (label, substring, -1);
+ if (splitted_string == NULL)
+ {
+ token = g_markup_escape_text (label, -1);
+ new_label = g_string_append (new_label, token);
+ g_free (token);
+
+ 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], -1);
+ new_label = g_string_append (new_label, token);
+
+ g_free (token);
+
+ if (i != n_splits - 1)
+ {
+ token = g_markup_escape_text (substring, -1);
+ g_string_append_printf (new_label,
+ "<span background=\'#f57900\' color='white'>%s</span>",
+ token);
+
+ g_free (token);
+ }
+ }
+
+ g_strfreev (splitted_string);
+
+ return new_label;
+}
+
+static gchar *
+get_metadata (GList *selection_metadata,
+ gchar *file_name,
+ MetadataType metadata_type)
+{
+ GList *l;
+ FileMetadata *file_metadata;
+ gchar *metadata = NULL;
+
+ for (l = selection_metadata; l != NULL; l = l->next)
+ {
+ file_metadata = l->data;
+ if (g_strcmp0 (file_name, file_metadata->file_name->str) == 0)
+ {
+ if (file_metadata->metadata[metadata_type] &&
+ file_metadata->metadata[metadata_type]->len > 0)
+ {
+ metadata = file_metadata->metadata[metadata_type]->str;
+ }
+
+ break;
+ }
+ }
+
+ return metadata;
+}
+
+static GString *
+batch_rename_format (NautilusFile *file,
+ GList *text_chunks,
+ GList *selection_metadata,
+ gint count)
+{
+ GList *l;
+ GString *tag_string;
+ GString *new_name;
+ gboolean added_tag;
+ MetadataType metadata_type;
+ g_autofree gchar *file_name = NULL;
+ g_autofree gchar *extension = NULL;
+ gint i;
+ gchar *metadata;
+
+ file_name = nautilus_file_get_display_name (file);
+ if (!nautilus_file_is_directory (file))
+ {
+ extension = nautilus_file_get_extension (file);
+ }
+
+ new_name = g_string_new ("");
+
+ for (l = text_chunks; l != NULL; l = l->next)
+ {
+ added_tag = FALSE;
+ tag_string = l->data;
+
+ for (i = 0; i < G_N_ELEMENTS (numbering_tags_constants); i++)
+ {
+ g_autofree gchar *tag_text_representation = NULL;
+
+ tag_text_representation = batch_rename_get_tag_text_representation (numbering_tags_constants[i]);
+ if (g_strcmp0 (tag_string->str, tag_text_representation) == 0)
+ {
+ switch (numbering_tags_constants[i].numbering_type)
+ {
+ case NUMBERING_NO_ZERO_PAD:
+ {
+ g_string_append_printf (new_name, "%d", count);
+ }
+ break;
+
+ case NUMBERING_ONE_ZERO_PAD:
+ {
+ g_string_append_printf (new_name, "%02d", count);
+ }
+ break;
+
+ case NUMBERING_TWO_ZERO_PAD:
+ {
+ g_string_append_printf (new_name, "%03d", count);
+ }
+ break;
+
+ default:
+ {
+ g_warn_if_reached ();
+ }
+ break;
+ }
+
+ added_tag = TRUE;
+ break;
+ }
+ }
+
+ if (added_tag)
+ {
+ continue;
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (metadata_tags_constants); i++)
+ {
+ g_autofree gchar *tag_text_representation = NULL;
+
+ tag_text_representation = batch_rename_get_tag_text_representation (metadata_tags_constants[i]);
+ if (g_strcmp0 (tag_string->str, tag_text_representation) == 0)
+ {
+ metadata_type = metadata_tags_constants[i].metadata_type;
+ metadata = get_metadata (selection_metadata, file_name, metadata_type);
+
+ /* TODO: This is a hack, we should provide a cancellable for checking
+ * the metadata, and if that is happening don't enter here. We can
+ * special case original file name upper in the call stack */
+ if (!metadata && metadata_type != ORIGINAL_FILE_NAME)
+ {
+ g_warning ("Metadata not present in one file, it shouldn't have been added. File name: %s, Metadata: %s",
+ file_name, metadata_tags_constants[i].label);
+ continue;
+ }
+
+ switch (metadata_type)
+ {
+ case ORIGINAL_FILE_NAME:
+ {
+ if (nautilus_file_is_directory (file))
+ {
+ new_name = g_string_append (new_name, file_name);
+ }
+ else
+ {
+ g_autofree gchar *base_name = NULL;
+ base_name = eel_filename_strip_extension (file_name);
+ new_name = g_string_append (new_name, base_name);
+ }
+ }
+ break;
+
+ case TRACK_NUMBER:
+ {
+ g_string_append_printf (new_name, "%02d", atoi (metadata));
+ }
+ break;
+
+ default:
+ {
+ new_name = g_string_append (new_name, metadata);
+ }
+ break;
+ }
+
+ added_tag = TRUE;
+ break;
+ }
+ }
+
+ if (!added_tag)
+ {
+ new_name = g_string_append (new_name, tag_string->str);
+ }
+ }
+
+ if (g_strcmp0 (new_name->str, "") == 0)
+ {
+ new_name = g_string_append (new_name, file_name);
+ }
+ else
+ {
+ if (extension != NULL)
+ {
+ new_name = g_string_append (new_name, extension);
+ }
+ }
+
+ return new_name;
+}
+
+GList *
+batch_rename_dialog_get_new_names_list (NautilusBatchRenameDialogMode mode,
+ GList *selection,
+ GList *text_chunks,
+ GList *selection_metadata,
+ gchar *entry_text,
+ gchar *replace_text)
+{
+ GList *l;
+ GList *result;
+ GString *file_name;
+ GString *new_name;
+ NautilusFile *file;
+ gchar *name;
+ gint count;
+
+ result = NULL;
+ count = 1;
+
+ for (l = selection; l != NULL; l = l->next)
+ {
+ file = NAUTILUS_FILE (l->data);
+
+ name = nautilus_file_get_name (file);
+ file_name = g_string_new (name);
+
+ /* get the new name here and add it to the list*/
+ if (mode == NAUTILUS_BATCH_RENAME_DIALOG_FORMAT)
+ {
+ new_name = batch_rename_format (file,
+ text_chunks,
+ selection_metadata,
+ count++);
+ result = g_list_prepend (result, new_name);
+ }
+
+ if (mode == NAUTILUS_BATCH_RENAME_DIALOG_REPLACE)
+ {
+ new_name = batch_rename_replace (file_name->str,
+ entry_text,
+ replace_text);
+ result = g_list_prepend (result, new_name);
+ }
+
+ g_string_free (file_name, TRUE);
+ g_free (name);
+ }
+
+ return result;
+}
+
+/* There is a case that a new name for a file conflicts with an existing file name
+ * in the directory but it's not a problem because the file in the directory that
+ * conflicts is part of the batch renaming selection and it's going to change the name anyway. */
+gboolean
+file_name_conflicts_with_results (GList *selection,
+ GList *new_names,
+ GString *old_name,
+ gchar *parent_uri)
+{
+ GList *l1;
+ GList *l2;
+ NautilusFile *selection_file;
+ GString *new_name;
+
+ for (l1 = selection, l2 = new_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next)
+ {
+ g_autofree gchar *name1 = NULL;
+ g_autofree gchar *selection_parent_uri = NULL;
+
+ selection_file = NAUTILUS_FILE (l1->data);
+ name1 = nautilus_file_get_name (selection_file);
+
+ selection_parent_uri = nautilus_file_get_parent_uri (selection_file);
+
+ if (g_strcmp0 (name1, old_name->str) == 0)
+ {
+ new_name = l2->data;
+
+ /* if the name didn't change, then there's a conflict */
+ if (g_string_equal (old_name, new_name) &&
+ (parent_uri == NULL || g_strcmp0 (parent_uri, selection_parent_uri) == 0))
+ {
+ return FALSE;
+ }
+
+
+ /* if this file exists and it changed it's name, then there's no
+ * conflict */
+ return TRUE;
+ }
+ }
+
+ /* the case this function searched for doesn't exist, so the file
+ * has a conlfict */
+ return FALSE;
+}
+
+static gint
+compare_files_by_name_ascending (gconstpointer a,
+ gconstpointer b)
+{
+ NautilusFile *file1;
+ NautilusFile *file2;
+
+ file1 = NAUTILUS_FILE (a);
+ file2 = NAUTILUS_FILE (b);
+
+ return nautilus_file_compare_for_sort (file1, file2,
+ NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+ FALSE, FALSE);
+}
+
+static gint
+compare_files_by_name_descending (gconstpointer a,
+ gconstpointer b)
+{
+ NautilusFile *file1;
+ NautilusFile *file2;
+
+ file1 = NAUTILUS_FILE (a);
+ file2 = NAUTILUS_FILE (b);
+
+ return nautilus_file_compare_for_sort (file1, file2,
+ NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
+ FALSE, TRUE);
+}
+
+static gint
+compare_files_by_first_modified (gconstpointer a,
+ gconstpointer b)
+{
+ NautilusFile *file1;
+ NautilusFile *file2;
+
+ file1 = NAUTILUS_FILE (a);
+ file2 = NAUTILUS_FILE (b);
+
+ return nautilus_file_compare_for_sort (file1, file2,
+ NAUTILUS_FILE_SORT_BY_MTIME,
+ FALSE, FALSE);
+}
+
+static gint
+compare_files_by_last_modified (gconstpointer a,
+ gconstpointer b)
+{
+ NautilusFile *file1;
+ NautilusFile *file2;
+
+ file1 = NAUTILUS_FILE (a);
+ file2 = NAUTILUS_FILE (b);
+
+ return nautilus_file_compare_for_sort (file1, file2,
+ NAUTILUS_FILE_SORT_BY_MTIME,
+ FALSE, TRUE);
+}
+
+static gint
+compare_files_by_first_created (gconstpointer a,
+ gconstpointer b)
+{
+ CreateDateElem *elem1;
+ CreateDateElem *elem2;
+
+ elem1 = (CreateDateElem *) a;
+ elem2 = (CreateDateElem *) b;
+
+ return elem1->position - elem2->position;
+}
+
+static gint
+compare_files_by_last_created (gconstpointer a,
+ gconstpointer b)
+{
+ CreateDateElem *elem1;
+ CreateDateElem *elem2;
+
+ elem1 = (CreateDateElem *) a;
+ elem2 = (CreateDateElem *) b;
+
+ return elem2->position - elem1->position;
+}
+
+GList *
+nautilus_batch_rename_dialog_sort (GList *selection,
+ SortMode mode,
+ GHashTable *creation_date_table)
+{
+ GList *l, *l2;
+ NautilusFile *file;
+ GList *create_date_list;
+ GList *create_date_list_sorted;
+ gchar *name;
+
+ if (mode == ORIGINAL_ASCENDING)
+ {
+ return g_list_sort (selection, compare_files_by_name_ascending);
+ }
+
+ if (mode == ORIGINAL_DESCENDING)
+ {
+ return g_list_sort (selection, compare_files_by_name_descending);
+ }
+
+ if (mode == FIRST_MODIFIED)
+ {
+ return g_list_sort (selection, compare_files_by_first_modified);
+ }
+
+ if (mode == LAST_MODIFIED)
+ {
+ return g_list_sort (selection, compare_files_by_last_modified);
+ }
+
+ if (mode == FIRST_CREATED || mode == LAST_CREATED)
+ {
+ create_date_list = NULL;
+
+ for (l = selection; l != NULL; l = l->next)
+ {
+ CreateDateElem *elem;
+ elem = g_new (CreateDateElem, 1);
+
+ file = NAUTILUS_FILE (l->data);
+
+ name = nautilus_file_get_name (file);
+ elem->file = file;
+ elem->position = GPOINTER_TO_INT (g_hash_table_lookup (creation_date_table, name));
+ g_free (name);
+
+ create_date_list = g_list_prepend (create_date_list, elem);
+ }
+
+ if (mode == FIRST_CREATED)
+ {
+ create_date_list_sorted = g_list_sort (create_date_list,
+ compare_files_by_first_created);
+ }
+ else
+ {
+ create_date_list_sorted = g_list_sort (create_date_list,
+ compare_files_by_last_created);
+ }
+
+ for (l = selection, l2 = create_date_list_sorted; l2 != NULL; l = l->next, l2 = l2->next)
+ {
+ CreateDateElem *elem = l2->data;
+ l->data = elem->file;
+ }
+
+ g_list_free_full (create_date_list, g_free);
+ }
+
+ return selection;
+}
+
+static void
+cursor_next (QueryData *query_data,
+ TrackerSparqlCursor *cursor)
+{
+ tracker_sparql_cursor_next_async (cursor,
+ query_data->cancellable,
+ on_cursor_callback,
+ query_data);
+}
+
+static void
+remove_metadata (QueryData *query_data,
+ MetadataType metadata_type)
+{
+ GList *l;
+ FileMetadata *metadata_to_delete;
+
+ for (l = query_data->selection_metadata; l != NULL; l = l->next)
+ {
+ metadata_to_delete = l->data;
+ if (metadata_to_delete->metadata[metadata_type])
+ {
+ g_string_free (metadata_to_delete->metadata[metadata_type], TRUE);
+ metadata_to_delete->metadata[metadata_type] = NULL;
+ }
+ }
+
+ query_data->has_metadata[metadata_type] = FALSE;
+}
+
+static GString *
+format_date_time (GDateTime *date_time)
+{
+ g_autofree gchar *date = NULL;
+ GString *formated_date;
+
+ date = g_date_time_format (date_time, "%x");
+ if (strstr (date, "/") != NULL)
+ {
+ formated_date = batch_rename_replace (date, "/", "-");
+ }
+ else
+ {
+ formated_date = g_string_new (date);
+ }
+
+ return formated_date;
+}
+
+static void
+on_cursor_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TrackerSparqlCursor *cursor;
+ gboolean success;
+ QueryData *query_data;
+ MetadataType metadata_type;
+ g_autoptr (GError) error = NULL;
+ GList *l;
+ FileMetadata *file_metadata;
+ GDateTime *date_time;
+ guint i;
+ const gchar *current_metadata;
+ const gchar *file_name;
+ const gchar *creation_date;
+ const gchar *year;
+ const gchar *month;
+ const gchar *day;
+ const gchar *hours;
+ const gchar *minutes;
+ const gchar *seconds;
+ const gchar *equipment;
+ const gchar *season_number;
+ const gchar *episode_number;
+ const gchar *track_number;
+ const gchar *artist_name;
+ const gchar *title;
+ const gchar *album_name;
+
+ file_metadata = NULL;
+
+ cursor = TRACKER_SPARQL_CURSOR (object);
+ query_data = user_data;
+
+ success = tracker_sparql_cursor_next_finish (cursor, result, &error);
+ if (!success)
+ {
+ if (error != NULL)
+ {
+ g_warning ("Error on batch rename tracker query cursor: %s", error->message);
+ }
+
+ g_clear_object (&cursor);
+
+ /* The dialog is going away at the time of cancellation */
+ if (error == NULL ||
+ (error != NULL && error->code != G_IO_ERROR_CANCELLED))
+ {
+ nautilus_batch_rename_dialog_query_finished (query_data->dialog,
+ query_data->date_order_hash_table,
+ query_data->selection_metadata);
+ }
+
+ g_free (query_data);
+
+ return;
+ }
+
+ creation_date = tracker_sparql_cursor_get_string (cursor, CREATION_DATE_INDEX, NULL);
+
+ year = tracker_sparql_cursor_get_string (cursor, YEAR_INDEX, NULL);
+ month = tracker_sparql_cursor_get_string (cursor, MONTH_INDEX, NULL);
+ day = tracker_sparql_cursor_get_string (cursor, DAY_INDEX, NULL);
+ hours = tracker_sparql_cursor_get_string (cursor, HOURS_INDEX, NULL);
+ minutes = tracker_sparql_cursor_get_string (cursor, MINUTES_INDEX, NULL);
+ seconds = tracker_sparql_cursor_get_string (cursor, SECONDS_INDEX, NULL);
+ equipment = tracker_sparql_cursor_get_string (cursor, CAMERA_MODEL_INDEX, NULL);
+ season_number = tracker_sparql_cursor_get_string (cursor, SEASON_INDEX, NULL);
+ episode_number = tracker_sparql_cursor_get_string (cursor, EPISODE_NUMBER_INDEX, NULL);
+ track_number = tracker_sparql_cursor_get_string (cursor, TRACK_NUMBER_INDEX, NULL);
+ artist_name = tracker_sparql_cursor_get_string (cursor, ARTIST_NAME_INDEX, NULL);
+ title = tracker_sparql_cursor_get_string (cursor, TITLE_INDEX, NULL);
+ album_name = tracker_sparql_cursor_get_string (cursor, ALBUM_NAME_INDEX, NULL);
+
+ /* Search for the metadata object corresponding to the file name */
+ file_name = tracker_sparql_cursor_get_string (cursor, FILE_NAME_INDEX, NULL);
+ for (l = query_data->selection_metadata; l != NULL; l = l->next)
+ {
+ file_metadata = l->data;
+
+ if (g_strcmp0 (file_name, file_metadata->file_name->str) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Set metadata when available, and delete for the whole selection when not */
+ for (i = 0; i < G_N_ELEMENTS (metadata_tags_constants); i++)
+ {
+ if (query_data->has_metadata[i])
+ {
+ metadata_type = metadata_tags_constants[i].metadata_type;
+ current_metadata = NULL;
+ switch (metadata_type)
+ {
+ case ORIGINAL_FILE_NAME:
+ {
+ current_metadata = file_name;
+ }
+ break;
+
+ case CREATION_DATE:
+ {
+ current_metadata = creation_date;
+ }
+ break;
+
+ case EQUIPMENT:
+ {
+ current_metadata = equipment;
+ }
+ break;
+
+ case SEASON_NUMBER:
+ {
+ current_metadata = season_number;
+ }
+ break;
+
+ case EPISODE_NUMBER:
+ {
+ current_metadata = episode_number;
+ }
+ break;
+
+ case ARTIST_NAME:
+ {
+ current_metadata = artist_name;
+ }
+ break;
+
+ case ALBUM_NAME:
+ {
+ current_metadata = album_name;
+ }
+ break;
+
+ case TITLE:
+ {
+ current_metadata = title;
+ }
+ break;
+
+ case TRACK_NUMBER:
+ {
+ current_metadata = track_number;
+ }
+ break;
+
+ default:
+ {
+ g_warn_if_reached ();
+ }
+ break;
+ }
+
+ /* TODO: Figure out how to inform the user of why the metadata is
+ * unavailable when one or more contains the unallowed character "/"
+ */
+ if (!current_metadata || g_strrstr (current_metadata, "/"))
+ {
+ remove_metadata (query_data,
+ metadata_type);
+
+ if (metadata_type == CREATION_DATE &&
+ query_data->date_order_hash_table)
+ {
+ g_hash_table_destroy (query_data->date_order_hash_table);
+ query_data->date_order_hash_table = NULL;
+ }
+ }
+ else
+ {
+ if (metadata_type == CREATION_DATE)
+ {
+ /* Add the sort order to the order hash table */
+ g_hash_table_insert (query_data->date_order_hash_table,
+ g_strdup (tracker_sparql_cursor_get_string (cursor, 0, NULL)),
+ GINT_TO_POINTER (g_hash_table_size (query_data->date_order_hash_table)));
+
+ date_time = g_date_time_new_local (atoi (year),
+ atoi (month),
+ atoi (day),
+ atoi (hours),
+ atoi (minutes),
+ atoi (seconds));
+
+ file_metadata->metadata[metadata_type] = format_date_time (date_time);
+ }
+ else
+ {
+ file_metadata->metadata[metadata_type] = g_string_new (current_metadata);
+ }
+ }
+ }
+ }
+
+ /* Get next */
+ cursor_next (query_data, cursor);
+}
+
+static void
+batch_rename_dialog_query_callback (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ TrackerSparqlConnection *connection;
+ TrackerSparqlCursor *cursor;
+ QueryData *query_data;
+ g_autoptr (GError) error = NULL;
+
+ connection = TRACKER_SPARQL_CONNECTION (object);
+ 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: %s", error->message);
+
+ /* The dialog is being finalized at this point */
+ if (error->code != G_IO_ERROR_CANCELLED)
+ {
+ nautilus_batch_rename_dialog_query_finished (query_data->dialog,
+ query_data->date_order_hash_table,
+ query_data->selection_metadata);
+ }
+
+ g_free (query_data);
+ }
+ else
+ {
+ cursor_next (query_data, cursor);
+ }
+}
+
+void
+check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
+ GList *selection,
+ GCancellable *cancellable)
+{
+ TrackerSparqlConnection *connection;
+ GString *query;
+ GList *l;
+ NautilusFile *file;
+ GError *error;
+ QueryData *query_data;
+ gchar *file_name;
+ FileMetadata *file_metadata;
+ GList *selection_metadata;
+ guint i;
+ g_autofree gchar *parent_uri = NULL;
+ gchar *file_name_escaped;
+
+ error = NULL;
+ selection_metadata = NULL;
+
+ query = g_string_new ("SELECT "
+ "nfo:fileName(?file) "
+ "nie:contentCreated(?content) "
+ "year(nie:contentCreated(?content)) "
+ "month(nie:contentCreated(?content)) "
+ "day(nie:contentCreated(?content)) "
+ "hours(nie:contentCreated(?content)) "
+ "minutes(nie:contentCreated(?content)) "
+ "seconds(nie:contentCreated(?content)) "
+ "nfo:model(nfo:equipment(?content)) "
+ "nmm:seasonNumber(?content) "
+ "nmm:episodeNumber(?content) "
+ "nmm:trackNumber(?content) "
+ "nmm:artistName(nmm:performer(?content)) "
+ "nie:title(?content) "
+ "nie:title(nmm:musicAlbum(?content)) "
+ "WHERE { ?file a nfo:FileDataObject. ?file nie:url ?url. ?content nie:isStoredAs ?file. ");
+
+ parent_uri = nautilus_file_get_parent_uri (NAUTILUS_FILE (selection->data));
+
+ g_string_append_printf (query,
+ "FILTER(tracker:uri-is-parent(\"%s\", ?url)) ",
+ parent_uri);
+
+ for (l = selection; l != NULL; l = l->next)
+ {
+ file = NAUTILUS_FILE (l->data);
+ file_name = nautilus_file_get_name (file);
+ file_name_escaped = tracker_sparql_escape_string (file_name);
+
+ if (l == selection)
+ {
+ g_string_append_printf (query,
+ "FILTER (nfo:fileName(?file) IN (\"%s\", ",
+ file_name_escaped);
+ }
+ else if (l->next == NULL)
+ {
+ g_string_append_printf (query,
+ "\"%s\")) ",
+ file_name_escaped);
+ }
+ else
+ {
+ g_string_append_printf (query,
+ "\"%s\", ",
+ file_name_escaped);
+ }
+
+ file_metadata = g_new0 (FileMetadata, 1);
+ file_metadata->file_name = g_string_new (file_name);
+ file_metadata->metadata[ORIGINAL_FILE_NAME] = g_string_new (file_name);
+
+ selection_metadata = g_list_prepend (selection_metadata, file_metadata);
+
+ g_free (file_name);
+ g_free (file_name_escaped);
+ }
+
+ selection_metadata = g_list_reverse (selection_metadata);
+
+ g_string_append (query, "} ORDER BY ASC(nie:contentCreated(?content))");
+
+ connection = nautilus_tracker_get_miner_fs_connection (&error);
+ if (!connection)
+ {
+ if (error)
+ {
+ g_warning ("Error on batch rename tracker connection: %s", error->message);
+ g_error_free (error);
+ }
+
+ return;
+ }
+
+ query_data = g_new (QueryData, 1);
+ query_data->date_order_hash_table = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ NULL);
+ query_data->dialog = dialog;
+ query_data->selection_metadata = selection_metadata;
+ for (i = 0; i < G_N_ELEMENTS (metadata_tags_constants); i++)
+ {
+ query_data->has_metadata[i] = TRUE;
+ }
+ query_data->cancellable = cancellable;
+
+ /* Make an asynchronous query to the store */
+ tracker_sparql_connection_query_async (connection,
+ query->str,
+ cancellable,
+ batch_rename_dialog_query_callback,
+ query_data);
+
+ g_string_free (query, TRUE);
+}
+
+GList *
+batch_rename_files_get_distinct_parents (GList *selection)
+{
+ GList *result;
+ GList *l1;
+ NautilusFile *file;
+ NautilusDirectory *directory;
+ NautilusFile *parent;
+
+ result = NULL;
+ for (l1 = selection; l1 != NULL; l1 = l1->next)
+ {
+ file = NAUTILUS_FILE (l1->data);
+ parent = nautilus_file_get_parent (file);
+ directory = nautilus_directory_get_for_file (parent);
+ if (!g_list_find (result, directory))
+ {
+ result = g_list_prepend (result, directory);
+ }
+
+ nautilus_file_unref (parent);
+ }
+
+ return result;
+}