Nautilus used to handle all the error handling in its asynchronous gnome_vfs_async_xfer callback, but it is not guaranteed to be always called, so problems may remain unhandled and cause data loss ([1]). [2] has some details. This patch still needs some serious testing. [1] http://bugzilla.gnome.org/show_bug.cgi?id=144726 [2] http://blogs.gnome.org/edit/cneumair/2006/01/10 -- Christian Neumair <chris gnome-de org>
Index: libnautilus-private/nautilus-file-operations.c =================================================================== RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-file-operations.c,v retrieving revision 1.203 diff -u -p -r1.203 nautilus-file-operations.c --- libnautilus-private/nautilus-file-operations.c 18 Dec 2005 01:21:18 -0000 1.203 +++ libnautilus-private/nautilus-file-operations.c 10 Jan 2006 20:26:33 -0000 @@ -59,24 +59,28 @@ #include "nautilus-link.h" #include "nautilus-trash-monitor.h" -typedef enum TransferKind TransferKind; -typedef struct TransferInfo TransferInfo; +typedef enum OperationKind OperationKind; +typedef struct OperationInfo OperationInfo; typedef struct IconPositionIterator IconPositionIterator; -enum TransferKind { +static void icon_position_iterator_free (IconPositionIterator *position_iterator); + +enum OperationKind { TRANSFER_MOVE, TRANSFER_COPY, TRANSFER_DUPLICATE, TRANSFER_MOVE_TO_TRASH, TRANSFER_EMPTY_TRASH, TRANSFER_DELETE, - TRANSFER_LINK + TRANSFER_LINK, + CREATE_FOLDER, + CREATE_FILE }; /* Copy engine callback state */ -struct TransferInfo { +struct OperationInfo { + /* basic info */ GnomeVFSAsyncHandle *handle; - NautilusFileOperationsProgress *progress_dialog; const char *operation_title; /* "Copying files" */ const char *action_label; /* "Files copied:" */ const char *progress_verb; /* "Copying" */ @@ -85,41 +89,47 @@ struct TransferInfo { GnomeVFSXferErrorMode error_mode; GnomeVFSXferOverwriteMode overwrite_mode; GtkWidget *parent_view; - TransferKind kind; - void (* done_callback) (GHashTable *debuting_uris, gpointer data); - gpointer done_callback_data; + OperationKind kind; + void (* done_callback) (GHashTable *debuting_uris, gpointer user_data); + gpointer done_callback_user_data; GHashTable *debuting_uris; gboolean cancelled; + NautilusFileOperationsProgress *progress_dialog; IconPositionIterator *iterator; + int last_sync_response; }; -static TransferInfo * -transfer_info_new (GtkWidget *parent_view) +static OperationInfo * +operation_info_new (GtkWidget *parent_view) { - TransferInfo *result; - - result = g_new0 (TransferInfo, 1); + OperationInfo *result; + + result = g_new0 (OperationInfo, 1); result->parent_view = parent_view; - + result->debuting_uris = g_hash_table_new_full + (g_str_hash, g_str_equal, g_free, NULL); + eel_add_weak_pointer (&result->parent_view); return result; } static void -transfer_info_destroy (TransferInfo *transfer_info) +operation_info_destroy (OperationInfo *operation_info) { - eel_remove_weak_pointer (&transfer_info->parent_view); - - if (transfer_info->progress_dialog != NULL) { - nautilus_file_operations_progress_done (transfer_info->progress_dialog); + eel_remove_weak_pointer (&operation_info->parent_view); + + icon_position_iterator_free (operation_info->iterator); + + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_done (operation_info->progress_dialog); } - if (transfer_info->debuting_uris != NULL) { - g_hash_table_destroy (transfer_info->debuting_uris); + if (operation_info->debuting_uris != NULL) { + g_hash_table_destroy (operation_info->debuting_uris); } - g_free (transfer_info); + g_free (operation_info); } /* Struct used to control applying icon positions to @@ -347,58 +357,58 @@ extract_and_ellipsize_file_name_for_dial } static GtkWidget * -parent_for_error_dialog (TransferInfo *transfer_info) +parent_for_error_dialog (OperationInfo *operation_info) { - if (transfer_info->progress_dialog != NULL) { - return GTK_WIDGET (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + return GTK_WIDGET (operation_info->progress_dialog); } - return transfer_info->parent_view; + return operation_info->parent_view; } static void -handle_response_callback (GtkDialog *dialog, int response, TransferInfo *transfer_info) +handle_response_callback (GtkDialog *dialog, int response, OperationInfo *operation_info) { - transfer_info->cancelled = TRUE; + operation_info->cancelled = TRUE; } static void -handle_close_callback (GtkDialog *dialog, TransferInfo *transfer_info) +handle_close_callback (GtkDialog *dialog, OperationInfo *operation_info) { - transfer_info->cancelled = TRUE; + operation_info->cancelled = TRUE; } static void -create_transfer_dialog (const GnomeVFSXferProgressInfo *progress_info, - TransferInfo *transfer_info) +create_operation_dialog (const GnomeVFSXferProgressInfo *progress_info, + OperationInfo *operation_info) { - g_return_if_fail (transfer_info->progress_dialog == NULL); + g_return_if_fail (operation_info->progress_dialog == NULL); - transfer_info->progress_dialog = nautilus_file_operations_progress_new - (transfer_info->operation_title, "", "", "", 0, 0, TRUE); + operation_info->progress_dialog = nautilus_file_operations_progress_new + (operation_info->operation_title, "", "", "", 0, 0, TRUE); /* Treat clicking on the close box or use of the escape key * the same as clicking cancel. */ - g_signal_connect (transfer_info->progress_dialog, + g_signal_connect (operation_info->progress_dialog, "response", G_CALLBACK (handle_response_callback), - transfer_info); - g_signal_connect (transfer_info->progress_dialog, + operation_info); + g_signal_connect (operation_info->progress_dialog, "close", G_CALLBACK (handle_close_callback), - transfer_info); + operation_info); /* Make the progress dialog show up over the window we are copying into */ - if (transfer_info->parent_view != NULL) { + if (operation_info->parent_view != NULL) { GtkWidget *toplevel; /* Transient-for-desktop are visible on all desktops, we don't want that. */ - toplevel = gtk_widget_get_toplevel (transfer_info->parent_view); + toplevel = gtk_widget_get_toplevel (operation_info->parent_view); if (toplevel != NULL && g_object_get_data (G_OBJECT (toplevel), "is_desktop_window") == NULL) { - gtk_window_set_transient_for (GTK_WINDOW (transfer_info->progress_dialog), + gtk_window_set_transient_for (GTK_WINDOW (operation_info->progress_dialog), GTK_WINDOW (toplevel)); } } @@ -491,123 +501,91 @@ progress_dialog_set_to_from_item_text (N g_free (to_text); } -static int -handle_transfer_ok (const GnomeVFSXferProgressInfo *progress_info, - TransferInfo *transfer_info) +static void +update_progress_dialog (const GnomeVFSXferProgressInfo *progress_info, + OperationInfo *operation_info) { - if (transfer_info->cancelled - && progress_info->phase != GNOME_VFS_XFER_PHASE_COMPLETED) { - /* If cancelled, delete any partially copied files that are laying - * around and return. Don't delete the source though.. - */ - if (progress_info->target_name != NULL - && progress_info->source_name != NULL - && strcmp (progress_info->source_name, progress_info->target_name) != 0 - && progress_info->bytes_total != progress_info->bytes_copied) { - GList *delete_me; - - delete_me = g_list_prepend (NULL, progress_info->target_name); - nautilus_file_operations_delete (delete_me, transfer_info->parent_view); - g_list_free (delete_me); - } - - return 0; - } - switch (progress_info->phase) { case GNOME_VFS_XFER_PHASE_INITIAL: - create_transfer_dialog (progress_info, transfer_info); - return 1; + break; case GNOME_VFS_XFER_PHASE_COLLECTING: - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { nautilus_file_operations_progress_set_operation_string - (transfer_info->progress_dialog, - transfer_info->preparation_name); + (operation_info->progress_dialog, + operation_info->preparation_name); } - return 1; + break; case GNOME_VFS_XFER_PHASE_READYTOGO: - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { nautilus_file_operations_progress_set_operation_string - (transfer_info->progress_dialog, - transfer_info->action_label); + (operation_info->progress_dialog, + operation_info->action_label); nautilus_file_operations_progress_set_total - (transfer_info->progress_dialog, + (operation_info->progress_dialog, progress_info->files_total, progress_info->bytes_total); } - return 1; - + break; + case GNOME_VFS_XFER_PHASE_DELETESOURCE: - nautilus_file_changes_consume_changes (FALSE); - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { progress_dialog_set_to_from_item_text - (transfer_info->progress_dialog, - transfer_info->progress_verb, + (operation_info->progress_dialog, + operation_info->progress_verb, progress_info->source_name, NULL, progress_info->file_index, progress_info->file_size); nautilus_file_operations_progress_update_sizes - (transfer_info->progress_dialog, + (operation_info->progress_dialog, MIN (progress_info->bytes_copied, progress_info->bytes_total), MIN (progress_info->total_bytes_copied, progress_info->bytes_total)); } - return 1; + break; case GNOME_VFS_XFER_PHASE_MOVING: case GNOME_VFS_XFER_PHASE_OPENSOURCE: case GNOME_VFS_XFER_PHASE_OPENTARGET: /* fall through */ case GNOME_VFS_XFER_PHASE_COPYING: - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { if (progress_info->bytes_copied == 0) { progress_dialog_set_to_from_item_text - (transfer_info->progress_dialog, - transfer_info->progress_verb, + (operation_info->progress_dialog, + operation_info->progress_verb, progress_info->source_name, progress_info->target_name, progress_info->file_index, progress_info->file_size); } else { nautilus_file_operations_progress_update_sizes - (transfer_info->progress_dialog, + (operation_info->progress_dialog, MIN (progress_info->bytes_copied, progress_info->bytes_total), MIN (progress_info->total_bytes_copied, progress_info->bytes_total)); } } - return 1; + break; case GNOME_VFS_XFER_PHASE_CLEANUP: - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { nautilus_file_operations_progress_clear - (transfer_info->progress_dialog); + (operation_info->progress_dialog); nautilus_file_operations_progress_set_operation_string - (transfer_info->progress_dialog, - transfer_info->cleanup_name); + (operation_info->progress_dialog, + operation_info->cleanup_name); } - return 1; + break; case GNOME_VFS_XFER_PHASE_COMPLETED: - nautilus_file_changes_consume_changes (TRUE); - if (transfer_info->done_callback != NULL) { - transfer_info->done_callback (transfer_info->debuting_uris, - transfer_info->done_callback_data); - /* done_callback now owns (will free) debuting_uris */ - transfer_info->debuting_uris = NULL; - } - - transfer_info_destroy (transfer_info); - return 1; - default: - return 1; + break; } } @@ -632,7 +610,7 @@ typedef enum { static void build_error_string (const char *source_name, const char *target_name, - TransferKind operation_kind, + OperationKind operation_kind, NautilusFileOperationsErrorKind error_kind, NautilusFileOperationsErrorLocation error_location, GnomeVFSResult error, @@ -687,6 +665,25 @@ build_error_string (const char *source_n } break; + case CREATE_FILE: + case CREATE_FOLDER: + switch (error) { + *error_string = g_strdup_printf (_("Error While Creating \"%s\"."), target_name); + + case GNOME_VFS_ERROR_ACCESS_DENIED: + detail_format = _("You do not have permissions to write to the destination."); + break; + + case GNOME_VFS_ERROR_NO_SPACE: + detail_format = _("There is no space on the destination."); + break; + + default: + detail_format = (char *) gnome_vfs_result_to_string (error); + break; + } + break; + default: g_assert_not_reached (); break; @@ -900,11 +897,11 @@ build_error_string (const char *source_n } static int -handle_transfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info, - TransferInfo *transfer_info) +handle_operation_vfs_error (const GnomeVFSXferProgressInfo *progress_info, + OperationInfo *operation_info) { - /* Notice that the error mode in `transfer_info' is the one we have been - * requested, but the transfer is always performed in mode + /* Notice that the error mode in `operation_info' is the one we have been + * requested, but the operation is always performed in mode * `GNOME_VFS_XFER_ERROR_MODE_QUERY'. */ @@ -917,26 +914,28 @@ handle_transfer_vfs_error (const GnomeVF NautilusFileOperationsErrorKind error_kind; NautilusFileOperationsErrorLocation error_location; - switch (transfer_info->error_mode) { + switch (operation_info->error_mode) { case GNOME_VFS_XFER_ERROR_MODE_QUERY: - /* transfer error, prompt the user to continue or cancel */ + /* operation error, prompt the user to continue or cancel */ /* stop timeout while waiting for user */ - nautilus_file_operations_progress_pause_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_pause_timeout (operation_info->progress_dialog); + } formatted_source_name = NULL; formatted_target_name = NULL; if (progress_info->source_name != NULL) { formatted_source_name = format_and_ellipsize_uri_for_dialog - (parent_for_error_dialog (transfer_info), + (parent_for_error_dialog (operation_info), progress_info->source_name); } if (progress_info->target_name != NULL) { formatted_target_name = format_and_ellipsize_uri_for_dialog - (parent_for_error_dialog (transfer_info), + (parent_for_error_dialog (operation_info), progress_info->target_name); } @@ -948,36 +947,36 @@ handle_transfer_vfs_error (const GnomeVF */ if ((progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM || progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY) - && (transfer_info->kind == TRANSFER_DELETE - || transfer_info->kind == TRANSFER_EMPTY_TRASH)) { + && (operation_info->kind == TRANSFER_DELETE + || operation_info->kind == TRANSFER_EMPTY_TRASH)) { error_location = ERROR_LOCATION_SOURCE_PARENT; error_kind = ERROR_READ_ONLY; } else if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED - && (transfer_info->kind == TRANSFER_DELETE - || transfer_info->kind == TRANSFER_EMPTY_TRASH)) { + && (operation_info->kind == TRANSFER_DELETE + || operation_info->kind == TRANSFER_EMPTY_TRASH)) { error_location = ERROR_LOCATION_SOURCE_PARENT; error_kind = ERROR_NOT_ENOUGH_PERMISSIONS; } else if ((progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM || progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY) - && (transfer_info->kind == TRANSFER_MOVE - || transfer_info->kind == TRANSFER_MOVE_TO_TRASH) + && (operation_info->kind == TRANSFER_MOVE + || operation_info->kind == TRANSFER_MOVE_TO_TRASH) && progress_info->phase != GNOME_VFS_XFER_CHECKING_DESTINATION) { error_location = ERROR_LOCATION_SOURCE_PARENT; error_kind = ERROR_READ_ONLY; } else if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED - && transfer_info->kind == TRANSFER_MOVE + && operation_info->kind == TRANSFER_MOVE && progress_info->phase == GNOME_VFS_XFER_PHASE_OPENTARGET) { error_location = ERROR_LOCATION_TARGET; error_kind = ERROR_NOT_ENOUGH_PERMISSIONS; } else if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED - && (transfer_info->kind == TRANSFER_MOVE - || transfer_info->kind == TRANSFER_MOVE_TO_TRASH) + && (operation_info->kind == TRANSFER_MOVE + || operation_info->kind == TRANSFER_MOVE_TO_TRASH) && progress_info->phase != GNOME_VFS_XFER_CHECKING_DESTINATION) { error_location = ERROR_LOCATION_SOURCE_OR_PARENT; error_kind = ERROR_NOT_ENOUGH_PERMISSIONS; } else if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED - && (transfer_info->kind == TRANSFER_COPY - || transfer_info->kind == TRANSFER_DUPLICATE) + && (operation_info->kind == TRANSFER_COPY + || operation_info->kind == TRANSFER_DUPLICATE) && (progress_info->phase == GNOME_VFS_XFER_PHASE_OPENSOURCE || progress_info->phase == GNOME_VFS_XFER_PHASE_COLLECTING || progress_info->phase == GNOME_VFS_XFER_PHASE_INITIAL)) { @@ -996,27 +995,29 @@ handle_transfer_vfs_error (const GnomeVF error_location = ERROR_LOCATION_TARGET; error_kind = ERROR_NO_SPACE; } else if (progress_info->vfs_status == GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY - && transfer_info->kind == TRANSFER_MOVE) { + && operation_info->kind == TRANSFER_MOVE) { error_location = ERROR_LOCATION_SOURCE_OR_PARENT; error_kind = ERROR_SOURCE_IN_TARGET; } build_error_string (formatted_source_name, formatted_target_name, - transfer_info->kind, + operation_info->kind, error_kind, error_location, progress_info->vfs_status, &text, &detail); if (error_location == ERROR_LOCATION_TARGET || - error_kind == ERROR_SOURCE_IN_TARGET) { + error_kind == ERROR_SOURCE_IN_TARGET || + operation_info->kind == CREATE_FILE || + operation_info->kind == CREATE_FOLDER) { /* We can't continue, just tell the user. */ - eel_run_simple_dialog (parent_for_error_dialog (transfer_info), + eel_run_simple_dialog (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_ERROR, text, detail, GTK_STOCK_OK, NULL); error_dialog_result = GNOME_VFS_XFER_ERROR_ACTION_ABORT; } else if (progress_info->files_total == 1) { error_dialog_button_pressed = eel_run_simple_dialog - (parent_for_error_dialog (transfer_info), TRUE, + (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_ERROR, text, detail, GTK_STOCK_CANCEL, _("_Retry"), NULL); @@ -1033,7 +1034,7 @@ handle_transfer_vfs_error (const GnomeVF } } else { error_dialog_button_pressed = eel_run_simple_dialog - (parent_for_error_dialog (transfer_info), TRUE, + (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_ERROR, text, detail, _("_Skip"), GTK_STOCK_CANCEL, _("_Retry"), NULL); @@ -1058,15 +1059,17 @@ handle_transfer_vfs_error (const GnomeVF g_free (formatted_source_name); g_free (formatted_target_name); - nautilus_file_operations_progress_resume_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_resume_timeout (operation_info->progress_dialog); + } return error_dialog_result; case GNOME_VFS_XFER_ERROR_MODE_ABORT: default: - if (transfer_info->progress_dialog != NULL) { + if (operation_info->progress_dialog != NULL) { nautilus_file_operations_progress_done - (transfer_info->progress_dialog); + (operation_info->progress_dialog); } return GNOME_VFS_XFER_ERROR_ACTION_ABORT; } @@ -1110,21 +1113,23 @@ is_directory (const char *uri) static int handle_transfer_overwrite (const GnomeVFSXferProgressInfo *progress_info, - TransferInfo *transfer_info) + OperationInfo *operation_info) { int result; char *text, *primary_text, *secondary_text, *formatted_name; gboolean is_merge, target_is_dir; - nautilus_file_operations_progress_pause_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_pause_timeout (operation_info->progress_dialog); + } /* Handle special case files such as Trash, mount links and home directory */ if (is_special_link (progress_info->target_name)) { formatted_name = extract_and_ellipsize_file_name_for_dialog - (parent_for_error_dialog (transfer_info), + (parent_for_error_dialog (operation_info), progress_info->target_name); - if (transfer_info->kind == TRANSFER_MOVE) { + if (operation_info->kind == TRANSFER_MOVE) { primary_text = g_strdup_printf (_("Could not move \"%s\" to the new location."), formatted_name); @@ -1140,7 +1145,7 @@ handle_transfer_overwrite (const GnomeVF "to copy the item, rename it and try again."); } - eel_run_simple_dialog (parent_for_error_dialog (transfer_info), + eel_run_simple_dialog (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_ERROR, primary_text, secondary_text, GTK_STOCK_OK, NULL); @@ -1148,14 +1153,16 @@ handle_transfer_overwrite (const GnomeVF g_free (primary_text); g_free (formatted_name); - nautilus_file_operations_progress_resume_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_resume_timeout (operation_info->progress_dialog); + } return GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP; } /* transfer conflict, prompt the user to replace or skip */ formatted_name = format_and_ellipsize_uri_for_dialog ( - parent_for_error_dialog (transfer_info), progress_info->target_name); + parent_for_error_dialog (operation_info), progress_info->target_name); target_is_dir = is_directory (progress_info->target_name); if (target_is_dir) { @@ -1180,7 +1187,7 @@ handle_transfer_overwrite (const GnomeVF * Replace All */ result = eel_run_simple_dialog - (parent_for_error_dialog (transfer_info), + (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_QUESTION, text, @@ -1188,7 +1195,9 @@ handle_transfer_overwrite (const GnomeVF _("_Skip"), _("_Replace"), NULL); g_free (text); - nautilus_file_operations_progress_resume_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_pause_timeout (operation_info->progress_dialog); + } switch (result) { case 0: @@ -1201,12 +1210,14 @@ handle_transfer_overwrite (const GnomeVF } } else { result = eel_run_simple_dialog - (parent_for_error_dialog (transfer_info), TRUE, GTK_MESSAGE_QUESTION, text, + (parent_for_error_dialog (operation_info), TRUE, GTK_MESSAGE_QUESTION, text, secondary_text, _("S_kip All"), _("Replace _All"), _("_Skip"), _("_Replace"), NULL); g_free (text); - nautilus_file_operations_progress_resume_timeout (transfer_info->progress_dialog); + if (operation_info->progress_dialog != NULL) { + nautilus_file_operations_progress_resume_timeout (operation_info->progress_dialog); + } switch (result) { case 0: @@ -1589,7 +1600,8 @@ get_duplicate_name (const char *name, in } static char * -get_next_duplicate_name (char *name, int count_increment) +get_next_duplicate_name (const char *name, + int count_increment) { char *unescaped_name; char *unescaped_tmp_name; @@ -1598,8 +1610,6 @@ get_next_duplicate_name (char *name, int char *new_file; unescaped_tmp_name = gnome_vfs_unescape_string (name, "/"); - g_free (name); - unescaped_name = g_filename_to_utf8 (unescaped_tmp_name, -1, NULL, NULL, NULL); if (!unescaped_name) { @@ -1626,53 +1636,101 @@ get_next_duplicate_name (char *name, int } static int -handle_transfer_duplicate (GnomeVFSXferProgressInfo *progress_info, - TransferInfo *transfer_info) +handle_operation_duplicate (GnomeVFSXferProgressInfo *progress_info, + OperationInfo *operation_info) { - switch (transfer_info->kind) { + char *old_name = progress_info->duplicate_name; + int old_count = progress_info->duplicate_count; + + switch (operation_info->kind) { case TRANSFER_LINK: - progress_info->duplicate_name = get_link_name - (progress_info->duplicate_name, - progress_info->duplicate_count); + progress_info->duplicate_name = get_link_name (old_name, old_count); break; case TRANSFER_COPY: case TRANSFER_MOVE_TO_TRASH: - progress_info->duplicate_name = get_next_duplicate_name - (progress_info->duplicate_name, - progress_info->duplicate_count); + progress_info->duplicate_name = get_next_duplicate_name (old_name, old_count); + break; + + case CREATE_FILE: + case CREATE_FOLDER: + if (progress_info->vfs_status == GNOME_VFS_ERROR_NAME_TOO_LONG) { + /* special case an 8.3 file system */ + progress_info->duplicate_name = g_strndup (old_name, 8); + g_free (old_name); + old_name = progress_info->duplicate_name; + + progress_info->duplicate_name = g_strdup_printf + ("%s.%d", old_name, old_count); + } else { + progress_info->duplicate_name = get_next_duplicate_name (old_name, old_count); + } break; + default: break; /* For all other cases we use the name as-is. */ } + if (old_name != progress_info->duplicate_name) { + g_free (old_name); + + icon_position_iterator_update_uri + (operation_info->iterator, + progress_info->target_name, + progress_info->duplicate_name); + } + + return GNOME_VFS_XFER_ERROR_ACTION_SKIP; } static int -update_transfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) +async_operation_callback (GnomeVFSAsyncHandle *handle, + GnomeVFSXferProgressInfo *progress_info, + gpointer data) { - TransferInfo *transfer_info; + OperationInfo *operation_info; + int ret; - transfer_info = (TransferInfo *) data; + operation_info = (OperationInfo *) data; switch (progress_info->status) { case GNOME_VFS_XFER_PROGRESS_STATUS_OK: - return handle_transfer_ok (progress_info, transfer_info); + update_progress_dialog (progress_info, operation_info); + break; + case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: - return handle_transfer_vfs_error (progress_info, transfer_info); case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE: - return handle_transfer_overwrite (progress_info, transfer_info); case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: - return handle_transfer_duplicate (progress_info, transfer_info); + break; + default: g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), progress_info->status); return 0; } + + /* It's not entirely predictable when this is called, + * but when this is the case the sync call already + * ran before this one, so we don't want to mess up its + * results. Blame GnomeVFS. + * */ + ret = operation_info->last_sync_response; + + switch (progress_info->phase) { + case GNOME_VFS_XFER_PHASE_DELETESOURCE: + nautilus_file_changes_consume_changes (FALSE); + break; + + case GNOME_VFS_XFER_PHASE_COMPLETED: + operation_info_destroy (operation_info); + + default: + break; + } + + return ret; } static void @@ -1689,119 +1747,196 @@ apply_one_position (IconPositionIterator } } -typedef struct { - GHashTable *debuting_uris; - IconPositionIterator *iterator; -} SyncTransferInfo; - -/* Low-level callback, called for every copy engine operation. - * Generates notifications about new, deleted and moved files. - */ static int -sync_transfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data) +handle_operation_ok (const GnomeVFSXferProgressInfo *progress_info, + OperationInfo *operation_info) { GHashTable *debuting_uris; IconPositionIterator *position_iterator; gboolean really_moved; - if (data != NULL) { - debuting_uris = ((SyncTransferInfo *) data)->debuting_uris; - position_iterator = ((SyncTransferInfo *) data)->iterator; - } else { - debuting_uris = NULL; - position_iterator = NULL; + if (operation_info->cancelled + && progress_info->phase != GNOME_VFS_XFER_PHASE_COMPLETED) { + + /* If cancelled, delete any partially copied files that are laying + * around and return. Don't delete the source though.. + */ + if (progress_info->target_name != NULL + && progress_info->source_name != NULL + && strcmp (progress_info->source_name, progress_info->target_name) != 0 + && progress_info->bytes_total != progress_info->bytes_copied) { + GList *delete_me; + + delete_me = g_list_prepend (NULL, progress_info->target_name); + nautilus_file_operations_delete (delete_me, operation_info->parent_view); + g_list_free (delete_me); + } + + return 0; } - if (progress_info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OK) { - switch (progress_info->phase) { - case GNOME_VFS_XFER_PHASE_OPENTARGET: - if (progress_info->top_level_item) { - /* this is one of the selected copied or moved items -- we need - * to make sure it's metadata gets copied over - */ - if (progress_info->source_name == NULL) { - /* remove any old metadata */ - nautilus_file_changes_queue_schedule_metadata_remove - (progress_info->target_name); - } else { - nautilus_file_changes_queue_schedule_metadata_copy - (progress_info->source_name, progress_info->target_name); + debuting_uris = operation_info->debuting_uris; + position_iterator = operation_info->iterator; - } + switch (progress_info->phase) { + case GNOME_VFS_XFER_PHASE_INITIAL: + case GNOME_VFS_XFER_CHECKING_DESTINATION: + case GNOME_VFS_XFER_PHASE_COLLECTING: + case GNOME_VFS_XFER_PHASE_READYTOGO: + case GNOME_VFS_XFER_PHASE_OPENSOURCE: + break; - apply_one_position (position_iterator, - progress_info->source_name, - progress_info->target_name); - - if (debuting_uris != NULL) { - g_hash_table_replace (debuting_uris, - g_strdup (progress_info->target_name), - GINT_TO_POINTER (TRUE)); - } + case GNOME_VFS_XFER_PHASE_OPENTARGET: + if (progress_info->source_name == NULL) { + /* remove any old metadata */ + nautilus_file_changes_queue_schedule_metadata_remove + (progress_info->target_name); + } else { + nautilus_file_changes_queue_schedule_metadata_copy + (progress_info->source_name, progress_info->target_name); + + } + + if (progress_info->top_level_item) { + apply_one_position (position_iterator, + progress_info->source_name, + progress_info->target_name); + + if (debuting_uris != NULL) { + g_hash_table_replace (debuting_uris, + g_strdup (progress_info->target_name), + GINT_TO_POINTER (TRUE)); } - nautilus_file_changes_queue_file_added (progress_info->target_name); - break; + } - case GNOME_VFS_XFER_PHASE_MOVING: - g_assert (progress_info->source_name != NULL); + nautilus_file_changes_queue_file_added (progress_info->target_name); + break; - /* If the source and target are the same, that - * means we "moved" something in place. No - * actual change happened, so we really don't - * want to send out any change notification, - * but we do want to select the files as - * "newly moved here" so we put them into the - * debuting_uris set. - */ - really_moved = strcmp (progress_info->source_name, - progress_info->target_name) != 0; + case GNOME_VFS_XFER_PHASE_COPYING: + break; - if (progress_info->top_level_item) { - if (really_moved) { - nautilus_file_changes_queue_schedule_metadata_move - (progress_info->source_name, progress_info->target_name); - } + case GNOME_VFS_XFER_PHASE_MOVING: + g_assert (progress_info->source_name != NULL); - apply_one_position (position_iterator, - progress_info->source_name, - progress_info->target_name); - - if (debuting_uris != NULL) { - g_hash_table_replace (debuting_uris, - g_strdup (progress_info->target_name), - GINT_TO_POINTER (really_moved)); - } + /* If the source and target are the same, that + * means we "moved" something in place. No + * actual change happened, so we really don't + * want to send out any change notification, + * but we do want to select the files as + * "newly moved here" so we put them into the + * debuting_uris set. + */ + really_moved = strcmp (progress_info->source_name, + progress_info->target_name) != 0; + + if (really_moved) { + nautilus_file_changes_queue_schedule_metadata_move (progress_info->source_name, + progress_info->target_name); + } + + if (progress_info->top_level_item) { + apply_one_position (position_iterator, + progress_info->source_name, + progress_info->target_name); + + if (debuting_uris != NULL) { + g_hash_table_replace (debuting_uris, + g_strdup (progress_info->target_name), + GINT_TO_POINTER (really_moved)); } + if (really_moved) { nautilus_file_changes_queue_file_moved (progress_info->source_name, progress_info->target_name); } - break; - - case GNOME_VFS_XFER_PHASE_DELETESOURCE: - g_assert (progress_info->source_name != NULL); - if (progress_info->top_level_item) { - nautilus_file_changes_queue_schedule_metadata_remove - (progress_info->source_name); - } - nautilus_file_changes_queue_file_removed (progress_info->source_name); - break; - - case GNOME_VFS_XFER_PHASE_COMPLETED: - /* done, clean up */ - icon_position_iterator_free (position_iterator); - /* SyncXferInfo doesn't own the debuting_uris hash table - don't free it here. - */ - g_free (data); - break; + } - default: - break; + break; + + case GNOME_VFS_XFER_PHASE_READSOURCE: + case GNOME_VFS_XFER_PHASE_WRITETARGET: + case GNOME_VFS_XFER_PHASE_CLOSESOURCE: + case GNOME_VFS_XFER_PHASE_CLOSETARGET: + break; + + case GNOME_VFS_XFER_PHASE_DELETESOURCE: + g_assert (progress_info->source_name != NULL); + nautilus_file_changes_queue_schedule_metadata_remove (progress_info->source_name); + nautilus_file_changes_queue_file_removed (progress_info->source_name); + break; + + case GNOME_VFS_XFER_PHASE_SETATTRIBUTES: + case GNOME_VFS_XFER_PHASE_FILECOMPLETED: + case GNOME_VFS_XFER_PHASE_CLEANUP: + break; + + case GNOME_VFS_XFER_PHASE_COMPLETED: + nautilus_file_changes_consume_changes (TRUE); + + if (operation_info->done_callback != NULL) { + operation_info->done_callback (operation_info->debuting_uris, + operation_info->done_callback_user_data); + operation_info->debuting_uris = NULL; } + + /* cleanup is done in the async callback */ + break; + + default: + g_warning (_("Unknown GnomeVFSXferPhase %d"), + progress_info->phase); + return 0; } + return 1; } +/* Low-level callback, called for every copy engine operation. + * Generates notifications about new, deleted and moved files, + * and handles problems. + */ +static int +sync_operation_callback (GnomeVFSXferProgressInfo *progress_info, + gpointer data) +{ + OperationInfo *operation_info = (OperationInfo *) data; + int ret; + + g_assert (operation_info != NULL); + + if (progress_info->phase == GNOME_VFS_XFER_PHASE_INITIAL && + operation_info->kind != CREATE_FILE && + operation_info->kind != CREATE_FOLDER) { + create_operation_dialog (progress_info, operation_info); + } + + switch (progress_info->status) { + case GNOME_VFS_XFER_PROGRESS_STATUS_OK: + ret = handle_operation_ok (progress_info, operation_info); + break; + + case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: + ret = handle_operation_vfs_error (progress_info, operation_info); + break; + + case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE: + ret = handle_transfer_overwrite (progress_info, operation_info); + break; + + case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: + ret = handle_operation_duplicate (progress_info, operation_info); + break; + default: + g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), + progress_info->status); + ret = 0; + } + + operation_info->last_sync_response = ret; + + return ret; +} + static gboolean check_target_directory_is_or_in_trash (GnomeVFSURI *trash_dir_uri, GnomeVFSURI *target_dir_uri) { @@ -1840,8 +1975,8 @@ nautilus_file_operations_copy_move (cons const char *target_dir, GdkDragAction copy_action, GtkWidget *parent_view, - void (*done_callback) (GHashTable *debuting_uris, gpointer data), - gpointer done_callback_data) + NautilusFileOperationsCallback done_callback, + gpointer done_callback_user_data) { const GList *p; GnomeVFSXferOptions move_options; @@ -1851,8 +1986,7 @@ nautilus_file_operations_copy_move (cons GnomeVFSURI *trash_dir_uri; GnomeVFSURI *uri; - TransferInfo *transfer_info; - SyncTransferInfo *sync_transfer_info; + OperationInfo *operation_info; GnomeVFSResult result; gboolean target_is_trash; gboolean duplicate; @@ -1998,7 +2132,7 @@ nautilus_file_operations_copy_move (cons } /* set up the copy/move parameters */ - transfer_info = transfer_info_new (parent_view); + operation_info = operation_info_new (parent_view); if (relative_item_points != NULL && relative_item_points->len > 0) { screen = gtk_widget_get_screen (GTK_WIDGET (parent_view)); screen_num = gdk_screen_get_number (screen); @@ -2015,52 +2149,52 @@ nautilus_file_operations_copy_move (cons /* when moving to trash, handle name conflicts automatically */ move_options |= GNOME_VFS_XFER_USE_UNIQUE_NAMES; /* localizers: progress dialog title */ - transfer_info->operation_title = _("Moving files to the Trash"); + operation_info->operation_title = _("Moving files to the Trash"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Throwing out file:"); + operation_info->action_label =_("Throwing out file:"); /* localizers: label prepended to the name of the current file moved */ - transfer_info->progress_verb =_("Moving"); - transfer_info->preparation_name =_("Preparing to Move to Trash..."); + operation_info->progress_verb =_("Moving"); + operation_info->preparation_name =_("Preparing to Move to Trash..."); - transfer_info->kind = TRANSFER_MOVE_TO_TRASH; + operation_info->kind = TRANSFER_MOVE_TO_TRASH; } else if ((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) { /* localizers: progress dialog title */ - transfer_info->operation_title = _("Moving files"); + operation_info->operation_title = _("Moving files"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Moving file:"); + operation_info->action_label =_("Moving file:"); /* localizers: label prepended to the name of the current file moved */ - transfer_info->progress_verb =_("Moving"); - transfer_info->preparation_name =_("Preparing To Move..."); - transfer_info->cleanup_name = _("Finishing Move..."); + operation_info->progress_verb =_("Moving"); + operation_info->preparation_name =_("Preparing To Move..."); + operation_info->cleanup_name = _("Finishing Move..."); - transfer_info->kind = TRANSFER_MOVE; + operation_info->kind = TRANSFER_MOVE; } else if ((move_options & GNOME_VFS_XFER_LINK_ITEMS) != 0) { /* when creating links, handle name conflicts automatically */ move_options |= GNOME_VFS_XFER_USE_UNIQUE_NAMES; /* localizers: progress dialog title */ - transfer_info->operation_title = _("Creating links to files"); + operation_info->operation_title = _("Creating links to files"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Linking file:"); + operation_info->action_label =_("Linking file:"); /* localizers: label prepended to the name of the current file linked */ - transfer_info->progress_verb =_("Linking"); - transfer_info->preparation_name = _("Preparing to Create Links..."); - transfer_info->cleanup_name = _("Finishing Creating Links..."); + operation_info->progress_verb =_("Linking"); + operation_info->preparation_name = _("Preparing to Create Links..."); + operation_info->cleanup_name = _("Finishing Creating Links..."); - transfer_info->kind = TRANSFER_LINK; + operation_info->kind = TRANSFER_LINK; } else { /* localizers: progress dialog title */ - transfer_info->operation_title = _("Copying files"); + operation_info->operation_title = _("Copying files"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Copying file:"); + operation_info->action_label =_("Copying file:"); /* localizers: label prepended to the name of the current file copied */ - transfer_info->progress_verb =_("Copying"); - transfer_info->preparation_name =_("Preparing To Copy..."); - transfer_info->cleanup_name = ""; + operation_info->progress_verb =_("Copying"); + operation_info->preparation_name =_("Preparing To Copy..."); + operation_info->cleanup_name = ""; - transfer_info->kind = TRANSFER_COPY; + operation_info->kind = TRANSFER_COPY; } /* we'll need to check for copy into Trash and for moving/copying the Trash itself */ @@ -2151,25 +2285,20 @@ nautilus_file_operations_copy_move (cons } } - transfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; - transfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_QUERY; - transfer_info->done_callback = done_callback; - transfer_info->done_callback_data = done_callback_data; - transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - - sync_transfer_info = g_new (SyncTransferInfo, 1); - sync_transfer_info->iterator = icon_position_iterator; - sync_transfer_info->debuting_uris = transfer_info->debuting_uris; + operation_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; + operation_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_QUERY; + operation_info->done_callback = done_callback; + operation_info->done_callback_user_data = done_callback_user_data; - transfer_info->iterator = sync_transfer_info->iterator; + operation_info->iterator = icon_position_iterator; if (result == GNOME_VFS_OK) { - gnome_vfs_async_xfer (&transfer_info->handle, source_uri_list, target_uri_list, + gnome_vfs_async_xfer (&operation_info->handle, source_uri_list, target_uri_list, move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, GNOME_VFS_PRIORITY_DEFAULT, - update_transfer_callback, transfer_info, - sync_transfer_callback, sync_transfer_info); + async_operation_callback, operation_info, + sync_operation_callback, operation_info); } gnome_vfs_uri_list_free (source_uri_list); @@ -2181,123 +2310,62 @@ nautilus_file_operations_copy_move (cons } typedef struct { - GnomeVFSAsyncHandle *handle; - NautilusNewFolderCallback done_callback; - gpointer data; - GtkWidget *parent_view; - IconPositionIterator *iterator; -} NewFolderTransferState; + NautilusNewFileCallback callback; + gpointer callback_user_data; +} NewFileInfo; -static int -handle_new_folder_vfs_error (const GnomeVFSXferProgressInfo *progress_info, NewFolderTransferState *state) +static void +get_new_file_uri (gpointer key, + gpointer value, + gpointer user_data) { - const char *error_string; - char *error_string_to_free; + char *uri; + char **uri_out; - error_string_to_free = NULL; + uri = key; + uri_out = user_data; - if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED) { - error_string = _("You do not have permissions to write to the destination."); - } else if (progress_info->vfs_status == GNOME_VFS_ERROR_NO_SPACE) { - error_string = _("There is no space on the destination."); - } else { - error_string = g_strdup_printf (_("Error \"%s\" creating new folder."), - gnome_vfs_result_to_string (progress_info->vfs_status)); - error_string_to_free = (char *)error_string; - } - - eel_show_error_dialog (_("Error creating new folder."), error_string, - GTK_WINDOW (gtk_widget_get_toplevel (state->parent_view))); - - g_free (error_string_to_free); - - return GNOME_VFS_XFER_ERROR_ACTION_ABORT; + *uri_out = uri; } -static int -new_folder_transfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) -{ - NewFolderTransferState *state; - char *temp_string; - char *new_uri; - - state = (NewFolderTransferState *) data; +static void +new_file_done_callback (GHashTable *debuting_uris, + gpointer user_data) +{ + NewFileInfo *new_file_info = (NewFileInfo *) user_data; + char *uri; - switch (progress_info->phase) { + g_assert (new_file_info != NULL); - case GNOME_VFS_XFER_PHASE_COMPLETED: - eel_remove_weak_pointer (&state->parent_view); - g_free (state); - return 0; + uri = NULL; - default: - switch (progress_info->status) { - case GNOME_VFS_XFER_PROGRESS_STATUS_OK: - nautilus_file_changes_consume_changes (TRUE); - new_uri = NULL; - if (progress_info->vfs_status == GNOME_VFS_OK) { - new_uri = progress_info->target_name; - } - (* state->done_callback) (new_uri, - state->data); - return 1; - - case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: - - temp_string = progress_info->duplicate_name; - - if (progress_info->vfs_status == GNOME_VFS_ERROR_NAME_TOO_LONG) { - /* special case an 8.3 file system */ - progress_info->duplicate_name = g_strndup (temp_string, 8); - progress_info->duplicate_name[8] = '\0'; - g_free (temp_string); - temp_string = progress_info->duplicate_name; - progress_info->duplicate_name = g_strdup_printf - ("%s.%d", - progress_info->duplicate_name, - progress_info->duplicate_count); - } else { - progress_info->duplicate_name = g_strdup_printf - ("%s%%20%d", - progress_info->duplicate_name, - progress_info->duplicate_count); - } - g_free (temp_string); - - icon_position_iterator_update_uri - (state->iterator, - progress_info->target_name, - progress_info->duplicate_name); + if (debuting_uris != NULL) { + g_hash_table_foreach (debuting_uris, get_new_file_uri, &uri); + } - return GNOME_VFS_XFER_ERROR_ACTION_SKIP; - - case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: - return handle_new_folder_vfs_error (progress_info, state); - - + if (new_file_info->callback != NULL) { + (* new_file_info->callback) (uri, new_file_info->callback_user_data); + } - default: - g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), - progress_info->status); - return 0; - } + if (debuting_uris != NULL) { + g_hash_table_destroy (debuting_uris); } + + g_free (new_file_info); } void nautilus_file_operations_new_folder (GtkWidget *parent_view, GdkPoint *target_point, const char *parent_dir, - NautilusNewFolderCallback done_callback, - gpointer data) + NautilusNewFileCallback done_callback, + gpointer done_callback_user_data) { GList *target_uri_list; GnomeVFSURI *uri, *parent_uri; char *text_uri, *dirname; - NewFolderTransferState *state; - SyncTransferInfo *sync_transfer_info; + OperationInfo *operation_info; + NewFileInfo *new_file_info; /* pass in the target directory and the new folder name as a destination URI */ parent_uri = gnome_vfs_uri_new (parent_dir); @@ -2310,165 +2378,34 @@ nautilus_file_operations_new_folder (Gtk text_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); - sync_transfer_info = g_new (SyncTransferInfo, 1); - sync_transfer_info->iterator = icon_position_iterator_new_single + operation_info = operation_info_new (parent_view); + operation_info->iterator = icon_position_iterator_new_single (target_point, text_uri, gdk_screen_get_number (gtk_widget_get_screen (parent_view)), FALSE); - sync_transfer_info->debuting_uris = NULL; + operation_info->kind = CREATE_FOLDER; - g_free (text_uri); + new_file_info = g_new (NewFileInfo, 1); + new_file_info->callback = done_callback; + new_file_info->callback_user_data = done_callback_user_data; - state = g_new (NewFolderTransferState, 1); - state->done_callback = done_callback; - state->data = data; - state->parent_view = parent_view; - state->iterator = sync_transfer_info->iterator; - eel_add_weak_pointer (&state->parent_view); + operation_info->done_callback = new_file_done_callback; + operation_info->done_callback_user_data = new_file_info; - gnome_vfs_async_xfer (&state->handle, NULL, target_uri_list, + g_free (text_uri); + + gnome_vfs_async_xfer (&operation_info->handle, NULL, target_uri_list, GNOME_VFS_XFER_NEW_UNIQUE_DIRECTORY, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, GNOME_VFS_PRIORITY_DEFAULT, - new_folder_transfer_callback, state, - sync_transfer_callback, sync_transfer_info); + async_operation_callback, operation_info, + sync_operation_callback, operation_info); gnome_vfs_uri_list_free (target_uri_list); gnome_vfs_uri_unref (parent_uri); } -typedef struct { - GnomeVFSAsyncHandle *handle; - NautilusNewFileCallback done_callback; - gpointer data; - GtkWidget *parent_view; - GHashTable *debuting_uris; - IconPositionIterator *iterator; -} NewFileTransferState; - - -static int -handle_new_file_vfs_error (const GnomeVFSXferProgressInfo *progress_info, NewFileTransferState *state) -{ - const char *error_string; - char *error_string_to_free; - - error_string_to_free = NULL; - - if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED) { - error_string = _("You do not have permissions to write to the destination."); - } else if (progress_info->vfs_status == GNOME_VFS_ERROR_NO_SPACE) { - error_string = _("There is no space on the destination."); - } else { - error_string = g_strdup_printf (_("Error \"%s\" creating new document."), - gnome_vfs_result_to_string (progress_info->vfs_status)); - error_string_to_free = (char *)error_string; - } - - eel_show_error_dialog (_("Error creating new document."), error_string, - GTK_WINDOW (gtk_widget_get_toplevel (state->parent_view))); - - g_free (error_string_to_free); - - return GNOME_VFS_XFER_ERROR_ACTION_ABORT; -} - -static void -get_new_file_uri (gpointer key, - gpointer value, - gpointer user_data) -{ - char *uri; - char **uri_out; - - uri = key; - uri_out = user_data; - - *uri_out = uri; -} - - -static int -new_file_transfer_callback (GnomeVFSAsyncHandle *handle, - GnomeVFSXferProgressInfo *progress_info, - gpointer data) -{ - NewFileTransferState *state; - char *temp_string; - char **temp_strings; - char *uri; - - state = (NewFileTransferState *) data; - - switch (progress_info->phase) { - - case GNOME_VFS_XFER_PHASE_COMPLETED: - uri = NULL; - - g_hash_table_foreach (state->debuting_uris, - get_new_file_uri, &uri); - - (* state->done_callback) (uri, state->data); - /* uri is owned by hashtable, don't free */ - eel_remove_weak_pointer (&state->parent_view); - g_hash_table_destroy (state->debuting_uris); - g_free (state); - return 0; - - default: - switch (progress_info->status) { - case GNOME_VFS_XFER_PROGRESS_STATUS_OK: - nautilus_file_changes_consume_changes (TRUE); - return 1; - - case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE: - - temp_string = progress_info->duplicate_name; - - if (progress_info->vfs_status == GNOME_VFS_ERROR_NAME_TOO_LONG) { - /* special case an 8.3 file system */ - progress_info->duplicate_name = g_strndup (temp_string, 8); - progress_info->duplicate_name[8] = '\0'; - g_free (temp_string); - temp_string = progress_info->duplicate_name; - progress_info->duplicate_name = g_strdup_printf - ("%s.%d", - progress_info->duplicate_name, - progress_info->duplicate_count); - } else { - temp_strings = g_strsplit (temp_string, ".", 2); - if (temp_strings[1] != NULL) { - progress_info->duplicate_name = g_strdup_printf - ("%s%%20%d.%s", - temp_strings[0], - progress_info->duplicate_count, - temp_strings[1]); - } else { - progress_info->duplicate_name = g_strdup_printf - ("%s%%20%d", - progress_info->duplicate_name, - progress_info->duplicate_count); - } - g_strfreev (temp_strings); - } - g_free (temp_string); - - return GNOME_VFS_XFER_ERROR_ACTION_SKIP; - - case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: - return handle_new_file_vfs_error (progress_info, state); - - - - default: - g_warning (_("Unknown GnomeVFSXferProgressStatus %d"), - progress_info->status); - return 0; - } - } -} - void nautilus_file_operations_new_file_from_template (GtkWidget *parent_view, GdkPoint *target_point, @@ -2476,14 +2413,14 @@ nautilus_file_operations_new_file_from_t const char *target_filename, const char *template_uri, NautilusNewFileCallback done_callback, - gpointer data) + gpointer done_callback_user_data) { GList *target_uri_list; GList *source_uri_list; GnomeVFSURI *target_uri, *parent_uri, *source_uri; GnomeVFSXferOptions options; - NewFileTransferState *state; - SyncTransferInfo *sync_transfer_info; + OperationInfo *operation_info; + NewFileInfo *new_file_info; char *tmp; g_assert (parent_dir != NULL); @@ -2494,7 +2431,7 @@ nautilus_file_operations_new_file_from_t source_uri = gnome_vfs_uri_new (template_uri); if (source_uri == NULL) { - (*done_callback) (NULL, data); + (*done_callback) (NULL, done_callback_user_data); return; } @@ -2506,33 +2443,33 @@ nautilus_file_operations_new_file_from_t g_free (tmp); } - sync_transfer_info = g_new (SyncTransferInfo, 1); - sync_transfer_info->iterator = icon_position_iterator_new_single + operation_info = operation_info_new (parent_view); + operation_info->iterator = icon_position_iterator_new_single (target_point, template_uri, gdk_screen_get_number (gtk_widget_get_screen (parent_view)), TRUE); - sync_transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + operation_info->kind = CREATE_FILE; + + new_file_info = g_new (NewFileInfo, 1); + new_file_info->callback = done_callback; + new_file_info->callback_user_data = done_callback_user_data; - state = g_new (NewFileTransferState, 1); - state->done_callback = done_callback; - state->data = data; - state->parent_view = parent_view; - state->iterator = sync_transfer_info->iterator; - state->debuting_uris = sync_transfer_info->debuting_uris; - eel_add_weak_pointer (&state->parent_view); + operation_info->done_callback = new_file_done_callback; + operation_info->done_callback_user_data = new_file_info; target_uri_list = g_list_prepend (NULL, target_uri); source_uri_list = g_list_prepend (NULL, source_uri); options = GNOME_VFS_XFER_USE_UNIQUE_NAMES; - gnome_vfs_async_xfer (&state->handle, source_uri_list, target_uri_list, + gnome_vfs_async_xfer (&operation_info->handle, + source_uri_list, target_uri_list, options, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_QUERY, GNOME_VFS_PRIORITY_DEFAULT, - new_file_transfer_callback, state, - sync_transfer_callback, sync_transfer_info); + async_operation_callback, operation_info, + sync_operation_callback, operation_info); gnome_vfs_uri_list_free (target_uri_list); gnome_vfs_uri_list_free (source_uri_list); @@ -2622,7 +2559,7 @@ nautilus_file_operations_delete (const G const GList *p; const char *item_uri; NautilusFile *file; - TransferInfo *transfer_info; + OperationInfo *operation_info; uri_list = NULL; for (p = item_uris; p != NULL; p = p->next) { @@ -2656,28 +2593,28 @@ nautilus_file_operations_delete (const G return; } - transfer_info = transfer_info_new (parent_view); + operation_info = operation_info_new (parent_view); /* localizers: progress dialog title */ - transfer_info->operation_title = _("Deleting files"); + operation_info->operation_title = _("Deleting files"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Files deleted:"); + operation_info->action_label =_("Files deleted:"); /* localizers: label prepended to the name of the current file deleted */ - transfer_info->progress_verb =_("Deleting"); - transfer_info->preparation_name =_("Preparing to Delete files..."); - transfer_info->cleanup_name =""; - - transfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; - transfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE; - transfer_info->kind = TRANSFER_DELETE; + operation_info->progress_verb =_("Deleting"); + operation_info->preparation_name =_("Preparing to Delete files..."); + operation_info->cleanup_name =""; + + operation_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; + operation_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE; + operation_info->kind = TRANSFER_DELETE; - gnome_vfs_async_xfer (&transfer_info->handle, uri_list, NULL, + gnome_vfs_async_xfer (&operation_info->handle, uri_list, NULL, GNOME_VFS_XFER_DELETE_ITEMS | GNOME_VFS_XFER_RECURSIVE, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, GNOME_VFS_PRIORITY_DEFAULT, - update_transfer_callback, transfer_info, - sync_transfer_callback, NULL); + async_operation_callback, operation_info, + sync_operation_callback, operation_info); gnome_vfs_uri_list_free (uri_list); } @@ -2685,33 +2622,33 @@ nautilus_file_operations_delete (const G static void do_empty_trash (GtkWidget *parent_view) { - TransferInfo *transfer_info; + OperationInfo *operation_info; GList *trash_dir_list; trash_dir_list = nautilus_trash_monitor_get_trash_directories (); if (trash_dir_list != NULL) { /* set up the move parameters */ - transfer_info = transfer_info_new (parent_view); + operation_info = operation_info_new (parent_view); /* localizers: progress dialog title */ - transfer_info->operation_title = _("Emptying the Trash"); + operation_info->operation_title = _("Emptying the Trash"); /* localizers: label prepended to the progress count */ - transfer_info->action_label =_("Files deleted:"); + operation_info->action_label =_("Files deleted:"); /* localizers: label prepended to the name of the current file deleted */ - transfer_info->progress_verb =_("Deleting"); - transfer_info->preparation_name =_("Preparing to Empty the Trash..."); - transfer_info->cleanup_name =""; - transfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; - transfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE; - transfer_info->kind = TRANSFER_EMPTY_TRASH; + operation_info->progress_verb =_("Deleting"); + operation_info->preparation_name =_("Preparing to Empty the Trash..."); + operation_info->cleanup_name =""; + operation_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY; + operation_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE; + operation_info->kind = TRANSFER_EMPTY_TRASH; - gnome_vfs_async_xfer (&transfer_info->handle, trash_dir_list, NULL, + gnome_vfs_async_xfer (&operation_info->handle, trash_dir_list, NULL, GNOME_VFS_XFER_EMPTY_DIRECTORIES, GNOME_VFS_XFER_ERROR_MODE_QUERY, GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, GNOME_VFS_PRIORITY_DEFAULT, - update_transfer_callback, transfer_info, - sync_transfer_callback, NULL); + async_operation_callback, operation_info, + sync_operation_callback, operation_info); } gnome_vfs_uri_list_free (trash_dir_list);
Attachment:
signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil