mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-10-01 05:23:56 +00:00
Implement batch renaming
Renaming multiple files at once has been a missing feature in Nautilus for a long time. This patch implements that feature in the following way: This operation is launched in the same way as the rename one, when the selection has more than one file. When the batch renaming is launched, a dialog is shown, offering two modes. In the first mode, the user can use metadata (if available), numbering and original file name tags to create the new names. Between the tags, there also can be written normal text, which will be added in the new names. If numbering is used, the order of the files can be modified by using several criteria. In the second mode, the user can replace an existing part of the name. https://bugzilla.gnome.org/show_bug.cgi?id=768311
This commit is contained in:
parent
d296183010
commit
be12a75100
|
@ -161,6 +161,8 @@ nautilus_no_main_sources = \
|
||||||
gtk/nautilusgtkplacesviewrowprivate.h \
|
gtk/nautilusgtkplacesviewrowprivate.h \
|
||||||
nautilus-application.c \
|
nautilus-application.c \
|
||||||
nautilus-application.h \
|
nautilus-application.h \
|
||||||
|
nautilus-batch-rename-dialog.c \
|
||||||
|
nautilus-batch-rename-dialog.h \
|
||||||
nautilus-bookmark-list.c \
|
nautilus-bookmark-list.c \
|
||||||
nautilus-bookmark-list.h \
|
nautilus-bookmark-list.h \
|
||||||
nautilus-canvas-view.c \
|
nautilus-canvas-view.c \
|
||||||
|
@ -214,6 +216,8 @@ nautilus_no_main_sources = \
|
||||||
nautilus-properties-window.h \
|
nautilus-properties-window.h \
|
||||||
nautilus-query-editor.c \
|
nautilus-query-editor.c \
|
||||||
nautilus-query-editor.h \
|
nautilus-query-editor.h \
|
||||||
|
nautilus-batch-rename-utilities.c \
|
||||||
|
nautilus-batch-rename-utilities.h \
|
||||||
nautilus-search-popover.c \
|
nautilus-search-popover.c \
|
||||||
nautilus-search-popover.h \
|
nautilus-search-popover.h \
|
||||||
nautilus-self-check-functions.c \
|
nautilus-self-check-functions.c \
|
||||||
|
|
3027
src/nautilus-batch-rename-dialog.c
Normal file
3027
src/nautilus-batch-rename-dialog.c
Normal file
File diff suppressed because it is too large
Load diff
100
src/nautilus-batch-rename-dialog.h
Normal file
100
src/nautilus-batch-rename-dialog.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include "nautilus-files-view.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define ORIGINAL_FILE_NAME "[Original file name]"
|
||||||
|
#define NUMBERING "[1, 2, 3]"
|
||||||
|
#define NUMBERING0 "[01, 02, 03]"
|
||||||
|
#define NUMBERING00 "[001, 002, 003]"
|
||||||
|
#define CAMERA_MODEL "[Camera model]"
|
||||||
|
#define CREATION_DATE "[Creation date]"
|
||||||
|
#define SEASON_NUMBER "[Season number]"
|
||||||
|
#define EPISODE_NUMBER "[Episode number]"
|
||||||
|
#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,
|
||||||
|
NAUTILUS_BATCH_RENAME_DIALOG_PREPEND = 1,
|
||||||
|
NAUTILUS_BATCH_RENAME_DIALOG_REPLACE = 2,
|
||||||
|
NAUTILUS_BATCH_RENAME_DIALOG_FORMAT = 3,
|
||||||
|
} NautilusBatchRenameDialogMode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ORIGINAL_ASCENDING = 0,
|
||||||
|
ORIGINAL_DESCENDING = 1,
|
||||||
|
FIRST_MODIFIED = 2,
|
||||||
|
LAST_MODIFIED = 3,
|
||||||
|
FIRST_CREATED = 4,
|
||||||
|
LAST_CREATED = 5,
|
||||||
|
} SortingMode;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gchar *name;
|
||||||
|
gint index;
|
||||||
|
} ConflictData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GString *file_name;
|
||||||
|
|
||||||
|
/* Photo */
|
||||||
|
GString *creation_date;
|
||||||
|
GString *equipment;
|
||||||
|
|
||||||
|
/* Video */
|
||||||
|
GString *season;
|
||||||
|
GString *episode_number;
|
||||||
|
|
||||||
|
/* Music */
|
||||||
|
GString *track_number;
|
||||||
|
GString *artist_name;
|
||||||
|
GString *title;
|
||||||
|
GString *album_name;
|
||||||
|
} FileMetadata;
|
||||||
|
|
||||||
|
#define NAUTILUS_TYPE_BATCH_RENAME_DIALOG (nautilus_batch_rename_dialog_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (NautilusBatchRenameDialog, nautilus_batch_rename_dialog, NAUTILUS, BATCH_RENAME_DIALOG, GtkDialog);
|
||||||
|
|
||||||
|
GtkWidget* nautilus_batch_rename_dialog_new (GList *selection,
|
||||||
|
NautilusDirectory *directory,
|
||||||
|
NautilusWindow *window);
|
||||||
|
|
||||||
|
void nautilus_batch_rename_dialog_query_finished (NautilusBatchRenameDialog *dialog,
|
||||||
|
GHashTable *hash_table,
|
||||||
|
GList *selection_metadata);
|
||||||
|
|
||||||
|
void check_conflict_for_files (NautilusBatchRenameDialog *dialog,
|
||||||
|
NautilusDirectory *directory,
|
||||||
|
GList *files);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
1050
src/nautilus-batch-rename-utilities.c
Normal file
1050
src/nautilus-batch-rename-utilities.c
Normal file
File diff suppressed because it is too large
Load diff
63
src/nautilus-batch-rename-utilities.h
Normal file
63
src/nautilus-batch-rename-utilities.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <tracker-sparql.h>
|
||||||
|
|
||||||
|
GList* batch_rename_dialog_get_new_names_list (NautilusBatchRenameDialogMode mode,
|
||||||
|
GList *selection,
|
||||||
|
GList *tags_list,
|
||||||
|
GList *selection_metadata,
|
||||||
|
gchar *entry_text,
|
||||||
|
gchar *replace_text);
|
||||||
|
|
||||||
|
GList* file_names_list_has_duplicates (NautilusBatchRenameDialog *dialog,
|
||||||
|
NautilusDirectory *model,
|
||||||
|
GList *names,
|
||||||
|
GList *selection,
|
||||||
|
GList *parents_list,
|
||||||
|
GCancellable *cancellable);
|
||||||
|
|
||||||
|
GList* nautilus_batch_rename_dialog_sort (GList *selection,
|
||||||
|
SortingMode mode,
|
||||||
|
GHashTable *creation_date_table);
|
||||||
|
|
||||||
|
void check_metadata_for_selection (NautilusBatchRenameDialog *dialog,
|
||||||
|
GList *selection);
|
||||||
|
|
||||||
|
gboolean selection_has_single_parent (GList *selection);
|
||||||
|
|
||||||
|
void string_free (gpointer mem);
|
||||||
|
|
||||||
|
void conflict_data_free (gpointer mem);
|
||||||
|
|
||||||
|
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_replace_label_text (gchar *label,
|
||||||
|
const gchar *substr);
|
||||||
|
|
||||||
|
#endif /* NAUTILUS_BATCH_RENAME_UTILITIES_H */
|
|
@ -214,6 +214,9 @@ struct NautilusFileDetails
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NautilusFile *file;
|
NautilusFile *file;
|
||||||
|
GList *files;
|
||||||
|
gint renamed_files;
|
||||||
|
gint skipped_files;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
NautilusFileOperationCallback callback;
|
NautilusFileOperationCallback callback;
|
||||||
gpointer callback_data;
|
gpointer callback_data;
|
||||||
|
|
|
@ -994,6 +994,292 @@ nautilus_file_undo_info_rename_set_data_post (NautilusFileUndoInfoRename *self,
|
||||||
self->priv->new_file = g_object_ref (new_file);
|
self->priv->new_file = g_object_ref (new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* batch rename */
|
||||||
|
G_DEFINE_TYPE (NautilusFileUndoInfoBatchRename, nautilus_file_undo_info_batch_rename, NAUTILUS_TYPE_FILE_UNDO_INFO);
|
||||||
|
|
||||||
|
struct _NautilusFileUndoInfoBatchRenameDetails {
|
||||||
|
GList *old_files;
|
||||||
|
GList *new_files;
|
||||||
|
GList *old_display_names;
|
||||||
|
GList *new_display_names;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
batch_rename_strings_func (NautilusFileUndoInfo *info,
|
||||||
|
gchar **undo_label,
|
||||||
|
gchar **undo_description,
|
||||||
|
gchar **redo_label,
|
||||||
|
gchar **redo_description)
|
||||||
|
{
|
||||||
|
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (info);
|
||||||
|
|
||||||
|
*undo_description = g_strdup_printf (_("Batch rename '%d' files"),
|
||||||
|
g_list_length (self->priv->new_files));
|
||||||
|
*redo_description = g_strdup_printf (_("Batch rename '%d' files"),
|
||||||
|
g_list_length (self->priv->new_files));
|
||||||
|
|
||||||
|
*undo_label = g_strdup (_("_Undo Batch rename"));
|
||||||
|
*redo_label = g_strdup (_("_Redo Batch rename"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
batch_rename_redo_func (NautilusFileUndoInfo *info,
|
||||||
|
GtkWindow *parent_window)
|
||||||
|
{
|
||||||
|
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (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;
|
||||||
|
|
||||||
|
for (l = self->priv->old_files; l != NULL; l = l->next) {
|
||||||
|
old_file = l->data;
|
||||||
|
|
||||||
|
file = nautilus_file_get (old_file);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
batch_rename_undo_func (NautilusFileUndoInfo *info,
|
||||||
|
GtkWindow *parent_window)
|
||||||
|
{
|
||||||
|
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (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;
|
||||||
|
|
||||||
|
for (l = self->priv->new_files; l != NULL; l = l->next) {
|
||||||
|
new_file = l->data;
|
||||||
|
|
||||||
|
file = nautilus_file_get (new_file);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nautilus_file_undo_info_batch_rename_init (NautilusFileUndoInfoBatchRename *self)
|
||||||
|
{
|
||||||
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, nautilus_file_undo_info_batch_rename_get_type (),
|
||||||
|
NautilusFileUndoInfoBatchRenameDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nautilus_file_undo_info_batch_rename_finalize (GObject *obj)
|
||||||
|
{
|
||||||
|
GList *l;
|
||||||
|
GFile *file;
|
||||||
|
GString *string;
|
||||||
|
NautilusFileUndoInfoBatchRename *self = NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (obj);
|
||||||
|
|
||||||
|
for (l = self->priv->new_files; l != NULL; l = l->next){
|
||||||
|
file = l->data;
|
||||||
|
|
||||||
|
g_clear_object (&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l = self->priv->old_files; l != NULL; l = l->next){
|
||||||
|
file = l->data;
|
||||||
|
|
||||||
|
g_clear_object (&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l = self->priv->new_display_names; l != NULL; l = l->next) {
|
||||||
|
string = l->data;
|
||||||
|
|
||||||
|
g_string_free (string, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l = self->priv->old_display_names; l != NULL; l = l->next) {
|
||||||
|
string = l->data;
|
||||||
|
|
||||||
|
g_string_free (string, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (self->priv->new_files);
|
||||||
|
g_list_free (self->priv->old_files);
|
||||||
|
g_list_free (self->priv->new_display_names);
|
||||||
|
g_list_free (self->priv->old_display_names);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (nautilus_file_undo_info_batch_rename_parent_class)->finalize (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nautilus_file_undo_info_batch_rename_class_init (NautilusFileUndoInfoBatchRenameClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *oclass = G_OBJECT_CLASS (klass);
|
||||||
|
NautilusFileUndoInfoClass *iclass = NAUTILUS_FILE_UNDO_INFO_CLASS (klass);
|
||||||
|
|
||||||
|
oclass->finalize = nautilus_file_undo_info_batch_rename_finalize;
|
||||||
|
|
||||||
|
iclass->undo_func = batch_rename_undo_func;
|
||||||
|
iclass->redo_func = batch_rename_redo_func;
|
||||||
|
iclass->strings_func = batch_rename_strings_func;
|
||||||
|
|
||||||
|
g_type_class_add_private (klass, sizeof (NautilusFileUndoInfoBatchRenameDetails));
|
||||||
|
}
|
||||||
|
|
||||||
|
NautilusFileUndoInfo *
|
||||||
|
nautilus_file_undo_info_batch_rename_new (gint item_count)
|
||||||
|
{
|
||||||
|
return g_object_new (NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME,
|
||||||
|
"op-type", NAUTILUS_FILE_UNDO_OP_BATCH_RENAME,
|
||||||
|
"item-count", item_count,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nautilus_file_undo_info_batch_rename_set_data_pre (NautilusFileUndoInfoBatchRename *self,
|
||||||
|
GList *old_files)
|
||||||
|
{
|
||||||
|
GList *l;
|
||||||
|
GString *old_name;
|
||||||
|
GFile *file;
|
||||||
|
|
||||||
|
self->priv->old_files = old_files;
|
||||||
|
self->priv->old_display_names = NULL;
|
||||||
|
|
||||||
|
for (l = old_files; l != NULL; l = l->next) {
|
||||||
|
file = l->data;
|
||||||
|
|
||||||
|
old_name = g_string_new (g_file_get_basename (file));
|
||||||
|
|
||||||
|
self->priv->old_display_names = g_list_append (self->priv->old_display_names, old_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRename *self,
|
||||||
|
GList *new_files)
|
||||||
|
{
|
||||||
|
GList *l;
|
||||||
|
GString *new_name;
|
||||||
|
GFile *file;
|
||||||
|
|
||||||
|
self->priv->new_files = new_files;
|
||||||
|
self->priv->new_display_names = NULL;
|
||||||
|
|
||||||
|
for (l = new_files; l != NULL; l = l->next) {
|
||||||
|
file = l->data;
|
||||||
|
|
||||||
|
new_name = g_string_new (g_file_get_basename (file));
|
||||||
|
|
||||||
|
self->priv->new_display_names = g_list_append (self->priv->new_display_names, new_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* trash */
|
/* trash */
|
||||||
G_DEFINE_TYPE (NautilusFileUndoInfoTrash, nautilus_file_undo_info_trash, NAUTILUS_TYPE_FILE_UNDO_INFO)
|
G_DEFINE_TYPE (NautilusFileUndoInfoTrash, nautilus_file_undo_info_trash, NAUTILUS_TYPE_FILE_UNDO_INFO)
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef enum {
|
||||||
NAUTILUS_FILE_UNDO_OP_DUPLICATE,
|
NAUTILUS_FILE_UNDO_OP_DUPLICATE,
|
||||||
NAUTILUS_FILE_UNDO_OP_MOVE,
|
NAUTILUS_FILE_UNDO_OP_MOVE,
|
||||||
NAUTILUS_FILE_UNDO_OP_RENAME,
|
NAUTILUS_FILE_UNDO_OP_RENAME,
|
||||||
|
NAUTILUS_FILE_UNDO_OP_BATCH_RENAME,
|
||||||
NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE,
|
NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE,
|
||||||
NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE,
|
NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE,
|
||||||
NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER,
|
NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER,
|
||||||
|
@ -188,6 +189,34 @@ void nautilus_file_undo_info_rename_set_data_pre (NautilusFileUndoInfoRename *se
|
||||||
void nautilus_file_undo_info_rename_set_data_post (NautilusFileUndoInfoRename *self,
|
void nautilus_file_undo_info_rename_set_data_post (NautilusFileUndoInfoRename *self,
|
||||||
GFile *new_file);
|
GFile *new_file);
|
||||||
|
|
||||||
|
/* batch rename */
|
||||||
|
#define NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME (nautilus_file_undo_info_batch_rename_get_type ())
|
||||||
|
#define NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME, NautilusFileUndoInfoBatchRename))
|
||||||
|
#define NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME, NautilusFileUndoInfoBatchRenameClass))
|
||||||
|
#define NAUTILUS_IS_FILE_UNDO_INFO_BATCH_RENAME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME))
|
||||||
|
#define NAUTILUS_IS_FILE_UNDO_INFO_BATCH_RENAME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME))
|
||||||
|
#define NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_BATCH_RENAME, NautilusFileUndoInfoBatchRenameClass))
|
||||||
|
|
||||||
|
typedef struct _NautilusFileUndoInfoBatchRename NautilusFileUndoInfoBatchRename;
|
||||||
|
typedef struct _NautilusFileUndoInfoBatchRenameClass NautilusFileUndoInfoBatchRenameClass;
|
||||||
|
typedef struct _NautilusFileUndoInfoBatchRenameDetails NautilusFileUndoInfoBatchRenameDetails;
|
||||||
|
|
||||||
|
struct _NautilusFileUndoInfoBatchRename {
|
||||||
|
NautilusFileUndoInfo parent;
|
||||||
|
NautilusFileUndoInfoBatchRenameDetails *priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _NautilusFileUndoInfoBatchRenameClass {
|
||||||
|
NautilusFileUndoInfoClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType nautilus_file_undo_info_batch_rename_get_type (void) G_GNUC_CONST;
|
||||||
|
NautilusFileUndoInfo *nautilus_file_undo_info_batch_rename_new (gint item_count);
|
||||||
|
void nautilus_file_undo_info_batch_rename_set_data_pre (NautilusFileUndoInfoBatchRename *self,
|
||||||
|
GList *old_files);
|
||||||
|
void nautilus_file_undo_info_batch_rename_set_data_post (NautilusFileUndoInfoBatchRename *self,
|
||||||
|
GList *new_files);
|
||||||
|
|
||||||
/* trash */
|
/* trash */
|
||||||
#define NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH (nautilus_file_undo_info_trash_get_type ())
|
#define NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH (nautilus_file_undo_info_trash_get_type ())
|
||||||
#define NAUTILUS_FILE_UNDO_INFO_TRASH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH, NautilusFileUndoInfoTrash))
|
#define NAUTILUS_FILE_UNDO_INFO_TRASH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_FILE_UNDO_INFO_TRASH, NautilusFileUndoInfoTrash))
|
||||||
|
|
|
@ -1221,3 +1221,19 @@ nautilus_ensure_extension_points (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !NAUTILUS_OMIT_SELF_CHECK */
|
#endif /* !NAUTILUS_OMIT_SELF_CHECK */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
nautilus_file_can_rename_files (GList *files)
|
||||||
|
{
|
||||||
|
GList *l;
|
||||||
|
NautilusFile *file;
|
||||||
|
|
||||||
|
for (l = files; l != NULL; l = l->next) {
|
||||||
|
file = NAUTILUS_FILE (l->data);
|
||||||
|
|
||||||
|
if (!nautilus_file_can_rename (file))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
|
@ -119,4 +119,6 @@ char * nautilus_get_common_filename_prefix_from_filenames (GList *filename_list,
|
||||||
void nautilus_ensure_extension_points (void);
|
void nautilus_ensure_extension_points (void);
|
||||||
void nautilus_ensure_extension_builtins (void);
|
void nautilus_ensure_extension_builtins (void);
|
||||||
|
|
||||||
|
gboolean nautilus_file_can_rename_files (GList *files);
|
||||||
|
|
||||||
#endif /* NAUTILUS_FILE_UTILITIES_H */
|
#endif /* NAUTILUS_FILE_UTILITIES_H */
|
||||||
|
|
|
@ -1648,15 +1648,36 @@ nautilus_file_operation_new (NautilusFile *file,
|
||||||
static void
|
static void
|
||||||
nautilus_file_operation_remove (NautilusFileOperation *op)
|
nautilus_file_operation_remove (NautilusFileOperation *op)
|
||||||
{
|
{
|
||||||
|
GList *l;
|
||||||
|
NautilusFile *file;
|
||||||
|
|
||||||
op->file->details->operations_in_progress = g_list_remove
|
op->file->details->operations_in_progress = g_list_remove
|
||||||
(op->file->details->operations_in_progress, op);
|
(op->file->details->operations_in_progress, op);
|
||||||
|
|
||||||
|
|
||||||
|
for (l = op->files; l != NULL; l = l->next) {
|
||||||
|
file = NAUTILUS_FILE (l->data);
|
||||||
|
file->details->operations_in_progress = g_list_remove
|
||||||
|
(file->details->operations_in_progress, op);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nautilus_file_operation_free (NautilusFileOperation *op)
|
nautilus_file_operation_free (NautilusFileOperation *op)
|
||||||
{
|
{
|
||||||
|
NautilusFile *file;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
nautilus_file_operation_remove (op);
|
nautilus_file_operation_remove (op);
|
||||||
nautilus_file_unref (op->file);
|
|
||||||
|
if (op->files == NULL)
|
||||||
|
nautilus_file_unref (op->file);
|
||||||
|
else
|
||||||
|
for (l = op->files; l != NULL; l = l->next) {
|
||||||
|
file = NAUTILUS_FILE (l->data);
|
||||||
|
nautilus_file_unref (file);
|
||||||
|
}
|
||||||
|
|
||||||
g_object_unref (op->cancellable);
|
g_object_unref (op->cancellable);
|
||||||
if (op->free_data) {
|
if (op->free_data) {
|
||||||
op->free_data (op->data);
|
op->free_data (op->data);
|
||||||
|
@ -1680,10 +1701,12 @@ nautilus_file_operation_complete (NautilusFileOperation *op,
|
||||||
* as "changing back".
|
* as "changing back".
|
||||||
*/
|
*/
|
||||||
nautilus_file_operation_remove (op);
|
nautilus_file_operation_remove (op);
|
||||||
nautilus_file_changed (op->file);
|
|
||||||
if (op->callback) {
|
if (op->files == NULL)
|
||||||
|
nautilus_file_changed (op->file);
|
||||||
|
|
||||||
|
if (op->callback)
|
||||||
(* op->callback) (op->file, result_file, error, op->callback_data);
|
(* op->callback) (op->file, result_file, error, op->callback_data);
|
||||||
}
|
|
||||||
|
|
||||||
if (error != NULL) {
|
if (error != NULL) {
|
||||||
g_clear_object (&op->undo_info);
|
g_clear_object (&op->undo_info);
|
||||||
|
@ -1759,6 +1782,86 @@ rename_get_info_callback (GObject *source_object,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
NautilusFileOperation *op;
|
||||||
|
NautilusFile *file;
|
||||||
|
} BatchRenameData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
batch_rename_get_info_callback (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer callback_data)
|
||||||
|
{
|
||||||
|
NautilusFileOperation *op;
|
||||||
|
NautilusDirectory *directory;
|
||||||
|
NautilusFile *existing_file;
|
||||||
|
char *old_uri;
|
||||||
|
char *new_uri;
|
||||||
|
const char *new_name;
|
||||||
|
GFileInfo *new_info;
|
||||||
|
GError *error;
|
||||||
|
BatchRenameData *data;
|
||||||
|
|
||||||
|
data = callback_data;
|
||||||
|
|
||||||
|
op = data->op;
|
||||||
|
op->file = data->file;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
|
||||||
|
if (new_info != NULL) {
|
||||||
|
old_uri = nautilus_file_get_uri (op->file);
|
||||||
|
|
||||||
|
new_name = g_file_info_get_name (new_info);
|
||||||
|
|
||||||
|
directory = op->file->details->directory;
|
||||||
|
|
||||||
|
/* If there was another file by the same name in this
|
||||||
|
* directory and it is not the same file that we are
|
||||||
|
* renaming, mark it gone.
|
||||||
|
*/
|
||||||
|
existing_file = nautilus_directory_find_file_by_name (directory, new_name);
|
||||||
|
if (existing_file != NULL && existing_file != op->file) {
|
||||||
|
nautilus_file_mark_gone (existing_file);
|
||||||
|
nautilus_file_changed (existing_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_info_and_name (op->file, new_info);
|
||||||
|
|
||||||
|
new_uri = nautilus_file_get_uri (op->file);
|
||||||
|
nautilus_directory_moved (old_uri, new_uri);
|
||||||
|
g_free (new_uri);
|
||||||
|
g_free (old_uri);
|
||||||
|
|
||||||
|
/* the rename could have affected the display name if e.g.
|
||||||
|
* we're in a vfolder where the name comes from a desktop file
|
||||||
|
* and a rename affects the contents of the desktop file.
|
||||||
|
*/
|
||||||
|
if (op->file->details->got_custom_display_name) {
|
||||||
|
nautilus_file_invalidate_attributes (op->file,
|
||||||
|
NAUTILUS_FILE_ATTRIBUTE_INFO |
|
||||||
|
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (new_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
op->renamed_files++;
|
||||||
|
|
||||||
|
if (op->renamed_files + op->skipped_files == g_list_length (op->files)) {
|
||||||
|
nautilus_file_operation_complete (op, NULL, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op->files == NULL)
|
||||||
|
nautilus_file_operation_complete (op, NULL, error);
|
||||||
|
|
||||||
|
g_free (data);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rename_callback (GObject *source_object,
|
rename_callback (GObject *source_object,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
|
@ -1779,7 +1882,6 @@ rename_callback (GObject *source_object,
|
||||||
nautilus_file_undo_info_rename_set_data_post (NAUTILUS_FILE_UNDO_INFO_RENAME (op->undo_info),
|
nautilus_file_undo_info_rename_set_data_post (NAUTILUS_FILE_UNDO_INFO_RENAME (op->undo_info),
|
||||||
new_file);
|
new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_file_query_info_async (new_file,
|
g_file_query_info_async (new_file,
|
||||||
NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
|
NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
|
||||||
0,
|
0,
|
||||||
|
@ -1812,6 +1914,217 @@ nautilus_file_rename (NautilusFile *file,
|
||||||
callback_data);
|
callback_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gchar*
|
||||||
|
nautilus_file_can_rename_file (NautilusFile *file,
|
||||||
|
const char *new_name,
|
||||||
|
NautilusFileOperationCallback callback,
|
||||||
|
gpointer callback_data)
|
||||||
|
{
|
||||||
|
GError *error;
|
||||||
|
gboolean is_renameable_desktop_file;
|
||||||
|
gboolean success;
|
||||||
|
gboolean name_changed;
|
||||||
|
gchar *new_file_name;
|
||||||
|
gchar *uri;
|
||||||
|
gchar *old_name;
|
||||||
|
|
||||||
|
is_renameable_desktop_file =
|
||||||
|
is_desktop_file (file) && can_rename_desktop_file (file);
|
||||||
|
|
||||||
|
/* Return an error for incoming names containing path separators.
|
||||||
|
* But not for .desktop files as '/' are allowed for them */
|
||||||
|
if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
|
||||||
|
error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("Slashes are not allowed in filenames"));
|
||||||
|
if (callback != NULL)
|
||||||
|
(* callback) (file, NULL, error, callback_data);
|
||||||
|
g_error_free (error);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Can't rename a file that's already gone.
|
||||||
|
* We need to check this here because there may be a new
|
||||||
|
* file with the same name.
|
||||||
|
*/
|
||||||
|
if (nautilus_file_rename_handle_file_gone (file, callback, callback_data)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test the name-hasn't-changed case explicitly, for two reasons.
|
||||||
|
* (1) rename returns an error if new & old are same.
|
||||||
|
* (2) We don't want to send file-changed signal if nothing changed.
|
||||||
|
*/
|
||||||
|
if (!is_renameable_desktop_file &&
|
||||||
|
name_is (file, new_name)) {
|
||||||
|
if (callback != NULL)
|
||||||
|
(* callback) (file, NULL, NULL, callback_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Self-owned files can't be renamed. Test the name-not-actually-changing
|
||||||
|
* case before this case.
|
||||||
|
*/
|
||||||
|
if (nautilus_file_is_self_owned (file)) {
|
||||||
|
/* Claim that something changed even if the rename
|
||||||
|
* failed. This makes it easier for some clients who
|
||||||
|
* see the "reverting" to the old name as "changing
|
||||||
|
* back".
|
||||||
|
*/
|
||||||
|
nautilus_file_changed (file);
|
||||||
|
error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
_("Toplevel files cannot be renamed"));
|
||||||
|
|
||||||
|
if (callback != NULL)
|
||||||
|
(* callback) (file, NULL, error, callback_data);
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_renameable_desktop_file) {
|
||||||
|
/* Don't actually change the name if the new name is the same.
|
||||||
|
* This helps for the vfolder method where this can happen and
|
||||||
|
* we want to minimize actual changes
|
||||||
|
*/
|
||||||
|
uri = nautilus_file_get_uri (file);
|
||||||
|
old_name = nautilus_link_local_get_text (uri);
|
||||||
|
if (old_name != NULL && strcmp (new_name, old_name) == 0) {
|
||||||
|
success = TRUE;
|
||||||
|
name_changed = FALSE;
|
||||||
|
} else {
|
||||||
|
success = nautilus_link_local_set_text (uri, new_name);
|
||||||
|
name_changed = TRUE;
|
||||||
|
}
|
||||||
|
g_free (old_name);
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
_("Probably the content of the file is an invalid desktop file format"));
|
||||||
|
if (callback != NULL)
|
||||||
|
(* callback) (file, NULL, error, callback_data);
|
||||||
|
g_error_free (error);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
new_file_name = g_strdup_printf ("%s.desktop", new_name);
|
||||||
|
new_file_name = g_strdelimit (new_file_name, "/", '-');
|
||||||
|
|
||||||
|
if (name_is (file, new_file_name)) {
|
||||||
|
if (name_changed) {
|
||||||
|
nautilus_file_invalidate_attributes (file,
|
||||||
|
NAUTILUS_FILE_ATTRIBUTE_INFO |
|
||||||
|
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback != NULL)
|
||||||
|
(* callback) (file, NULL, NULL, callback_data);
|
||||||
|
g_free (new_file_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_file_name = g_strdup (new_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_file_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
real_batch_rename (GList *files,
|
||||||
|
GList *new_names,
|
||||||
|
NautilusFileOperationCallback callback,
|
||||||
|
gpointer callback_data)
|
||||||
|
{
|
||||||
|
GList *l1, *l2, *old_files, *new_files;
|
||||||
|
NautilusFileOperation *op;
|
||||||
|
GFile *location;
|
||||||
|
gchar *new_file_name;
|
||||||
|
GString *new_name;
|
||||||
|
NautilusFile *file;
|
||||||
|
GError *error;
|
||||||
|
GFile *new_file;
|
||||||
|
BatchRenameData *data;
|
||||||
|
|
||||||
|
error = NULL;
|
||||||
|
old_files = NULL;
|
||||||
|
new_files = NULL;
|
||||||
|
|
||||||
|
/* Set up a batch renaming operation. */
|
||||||
|
op = nautilus_file_operation_new (files->data, callback, callback_data);
|
||||||
|
op->files = files;
|
||||||
|
op->renamed_files = 0;
|
||||||
|
op->skipped_files = 0;
|
||||||
|
|
||||||
|
for (l1 = files->next; l1 != NULL; l1 = l1->next) {
|
||||||
|
file = NAUTILUS_FILE (l1->data);
|
||||||
|
|
||||||
|
file->details->operations_in_progress = g_list_prepend (file->details->operations_in_progress,
|
||||||
|
op);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l1 = files, l2 = new_names; l1 != NULL && l2 != NULL; l1 = l1->next, l2 = l2->next) {
|
||||||
|
file = NAUTILUS_FILE (l1->data);
|
||||||
|
new_name = l2->data;
|
||||||
|
|
||||||
|
location = nautilus_file_get_location (file);
|
||||||
|
old_files = g_list_append (old_files, location);
|
||||||
|
|
||||||
|
new_file_name = nautilus_file_can_rename_file (file,
|
||||||
|
new_name->str,
|
||||||
|
callback,
|
||||||
|
callback_data);
|
||||||
|
|
||||||
|
if (new_file_name == NULL) {
|
||||||
|
op->skipped_files++;
|
||||||
|
|
||||||
|
new_file = nautilus_file_get_location (file);
|
||||||
|
new_files = g_list_append (new_files, new_file);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (G_IS_FILE (location));
|
||||||
|
|
||||||
|
/* Do the renaming. */
|
||||||
|
new_file = g_file_set_display_name (location,
|
||||||
|
new_file_name,
|
||||||
|
op->cancellable,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
data = g_new0 (BatchRenameData, 1);
|
||||||
|
data->op = op;
|
||||||
|
data->file = file;
|
||||||
|
|
||||||
|
new_files = g_list_append (new_files, new_file);
|
||||||
|
|
||||||
|
g_file_query_info_async (new_file,
|
||||||
|
NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
|
||||||
|
0,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
op->cancellable,
|
||||||
|
batch_rename_get_info_callback,
|
||||||
|
data);
|
||||||
|
|
||||||
|
if (error != NULL) {
|
||||||
|
g_warning ("Batch rename for file \"%s\" failed", nautilus_file_get_name (file));
|
||||||
|
g_error_free (error);
|
||||||
|
error = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the undo manager a batch rename is taking place */
|
||||||
|
if (!nautilus_file_undo_manager_is_operating ()) {
|
||||||
|
op->undo_info = nautilus_file_undo_info_batch_rename_new (g_list_length (new_files));
|
||||||
|
|
||||||
|
nautilus_file_undo_info_batch_rename_set_data_pre (NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (op->undo_info),
|
||||||
|
old_files);
|
||||||
|
|
||||||
|
nautilus_file_undo_info_batch_rename_set_data_post (NAUTILUS_FILE_UNDO_INFO_BATCH_RENAME (op->undo_info),
|
||||||
|
new_files);
|
||||||
|
|
||||||
|
nautilus_file_undo_manager_set_action (op->undo_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nautilus_file_rename_handle_file_gone (NautilusFile *file,
|
nautilus_file_rename_handle_file_gone (NautilusFile *file,
|
||||||
NautilusFileOperationCallback callback,
|
NautilusFileOperationCallback callback,
|
||||||
|
@ -1820,7 +2133,7 @@ nautilus_file_rename_handle_file_gone (NautilusFile *file,
|
||||||
GError *error;
|
GError *error;
|
||||||
|
|
||||||
if (nautilus_file_is_gone (file)) {
|
if (nautilus_file_is_gone (file)) {
|
||||||
/* Claim that something changed even if the rename
|
/* Claim that something changed even if the rename
|
||||||
* failed. This makes it easier for some clients who
|
* failed. This makes it easier for some clients who
|
||||||
* see the "reverting" to the old name as "changing
|
* see the "reverting" to the old name as "changing
|
||||||
* back".
|
* back".
|
||||||
|
@ -1836,6 +2149,18 @@ nautilus_file_rename_handle_file_gone (NautilusFile *file,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nautilus_file_batch_rename (GList *files,
|
||||||
|
GList *new_names,
|
||||||
|
NautilusFileOperationCallback callback,
|
||||||
|
gpointer callback_data)
|
||||||
|
{
|
||||||
|
real_batch_rename (files,
|
||||||
|
new_names,
|
||||||
|
callback,
|
||||||
|
callback_data);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
real_rename (NautilusFile *file,
|
real_rename (NautilusFile *file,
|
||||||
const char *new_name,
|
const char *new_name,
|
||||||
|
@ -1843,107 +2168,21 @@ real_rename (NautilusFile *file,
|
||||||
gpointer callback_data)
|
gpointer callback_data)
|
||||||
{
|
{
|
||||||
NautilusFileOperation *op;
|
NautilusFileOperation *op;
|
||||||
char *uri;
|
|
||||||
char *old_name;
|
char *old_name;
|
||||||
char *new_file_name;
|
char *new_file_name;
|
||||||
gboolean success, name_changed;
|
|
||||||
gboolean is_renameable_desktop_file;
|
|
||||||
GFile *location;
|
GFile *location;
|
||||||
GError *error;
|
|
||||||
|
|
||||||
g_return_if_fail (NAUTILUS_IS_FILE (file));
|
g_return_if_fail (NAUTILUS_IS_FILE (file));
|
||||||
g_return_if_fail (new_name != NULL);
|
g_return_if_fail (new_name != NULL);
|
||||||
g_return_if_fail (callback != NULL);
|
g_return_if_fail (callback != NULL);
|
||||||
|
|
||||||
is_renameable_desktop_file =
|
new_file_name = nautilus_file_can_rename_file (file,
|
||||||
is_desktop_file (file) && can_rename_desktop_file (file);
|
new_name,
|
||||||
|
callback,
|
||||||
/* Return an error for incoming names containing path separators.
|
callback_data);
|
||||||
* But not for .desktop files as '/' are allowed for them */
|
|
||||||
if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
|
if (new_file_name == NULL)
|
||||||
error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
||||||
_("Slashes are not allowed in filenames"));
|
|
||||||
(* callback) (file, NULL, error, callback_data);
|
|
||||||
g_error_free (error);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Can't rename a file that's already gone.
|
|
||||||
* We need to check this here because there may be a new
|
|
||||||
* file with the same name.
|
|
||||||
*/
|
|
||||||
if (nautilus_file_rename_handle_file_gone (file, callback, callback_data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Test the name-hasn't-changed case explicitly, for two reasons.
|
|
||||||
* (1) rename returns an error if new & old are same.
|
|
||||||
* (2) We don't want to send file-changed signal if nothing changed.
|
|
||||||
*/
|
|
||||||
if (!is_renameable_desktop_file &&
|
|
||||||
name_is (file, new_name)) {
|
|
||||||
(* callback) (file, NULL, NULL, callback_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Self-owned files can't be renamed. Test the name-not-actually-changing
|
|
||||||
* case before this case.
|
|
||||||
*/
|
|
||||||
if (nautilus_file_is_self_owned (file)) {
|
|
||||||
/* Claim that something changed even if the rename
|
|
||||||
* failed. This makes it easier for some clients who
|
|
||||||
* see the "reverting" to the old name as "changing
|
|
||||||
* back".
|
|
||||||
*/
|
|
||||||
nautilus_file_changed (file);
|
|
||||||
error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
||||||
_("Toplevel files cannot be renamed"));
|
|
||||||
|
|
||||||
(* callback) (file, NULL, error, callback_data);
|
|
||||||
g_error_free (error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_renameable_desktop_file) {
|
|
||||||
/* Don't actually change the name if the new name is the same.
|
|
||||||
* This helps for the vfolder method where this can happen and
|
|
||||||
* we want to minimize actual changes
|
|
||||||
*/
|
|
||||||
uri = nautilus_file_get_uri (file);
|
|
||||||
old_name = nautilus_link_local_get_text (uri);
|
|
||||||
if (old_name != NULL && strcmp (new_name, old_name) == 0) {
|
|
||||||
success = TRUE;
|
|
||||||
name_changed = FALSE;
|
|
||||||
} else {
|
|
||||||
success = nautilus_link_local_set_text (uri, new_name);
|
|
||||||
name_changed = TRUE;
|
|
||||||
}
|
|
||||||
g_free (old_name);
|
|
||||||
g_free (uri);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
_("Probably the content of the file is an invalid desktop file format"));
|
|
||||||
(* callback) (file, NULL, error, callback_data);
|
|
||||||
g_error_free (error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
new_file_name = g_strdup_printf ("%s.desktop", new_name);
|
|
||||||
new_file_name = g_strdelimit (new_file_name, "/", '-');
|
|
||||||
|
|
||||||
if (name_is (file, new_file_name)) {
|
|
||||||
if (name_changed) {
|
|
||||||
nautilus_file_invalidate_attributes (file,
|
|
||||||
NAUTILUS_FILE_ATTRIBUTE_INFO |
|
|
||||||
NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
|
|
||||||
}
|
|
||||||
|
|
||||||
(* callback) (file, NULL, NULL, callback_data);
|
|
||||||
g_free (new_file_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
new_file_name = g_strdup (new_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up a renaming operation. */
|
/* Set up a renaming operation. */
|
||||||
op = nautilus_file_operation_new (file, callback, callback_data);
|
op = nautilus_file_operation_new (file, callback, callback_data);
|
||||||
|
|
|
@ -324,6 +324,10 @@ void nautilus_file_rename (Nautilu
|
||||||
const char *new_name,
|
const char *new_name,
|
||||||
NautilusFileOperationCallback callback,
|
NautilusFileOperationCallback callback,
|
||||||
gpointer callback_data);
|
gpointer callback_data);
|
||||||
|
void nautilus_file_batch_rename (GList *files,
|
||||||
|
GList *new_names,
|
||||||
|
NautilusFileOperationCallback callback,
|
||||||
|
gpointer callback_data);
|
||||||
void nautilus_file_cancel (NautilusFile *file,
|
void nautilus_file_cancel (NautilusFile *file,
|
||||||
NautilusFileOperationCallback callback,
|
NautilusFileOperationCallback callback,
|
||||||
gpointer callback_data);
|
gpointer callback_data);
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include "nautilus-files-view.h"
|
#include "nautilus-files-view.h"
|
||||||
|
|
||||||
#include "nautilus-application.h"
|
#include "nautilus-application.h"
|
||||||
|
#include "nautilus-batch-rename-dialog.h"
|
||||||
|
#include "nautilus-batch-rename-utilities.h"
|
||||||
#include "nautilus-error-reporting.h"
|
#include "nautilus-error-reporting.h"
|
||||||
#include "nautilus-file-undo-manager.h"
|
#include "nautilus-file-undo-manager.h"
|
||||||
#include "nautilus-floating-bar.h"
|
#include "nautilus-floating-bar.h"
|
||||||
|
@ -5566,6 +5568,7 @@ real_action_rename (NautilusFilesView *view)
|
||||||
{
|
{
|
||||||
NautilusFile *file;
|
NautilusFile *file;
|
||||||
GList *selection;
|
GList *selection;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
|
||||||
g_assert (NAUTILUS_IS_FILES_VIEW (view));
|
g_assert (NAUTILUS_IS_FILES_VIEW (view));
|
||||||
|
|
||||||
|
@ -5576,6 +5579,21 @@ real_action_rename (NautilusFilesView *view)
|
||||||
if (selection->next != NULL) {
|
if (selection->next != NULL) {
|
||||||
if (have_bulk_rename_tool ()) {
|
if (have_bulk_rename_tool ()) {
|
||||||
invoke_external_bulk_rename_utility (view, selection);
|
invoke_external_bulk_rename_utility (view, selection);
|
||||||
|
} else {
|
||||||
|
GdkCursor *cursor;
|
||||||
|
GdkDisplay *display;
|
||||||
|
|
||||||
|
display = gtk_widget_get_display (GTK_WIDGET (nautilus_files_view_get_window (view)));
|
||||||
|
cursor = gdk_cursor_new_from_name (display, "progress");
|
||||||
|
gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (nautilus_files_view_get_window (view))),
|
||||||
|
cursor);
|
||||||
|
g_object_unref (cursor);
|
||||||
|
|
||||||
|
dialog = nautilus_batch_rename_dialog_new (nautilus_files_view_get_selection (NAUTILUS_VIEW (view)),
|
||||||
|
nautilus_files_view_get_model (view),
|
||||||
|
nautilus_files_view_get_window (view));
|
||||||
|
|
||||||
|
gtk_widget_show (GTK_WIDGET (dialog));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file = NAUTILUS_FILE (selection->data);
|
file = NAUTILUS_FILE (selection->data);
|
||||||
|
@ -6625,8 +6643,12 @@ real_update_actions_state (NautilusFilesView *view)
|
||||||
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
|
action = g_action_map_lookup_action (G_ACTION_MAP (view_action_group),
|
||||||
"rename");
|
"rename");
|
||||||
if (selection_count > 1) {
|
if (selection_count > 1) {
|
||||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
if (have_bulk_rename_tool())
|
||||||
have_bulk_rename_tool ());
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||||
|
have_bulk_rename_tool ());
|
||||||
|
else
|
||||||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||||
|
nautilus_file_can_rename_files (selection));
|
||||||
} else {
|
} else {
|
||||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||||
selection_count == 1 &&
|
selection_count == 1 &&
|
||||||
|
|
|
@ -169,3 +169,19 @@
|
||||||
* always allocates at least 1 pixel */
|
* always allocates at least 1 pixel */
|
||||||
searchbar { border-top: 1px solid @borders; }
|
searchbar { border-top: 1px solid @borders; }
|
||||||
.searchbar-container { margin-top: -1px; }
|
.searchbar-container { margin-top: -1px; }
|
||||||
|
|
||||||
|
@define-color conflict_bg #fef6b6;
|
||||||
|
|
||||||
|
.conflict-row {
|
||||||
|
background: @conflict_bg;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.conflict-row:hover {
|
||||||
|
background-color: shade(@conflict_bg, 0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.conflict-row:selected {
|
||||||
|
background: @theme_selected_bg_color;
|
||||||
|
color: @theme_selected_fg_color;
|
||||||
|
}
|
|
@ -18,6 +18,7 @@
|
||||||
<file>ui/nautilus-no-search-results.ui</file>
|
<file>ui/nautilus-no-search-results.ui</file>
|
||||||
<file>ui/nautilus-folder-is-empty.ui</file>
|
<file>ui/nautilus-folder-is-empty.ui</file>
|
||||||
<file>gtk/help-overlay.ui</file>
|
<file>gtk/help-overlay.ui</file>
|
||||||
|
<file>ui/nautilus-batch-rename-dialog.ui</file>
|
||||||
<file alias="gtk/ui/nautilusgtkplacesview.ui">../gtk/nautilusgtkplacesview.ui</file>
|
<file alias="gtk/ui/nautilusgtkplacesview.ui">../gtk/nautilusgtkplacesview.ui</file>
|
||||||
<file alias="gtk/ui/nautilusgtkplacesviewrow.ui">../gtk/nautilusgtkplacesviewrow.ui</file>
|
<file alias="gtk/ui/nautilusgtkplacesviewrow.ui">../gtk/nautilusgtkplacesviewrow.ui</file>
|
||||||
<file alias="icons/thumbnail_frame.png">../../icons/thumbnail_frame.png</file>
|
<file alias="icons/thumbnail_frame.png">../../icons/thumbnail_frame.png</file>
|
||||||
|
|
502
src/resources/ui/nautilus-batch-rename-dialog.ui
Normal file
502
src/resources/ui/nautilus-batch-rename-dialog.ui
Normal file
|
@ -0,0 +1,502 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<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"/>
|
||||||
|
<child type="action">
|
||||||
|
<object class="GtkButton" id="cancel_button">
|
||||||
|
<property name="label" translatable="yes">_Cancel</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="action">
|
||||||
|
<object class="GtkButton" id="rename_button">
|
||||||
|
<property name="label" translatable="yes">_Rename</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="can_default">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="suggested-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<action-widgets>
|
||||||
|
<action-widget response="ok" default="true">rename_button</action-widget>
|
||||||
|
<action-widget response="cancel">cancel_button</action-widget>
|
||||||
|
</action-widgets>
|
||||||
|
<child internal-child="vbox">
|
||||||
|
<object class="GtkBox" id="vbox">
|
||||||
|
<property name="border-width">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="grid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="margin">0</property>
|
||||||
|
<property name="row-spacing">6</property>
|
||||||
|
<property name="column-spacing">6</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="row-homogeneous">False</property>
|
||||||
|
<property name="column-homogeneous">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">15</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="margin">20</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="format_mode_button">
|
||||||
|
<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>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<signal name="toggled" handler="batch_rename_dialog_mode_changed" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="replace_mode_button">
|
||||||
|
<property name="label" translatable="yes">Find and replace _text</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="group">format_mode_button</property>
|
||||||
|
<signal name="toggled" handler="batch_rename_dialog_mode_changed" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">3</property>
|
||||||
|
<property name="top-attach">0</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkStack" id="mode_stack">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="vhomogeneous">False</property>
|
||||||
|
<property name="hhomogeneous">True</property>
|
||||||
|
<property name="transition_type">crossfade</property>
|
||||||
|
<property name="transition_duration">100</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="format_stack_child">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="margin-left">40</property>
|
||||||
|
<property name="margin-right">40</property>
|
||||||
|
<property name="margin-top">0</property>
|
||||||
|
<property name="margin-bottom">10</property>
|
||||||
|
<property name="row-spacing">15</property>
|
||||||
|
<property name="column-spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="name_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="has_focus">True</property>
|
||||||
|
<property name="width_request">400</property>
|
||||||
|
<property name="hexpand">False</property>
|
||||||
|
<property name="activates-default">True</property>
|
||||||
|
<signal name="changed" handler="file_names_widget_entry_on_changed" swapped="yes" />
|
||||||
|
<signal name="activate" handler="file_names_widget_on_activate" swapped="yes" />
|
||||||
|
<signal name="key-press-event" handler="on_key_press_event" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="add_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="toggled" handler="add_button_clicked" swapped="yes" />
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">0</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">list-add-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Add</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="linked"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">0</property>
|
||||||
|
<property name="width">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="numbering_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Automatic Numbering Order</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="height-request">35</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkToggleButton" id="numbering_order_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<signal name="toggled" handler="numbering_order_button_clicked" swapped="yes" />
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">15</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="numbering_order_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="width-request">180</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
<property name="label" translatable="yes">Original name (Ascending)</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="action_icon">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">pan-down-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">4</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">format</property>
|
||||||
|
<property name="title" translatable="yes">Format</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="replace_stack_child">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="margin-left">40</property>
|
||||||
|
<property name="margin-right">40</property>
|
||||||
|
<property name="margin-top">0</property>
|
||||||
|
<property name="margin-bottom">10</property>
|
||||||
|
<property name="row-spacing">16</property>
|
||||||
|
<property name="column-spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="existing_text_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Existing Text</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">0</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="find_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="width_request">375</property>
|
||||||
|
<property name="hexpand">False</property>
|
||||||
|
<property name="activates-default">True</property>
|
||||||
|
<signal name="changed" handler="file_names_widget_entry_on_changed" swapped="yes" />
|
||||||
|
<signal name="activate" handler="file_names_widget_on_activate" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">0</property>
|
||||||
|
<property name="width">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="replace_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes">Replace With</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
<property name="width">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="replace_entry">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="width_request">375</property>
|
||||||
|
<signal name="changed" handler="file_names_widget_entry_on_changed" swapped="yes" />
|
||||||
|
<signal name="activate" handler="file_names_widget_on_activate" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">1</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
<property name="width">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">replace</property>
|
||||||
|
<property name="title" translatable="yes">Replace</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">1</property>
|
||||||
|
<property name="width">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="scrolled_window">
|
||||||
|
<property name="height_request">250</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="hexpand">False</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkViewport">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="a_box">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="original_name_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="arrow_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="result_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">2</property>
|
||||||
|
<property name="width">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="conflict_box">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<property name="visible">False</property>
|
||||||
|
<property name="margin-left">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="conflict_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack-type">start</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">horizontal</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="conflict_down">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="relief">none</property>
|
||||||
|
<signal name="clicked" handler="select_next_conflict_down" swapped="yes" />
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">go-down-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="conflict_up">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="relief">GTK_RELIEF_NONE</property>
|
||||||
|
<signal name="clicked" handler="select_next_conflict_up" swapped="yes" />
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon-name">go-up-symbolic</property>
|
||||||
|
<property name="icon-size">1</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack-type">end</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left-attach">0</property>
|
||||||
|
<property name="top-attach">3</property>
|
||||||
|
<property name="width">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
<menu id="add_tag_menu">
|
||||||
|
<section>
|
||||||
|
<attribute name="label" translatable="yes">Automatic Numbers</attribute>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">1, 2, 3, 4</attribute>
|
||||||
|
<attribute name="action">dialog.add-numbering-tag-zero</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">01, 02, 03, 04</attribute>
|
||||||
|
<attribute name="action">dialog.add-numbering-tag-one</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">001, 002, 003, 004</attribute>
|
||||||
|
<attribute name="action">dialog.add-numbering-tag-two</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<attribute name="label" translatable="yes">Metadata</attribute>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Creation Date</attribute>
|
||||||
|
<attribute name="action">dialog.add-creation-date-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Camera Model</attribute>
|
||||||
|
<attribute name="action">dialog.add-equipment-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Season Number</attribute>
|
||||||
|
<attribute name="action">dialog.add-season-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Episode Number</attribute>
|
||||||
|
<attribute name="action">dialog.add-episode-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Track Number</attribute>
|
||||||
|
<attribute name="action">dialog.add-track-number-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Artist Name</attribute>
|
||||||
|
<attribute name="action">dialog.add-artist-name-tag</attribute>
|
||||||
|
<attribute name="hidden-when">action-disabled</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Title</attribute>
|
||||||
|
<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>
|
||||||
|
<attribute name="label" translatable="yes">Original File Name</attribute>
|
||||||
|
<attribute name="action">dialog.add-original-file-name-tag</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
</menu>
|
||||||
|
<object class="GtkPopover" id="add_popover">
|
||||||
|
<property name="position">bottom</property>
|
||||||
|
<property name="relative-to">add_button</property>
|
||||||
|
<signal name="closed" handler="add_popover_closed" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="done_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="icon_name">object-select-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<menu id="numbering_order_menu">
|
||||||
|
<section>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Original name (Ascending) </attribute>
|
||||||
|
<attribute name="action">dialog.numbering-order-changed</attribute>
|
||||||
|
<attribute name="target">name-ascending</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Original name (Descending)</attribute>
|
||||||
|
<attribute name="action">dialog.numbering-order-changed</attribute>
|
||||||
|
<attribute name="target">name-descending</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">First Modified</attribute>
|
||||||
|
<attribute name="action">dialog.numbering-order-changed</attribute>
|
||||||
|
<attribute name="target">first-modified</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Last Modified</attribute>
|
||||||
|
<attribute name="action">dialog.numbering-order-changed</attribute>
|
||||||
|
<attribute name="target">last-modified</attribute>
|
||||||
|
</item>
|
||||||
|
</section>
|
||||||
|
</menu>
|
||||||
|
<object class="GtkPopover" id="numbering_order_popover">
|
||||||
|
<property name="position">bottom</property>
|
||||||
|
<property name="relative-to">numbering_order_button</property>
|
||||||
|
<signal name="closed" handler="numbering_order_popover_closed" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -215,7 +215,7 @@
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">Rena_me</attribute>
|
<attribute name="label" translatable="yes">Rena_me…</attribute>
|
||||||
<attribute name="action">view.rename</attribute>
|
<attribute name="action">view.rename</attribute>
|
||||||
</item>
|
</item>
|
||||||
</section>
|
</section>
|
||||||
|
|
Loading…
Reference in a new issue