[gthumb] move files if possible instead of always copying and deleting
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] move files if possible instead of always copying and deleting
- Date: Wed, 18 Apr 2018 19:35:53 +0000 (UTC)
commit 7525b459104d2bbe2fd33d7ee780468c6eddd304
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Apr 18 10:45:38 2018 +0200
move files if possible instead of always copying and deleting
extensions/file_manager/gth-duplicate-task.c | 1 +
gthumb/gio-utils.c | 233 +++++++++++++++++---------
gthumb/gio-utils.h | 1 +
gthumb/gth-overwrite-dialog.c | 2 +
4 files changed, 161 insertions(+), 76 deletions(-)
---
diff --git a/extensions/file_manager/gth-duplicate-task.c b/extensions/file_manager/gth-duplicate-task.c
index 9c6459d..ab91105 100644
--- a/extensions/file_manager/gth-duplicate-task.c
+++ b/extensions/file_manager/gth-duplicate-task.c
@@ -77,6 +77,7 @@ static void duplicate_current_file (GthDuplicateTask *self);
static void
copy_ready_cb (GthOverwriteResponse response,
+ GList *other_files,
GError *error,
gpointer user_data)
{
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index 034724b..0a0eb8b 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -1108,6 +1108,7 @@ typedef struct {
gpointer dialog_callback_data;
CopyReadyCallback ready_callback;
gpointer user_data;
+ gboolean move_succeed;
GFile *current_destination;
char *message;
@@ -1140,10 +1141,12 @@ copy_file__delete_source (CopyFileData *copy_file_data)
{
GError *error = NULL;
- if (copy_file_data->move)
+ /* delete the source if we are moving the file but the move operation
+ * is not supported. */
+ if (copy_file_data->move && ! copy_file_data->move_succeed)
g_file_delete (copy_file_data->source->file, copy_file_data->cancellable, &error);
- copy_file_data->ready_callback (copy_file_data->default_response, error, copy_file_data->user_data);
+ copy_file_data->ready_callback (copy_file_data->default_response, copy_file_data->source_sidecars,
error, copy_file_data->user_data);
copy_file_data_free (copy_file_data);
}
@@ -1212,6 +1215,28 @@ copy_file__copy_current_sidecar (CopyFileData *copy_file_data)
}
+static void
+copy_file__copy_sidecars (CopyFileData *copy_file_data)
+{
+ /* copy the metadata sidecars if requested */
+
+ _g_object_list_unref (copy_file_data->source_sidecars);
+ _g_object_list_unref (copy_file_data->destination_sidecars);
+ copy_file_data->source_sidecars = NULL;
+ copy_file_data->destination_sidecars = NULL;
+ if (copy_file_data->flags & GTH_FILE_COPY_ALL_METADATA) {
+ gth_hook_invoke ("add-sidecars", copy_file_data->source->file,
©_file_data->source_sidecars);
+ gth_hook_invoke ("add-sidecars", copy_file_data->destination,
©_file_data->destination_sidecars);
+ copy_file_data->source_sidecars = g_list_reverse (copy_file_data->source_sidecars);
+ copy_file_data->destination_sidecars = g_list_reverse (copy_file_data->destination_sidecars);
+ }
+
+ copy_file_data->current_source_sidecar = copy_file_data->source_sidecars;
+ copy_file_data->current_destination_sidecar = copy_file_data->destination_sidecars;
+ copy_file__copy_current_sidecar (copy_file_data);
+}
+
+
static void _g_copy_file_to_destination (CopyFileData *copy_file_data,
GFile *destination,
GFileCopyFlags flags);
@@ -1246,7 +1271,7 @@ copy_file__overwrite_dialog_response_cb (GtkDialog *dialog,
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, "");
else
error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_EXISTS, "");
- copy_file_data->ready_callback (copy_file_data->default_response, error,
copy_file_data->user_data);
+ copy_file_data->ready_callback (copy_file_data->default_response, NULL, error,
copy_file_data->user_data);
copy_file_data_free (copy_file_data);
return;
}
@@ -1276,69 +1301,66 @@ copy_file__overwrite_dialog_response_cb (GtkDialog *dialog,
static void
-copy_file_ready_cb (GObject *source_object,
- GAsyncResult *result,
- gpointer user_data)
+copy_file__handle_error (CopyFileData *copy_file_data,
+ GError *error)
{
- CopyFileData *copy_file_data = user_data;
- GError *error = NULL;
+ g_return_if_fail (GTH_IS_FILE_DATA (copy_file_data->source));
+ g_return_if_fail (G_IS_FILE (copy_file_data->source->file));
- if (! g_file_copy_finish ((GFile *) source_object, result, &error)) {
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
- if (copy_file_data->duplicating_file) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
+ if (copy_file_data->duplicating_file) {
- /* the duplicated file already exists, try another one */
+ /* the duplicated file already exists, try another one */
- GFile *new_destination = _g_file_get_duplicated
(copy_file_data->current_destination);
- _g_copy_file_to_destination (copy_file_data, new_destination,
G_FILE_COPY_NONE);
+ GFile *new_destination = _g_file_get_duplicated (copy_file_data->current_destination);
+ _g_copy_file_to_destination (copy_file_data, new_destination, G_FILE_COPY_NONE);
- g_object_unref (new_destination);
- }
- else if (copy_file_data->default_response != GTH_OVERWRITE_RESPONSE_ALWAYS_NO) {
- GtkWidget *dialog;
-
- dialog = gth_overwrite_dialog_new (copy_file_data->source->file,
- NULL,
- copy_file_data->current_destination,
- copy_file_data->default_response,
- copy_file_data->tot_files == 1);
-
- if (copy_file_data->dialog_callback != NULL)
- copy_file_data->dialog_callback (TRUE, dialog,
copy_file_data->dialog_callback_data);
-
- g_signal_connect (dialog,
- "response",
- G_CALLBACK (copy_file__overwrite_dialog_response_cb),
- copy_file_data);
- gtk_widget_show (dialog);
- }
- else {
- copy_file_data->ready_callback (copy_file_data->default_response, error,
copy_file_data->user_data);
- copy_file_data_free (copy_file_data);
- }
- return;
+ g_object_unref (new_destination);
+ }
+ else if (copy_file_data->default_response != GTH_OVERWRITE_RESPONSE_ALWAYS_NO) {
+ GtkWidget *dialog;
+
+ dialog = gth_overwrite_dialog_new (copy_file_data->source->file,
+ NULL,
+ copy_file_data->current_destination,
+ copy_file_data->default_response,
+ copy_file_data->tot_files == 1);
+
+ if (copy_file_data->dialog_callback != NULL)
+ copy_file_data->dialog_callback (TRUE, dialog,
copy_file_data->dialog_callback_data);
+
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (copy_file__overwrite_dialog_response_cb),
+ copy_file_data);
+ gtk_widget_show (dialog);
}
- copy_file_data->ready_callback (copy_file_data->default_response, error,
copy_file_data->user_data);
+ else {
+ copy_file_data->ready_callback (copy_file_data->default_response, NULL, error,
copy_file_data->user_data);
+ copy_file_data_free (copy_file_data);
+ }
+ }
+ else {
+ copy_file_data->ready_callback (copy_file_data->default_response, NULL, error,
copy_file_data->user_data);
copy_file_data_free (copy_file_data);
- return;
}
+}
- /* copy the metadata sidecars if requested */
- _g_object_list_unref (copy_file_data->source_sidecars);
- _g_object_list_unref (copy_file_data->destination_sidecars);
- copy_file_data->source_sidecars = NULL;
- copy_file_data->destination_sidecars = NULL;
- if (copy_file_data->flags & GTH_FILE_COPY_ALL_METADATA) {
- gth_hook_invoke ("add-sidecars", copy_file_data->source->file,
©_file_data->source_sidecars);
- gth_hook_invoke ("add-sidecars", copy_file_data->destination,
©_file_data->destination_sidecars);
- copy_file_data->source_sidecars = g_list_reverse (copy_file_data->source_sidecars);
- copy_file_data->destination_sidecars = g_list_reverse (copy_file_data->destination_sidecars);
+static void
+copy_file_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CopyFileData *copy_file_data = user_data;
+ GError *error = NULL;
+
+ if (! g_file_copy_finish (G_FILE (source_object), result, &error)) {
+ copy_file__handle_error (copy_file_data, error);
+ return;
}
- copy_file_data->current_source_sidecar = copy_file_data->source_sidecars;
- copy_file_data->current_destination_sidecar = copy_file_data->destination_sidecars;
- copy_file__copy_current_sidecar (copy_file_data);
+ copy_file__copy_sidecars (copy_file_data);
}
@@ -1378,14 +1400,14 @@ _g_copy_file_to_destination_call_ready_callback (gpointer user_data)
{
CopyFileData *copy_file_data = user_data;
- copy_file_data->ready_callback (copy_file_data->default_response, NULL, copy_file_data->user_data);
+ copy_file_data->ready_callback (copy_file_data->default_response, NULL, NULL,
copy_file_data->user_data);
copy_file_data_free (copy_file_data);
}
static void
make_directory_ready_cb (GObject *source_object,
- GAsyncResult *result,
+ GAsyncResult *result,
gpointer user_data)
{
CopyFileData *copy_file_data = user_data;
@@ -1396,7 +1418,7 @@ make_directory_ready_cb (GObject *source_object,
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
g_clear_error (&error);
- copy_file_data->ready_callback (copy_file_data->default_response, error, copy_file_data->user_data);
+ copy_file_data->ready_callback (copy_file_data->default_response, NULL, error,
copy_file_data->user_data);
copy_file_data_free (copy_file_data);
}
@@ -1457,23 +1479,53 @@ _g_copy_file_to_destination (CopyFileData *copy_file_data,
g_object_unref (destination_parent);
}
- if (g_file_info_get_file_type (copy_file_data->source->info) == G_FILE_TYPE_DIRECTORY)
+ switch (g_file_info_get_file_type (copy_file_data->source->info)) {
+ case G_FILE_TYPE_DIRECTORY:
/* FIXME: handle the GTH_FILE_COPY_RENAME_SAME_FILE flag for directories */
g_file_make_directory_async (copy_file_data->current_destination,
copy_file_data->io_priority,
copy_file_data->cancellable,
make_directory_ready_cb,
copy_file_data);
- else
+ break;
+
+ default:
+ if (copy_file_data->move) {
+ GError *error = NULL;
+
+ flags |= G_FILE_COPY_NO_FALLBACK_FOR_MOVE;
+ if (g_file_move (copy_file_data->source->file,
+ copy_file_data->current_destination,
+ flags,
+ copy_file_data->cancellable,
+ copy_file_progress_cb,
+ copy_file_data,
+ &error))
+ {
+ copy_file_data->move_succeed = TRUE;
+ copy_file__copy_sidecars (copy_file_data);
+ return;
+ }
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
+ /* fallback to copy and delete */
+ }
+ else {
+ copy_file__handle_error (copy_file_data, error);
+ return;
+ }
+ }
+
g_file_copy_async (copy_file_data->source->file,
- copy_file_data->current_destination,
- flags,
- copy_file_data->io_priority,
- copy_file_data->cancellable,
- copy_file_progress_cb,
- copy_file_data,
- copy_file_ready_cb,
- copy_file_data);
+ copy_file_data->current_destination,
+ flags,
+ copy_file_data->io_priority,
+ copy_file_data->cancellable,
+ copy_file_progress_cb,
+ copy_file_data,
+ copy_file_ready_cb,
+ copy_file_data);
+ break;
+ }
}
@@ -1497,6 +1549,9 @@ _g_copy_file_async_private (GthFileData *source,
{
CopyFileData *copy_file_data;
+ g_return_if_fail (GTH_IS_FILE_DATA (source));
+ g_return_if_fail (G_IS_FILE (destination));
+
copy_file_data = g_new0 (CopyFileData, 1);
copy_file_data->source = g_object_ref (source);
copy_file_data->destination = g_object_ref (destination);
@@ -1514,6 +1569,7 @@ _g_copy_file_async_private (GthFileData *source,
copy_file_data->ready_callback = ready_callback;
copy_file_data->user_data = user_data;
copy_file_data->default_response = default_response;
+ copy_file_data->move_succeed = FALSE;
_g_copy_file_to_destination (copy_file_data, copy_file_data->destination, G_FILE_COPY_NONE);
}
@@ -1563,6 +1619,7 @@ typedef struct {
GList *files; /* GthFileData list */
GList *current;
GList *copied_directories; /* GFile list */
+ GHashTable *copied_files;
GFile *source_base;
GFile *current_destination;
@@ -1599,6 +1656,7 @@ copy_data_free (CopyData *copy_data)
_g_object_list_unref (copy_data->source_sidecars);
_g_object_unref (copy_data->current_destination);
_g_object_list_unref (copy_data->copied_directories);
+ g_hash_table_destroy (copy_data->copied_files);
_g_object_list_unref (copy_data->files);
_g_object_unref (copy_data->source_base);
g_hash_table_destroy (copy_data->source_hash);
@@ -1633,18 +1691,18 @@ copy_data__copy_next_file (CopyData *copy_data)
static void
copy_data__copy_current_file_ready_cb (GthOverwriteResponse response,
+ GList *other_files,
GError *error,
gpointer user_data)
{
- CopyData *copy_data = user_data;
+ CopyData *copy_data = user_data;
+ GthFileData *source = (GthFileData *) copy_data->current->data;
+ GList *scan;
if (error == NULL) {
/* save the correctly copied directories in order to delete
* them after moving their content. */
if (copy_data->move) {
- GthFileData *source;
-
- source = (GthFileData *) copy_data->current->data;
if (g_file_info_get_file_type (source->info) == G_FILE_TYPE_DIRECTORY)
copy_data->copied_directories = g_list_prepend
(copy_data->copied_directories, g_file_dup (source->file));
}
@@ -1654,6 +1712,12 @@ copy_data__copy_current_file_ready_cb (GthOverwriteResponse response,
return;
}
+ g_hash_table_insert (copy_data->copied_files, g_file_dup (source->file), GINT_TO_POINTER (1));
+ for (scan = other_files; scan != NULL; scan = scan->next) {
+ GFile *other_file = G_FILE (scan->data);
+ g_hash_table_insert (copy_data->copied_files, g_file_dup (other_file), GINT_TO_POINTER (1));
+ }
+
copy_data->default_response = response;
copy_data__copy_next_file (copy_data);
}
@@ -1670,8 +1734,16 @@ copy_data__delete_source_directories (CopyData *copy_data)
for (scan = copy_data->copied_directories; scan; scan = scan->next) {
GFile *file = scan->data;
- if (! g_file_delete (file, copy_data->cancellable, &error))
- break;
+ if (! g_file_delete (file, copy_data->cancellable, &error)) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY)) {
+ /* ignore this kind of errors, because
+ * it is caused by the user choice of
+ * not move a file. */
+ g_clear_error (&error);
+ }
+ else
+ break;
+ }
}
}
@@ -1691,13 +1763,21 @@ copy_data__copy_current_file (CopyData *copy_data)
return;
}
- source = (GthFileData *) copy_data->current->data;
- explicitly_requested = (g_hash_table_lookup (copy_data->source_hash, source->file) != NULL);
+ source = GTH_FILE_DATA (copy_data->current->data);
+
+ /* Ignore already copied files. These are sidecar files already copied
+ * with _g_copy_file_async_private */
+
+ if (g_hash_table_lookup (copy_data->copied_files, source->file) != NULL) {
+ call_when_idle ((DataFunc) copy_data__copy_next_file, copy_data);
+ return;
+ }
/* Ignore non-existent files that weren't explicitly requested,
* they are children of some requested directory and if they don't
* exist anymore they have been already moved to the destination
* because they are metadata of other files. */
+ explicitly_requested = (g_hash_table_lookup (copy_data->source_hash, source->file) != NULL);
if (! explicitly_requested) {
if (! g_file_query_exists (source->file, copy_data->cancellable)) {
call_when_idle ((DataFunc) copy_data__copy_next_file, copy_data);
@@ -1750,7 +1830,7 @@ copy_files__sources_info_ready_cb (GList *files,
copy_data->tot_size = 0;
copy_data->tot_files = 0;
for (scan = copy_data->files; scan; scan = scan->next) {
- GthFileData *file_data = (GthFileData *) scan->data;
+ GthFileData *file_data = GTH_FILE_DATA (scan->data);
copy_data->tot_size += g_file_info_get_size (file_data->info);
copy_data->tot_files += 1;
@@ -1793,6 +1873,7 @@ _g_copy_files_async (GList *sources, /* GFile list */
copy_data->done_callback = done_callback;
copy_data->user_data = user_data;
copy_data->default_response = default_response;
+ copy_data->copied_files = g_hash_table_new_full ((GHashFunc) g_file_hash, (GEqualFunc) g_file_equal,
(GDestroyNotify) g_object_unref, NULL);
/* save the explicitly requested files */
copy_data->source_hash = g_hash_table_new_full ((GHashFunc) g_file_hash, (GEqualFunc) g_file_equal,
(GDestroyNotify) g_object_unref, NULL);
diff --git a/gthumb/gio-utils.h b/gthumb/gio-utils.h
index 1fcea2c..8184fd0 100644
--- a/gthumb/gio-utils.h
+++ b/gthumb/gio-utils.h
@@ -71,6 +71,7 @@ typedef void (*InfoReadyCallback) (GList *files,
GError *error,
gpointer user_data);
typedef void (*CopyReadyCallback) (GthOverwriteResponse default_response,
+ GList *other_files,
GError *error,
gpointer user_data);
diff --git a/gthumb/gth-overwrite-dialog.c b/gthumb/gth-overwrite-dialog.c
index 9546a8b..0fda5d6 100644
--- a/gthumb/gth-overwrite-dialog.c
+++ b/gthumb/gth-overwrite-dialog.c
@@ -331,6 +331,8 @@ gth_overwrite_dialog_new (GFile *source,
{
GthOverwriteDialog *self;
+ g_return_val_if_fail (G_IS_FILE (source), NULL);
+
self = g_object_new (GTH_TYPE_OVERWRITE_DIALOG,
"use-header-bar", _gtk_settings_get_dialogs_use_header (),
NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]