nautilus/libnautilus-private/nautilus-file-operations.c
Darin Adler 0ee0b7176b Tweak to match Nautilus coding style.
* libnautilus-extensions/nautilus-file-operations.h:
	* libnautilus-extensions/nautilus-file-operations.c:
	* src/nautilus-first-time-druid.h:
	Tweak to match Nautilus coding style.

	* src/nautilus-first-time-druid.c: (druid_cancel): Added FIXME
	about the way it quits Nautilus when you cancel.
	(druid_finished): Use #define constants instead of hard-coded
	URLs.
	(make_anti_aliased_label): Put FIXME where a font and size are
	hard-coded.
	(make_hbox_user_level_radio_button): Put FIXME where a font is
	hard-coded.
	(set_up_user_level_page): Put FIXME where a font size is
	hard-coded.
	(next_update_page_callback): Put FIXME where a comment mentions
	a "timer task" that does not exist.
	(nautilus_first_time_druid_show), (download_callback),
	(read_file_handle_cancel_cover), (initiate_file_download): Got rid
	of "cheap workaround" for when the druid goes away; instead, we
	cancel the I/O.

	Other tweaks to be at least in the vicinity of Nautilus coding
	style.
2000-11-07 19:26:37 +00:00

1690 lines
48 KiB
C

/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* xfer.c - Bonobo::Desktop::FileOperationService transfer service.
Copyright (C) 1999, 2000 Free Software Foundation
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, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Authors:
Ettore Perazzoli <ettore@gnu.org>
Pavel Cisler <pavel@eazel.com>
*/
#include <config.h>
#include <gnome.h>
#include <libgnomevfs/gnome-vfs-find-directory.h>
#include <libgnomevfs/gnome-vfs-uri.h>
#include "nautilus-file-operations.h"
#include "nautilus-file-operations-progress.h"
#include "nautilus-lib-self-check-functions.h"
#include <libnautilus-extensions/nautilus-file-changes-queue.h>
#include <libnautilus-extensions/nautilus-file-utilities.h>
#include <libnautilus-extensions/nautilus-glib-extensions.h>
#include <libnautilus-extensions/nautilus-global-preferences.h>
#include <libnautilus-extensions/nautilus-stock-dialogs.h>
#include <libnautilus-extensions/nautilus-link.h>
typedef enum {
XFER_MOVE,
XFER_COPY,
XFER_DUPLICATE,
XFER_MOVE_TO_TRASH,
XFER_EMPTY_TRASH,
XFER_DELETE,
XFER_LINK
} XferKind;
/* Copy engine callback state */
typedef struct {
GnomeVFSAsyncHandle *handle;
GtkWidget *progress_dialog;
const char *operation_title; /* "Copying files" */
const char *action_verb; /* "copied" */
const char *progress_verb; /* "Copying" */
const char *preparation_name; /* "Preparing To Copy..." */
const char *cleanup_name; /* "Finishing Move..." */
GnomeVFSXferErrorMode error_mode;
GnomeVFSXferOverwriteMode overwrite_mode;
GtkWidget *parent_view;
XferKind kind;
gboolean show_progress_dialog;
void (*done_callback) (GHashTable *debuting_uris, gpointer data);
gpointer done_callback_data;
GHashTable *debuting_uris;
} XferInfo;
/* Struct used to control applying icon positions to
* top level items during a copy, drag, new folder creation and
* link creation
*/
typedef struct {
GdkPoint *icon_positions;
int last_icon_position_index;
GList *uris;
const GList *last_uri;
} IconPositionIterator;
static IconPositionIterator *
icon_position_iterator_new (const GdkPoint *icon_positions, const GList *uris)
{
IconPositionIterator *result;
int uri_count;
uri_count = g_list_length ((GList *)uris);
result = g_new (IconPositionIterator, 1);
result->icon_positions = g_new (GdkPoint, uri_count);
memcpy (result->icon_positions, icon_positions, uri_count * sizeof (GdkPoint));
result->last_icon_position_index = 0;
result->uris = nautilus_g_str_list_copy ((GList *)uris);
result->last_uri = result->uris;
return result;
}
static void
icon_position_iterator_free (IconPositionIterator *position_iterator)
{
if (position_iterator == NULL) {
return;
}
g_free (position_iterator->icon_positions);
nautilus_g_list_free_deep (position_iterator->uris);
g_free (position_iterator);
}
char *
nautilus_convert_to_unescaped_string_for_display (char *escaped)
{
char *result;
if (escaped == NULL) {
return NULL;
}
result = gnome_vfs_unescape_string_for_display (escaped);
g_free (escaped);
return result;
}
static void
xfer_dialog_clicked_callback (NautilusFileOperationsProgress *dialog,
int button_number,
gpointer data)
{
XferInfo *info;
info = (XferInfo *) data;
gnome_vfs_async_cancel (info->handle);
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
create_xfer_dialog (const GnomeVFSXferProgressInfo *progress_info,
XferInfo *xfer_info)
{
if (!xfer_info->show_progress_dialog) {
return;
}
g_return_if_fail (xfer_info->progress_dialog == NULL);
xfer_info->progress_dialog = nautilus_file_operations_progress_new
(xfer_info->operation_title, "", "", "", 1, 1);
gtk_signal_connect (GTK_OBJECT (xfer_info->progress_dialog),
"clicked",
GTK_SIGNAL_FUNC (xfer_dialog_clicked_callback),
xfer_info);
gtk_widget_show (xfer_info->progress_dialog);
}
static void
progress_dialog_set_files_done_text ( NautilusFileOperationsProgress *dialog,
const char *action_verb)
{
char *text;
text = g_strdup_printf ("Files %s:", action_verb);
nautilus_file_operations_progress_set_operation_string (dialog, text);
g_free (text);
}
static void
progress_dialog_set_to_from_item_text (NautilusFileOperationsProgress *dialog,
const char *progress_verb, const char *from_uri, const char *to_uri,
gulong index, gulong size)
{
char *item;
char *from_path;
char *to_path;
char *progress_label_text;
const char *from_prefix;
const char *to_prefix;
GnomeVFSURI *uri;
int length;
item = NULL;
from_path = NULL;
to_path = NULL;
from_prefix = "";
to_prefix = "";
progress_label_text = NULL;
if (from_uri != NULL) {
uri = gnome_vfs_uri_new (from_uri);
item = gnome_vfs_uri_extract_short_name (uri);
from_path = gnome_vfs_uri_extract_dirname (uri);
/* remove the last '/' */
length = strlen (from_path);
if (from_path [length - 1] == '/') {
from_path [length - 1] = '\0';
}
gnome_vfs_uri_unref (uri);
g_assert (progress_verb);
progress_label_text = g_strdup_printf ("%s:", progress_verb);
from_prefix = _("From:");
}
if (to_uri != NULL) {
uri = gnome_vfs_uri_new (from_uri);
to_path = gnome_vfs_uri_extract_dirname (uri);
/* remove the last '/' */
length = strlen (to_path);
if (to_path [length - 1] == '/') {
to_path [length - 1] = '\0';
}
gnome_vfs_uri_unref (uri);
to_prefix = _("To:");
}
nautilus_file_operations_progress_new_file (dialog,
progress_label_text ? progress_label_text : "",
item ? item : "",
from_path ? from_path : "",
to_path ? to_path : "",
from_prefix, to_prefix, index, size);
g_free (progress_label_text);
g_free (item);
g_free (from_path);
g_free (to_path);
}
static int
handle_xfer_ok (const GnomeVFSXferProgressInfo *progress_info,
XferInfo *xfer_info)
{
switch (progress_info->phase) {
case GNOME_VFS_XFER_PHASE_INITIAL:
create_xfer_dialog (progress_info, xfer_info);
return TRUE;
case GNOME_VFS_XFER_PHASE_COLLECTING:
if (xfer_info->progress_dialog != NULL) {
nautilus_file_operations_progress_set_operation_string
(NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog),
xfer_info->preparation_name);
}
return TRUE;
case GNOME_VFS_XFER_PHASE_READYTOGO:
if (xfer_info->progress_dialog != NULL) {
progress_dialog_set_files_done_text (
NAUTILUS_FILE_OPERATIONS_PROGRESS (xfer_info->progress_dialog),
xfer_info->action_verb);
nautilus_file_operations_progress_set_total
(NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog),
progress_info->files_total,
progress_info->bytes_total);
}
return TRUE;
case GNOME_VFS_XFER_PHASE_DELETESOURCE:
nautilus_file_changes_consume_changes (FALSE);
if (xfer_info->progress_dialog != NULL) {
progress_dialog_set_to_from_item_text (
NAUTILUS_FILE_OPERATIONS_PROGRESS (xfer_info->progress_dialog),
xfer_info->progress_verb,
progress_info->source_name,
NULL,
progress_info->file_index,
progress_info->file_size);
nautilus_file_operations_progress_update_sizes
(NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog),
MIN (progress_info->bytes_copied,
progress_info->bytes_total),
MIN (progress_info->total_bytes_copied,
progress_info->bytes_total));
}
return TRUE;
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 (xfer_info->progress_dialog != NULL) {
if (progress_info->bytes_copied == 0) {
progress_dialog_set_to_from_item_text (
NAUTILUS_FILE_OPERATIONS_PROGRESS (xfer_info->progress_dialog),
xfer_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
(NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog),
MIN (progress_info->bytes_copied,
progress_info->bytes_total),
MIN (progress_info->total_bytes_copied,
progress_info->bytes_total));
}
}
return TRUE;
case GNOME_VFS_XFER_PHASE_CLEANUP:
if (xfer_info->progress_dialog != NULL) {
nautilus_file_operations_progress_clear(
NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog));
nautilus_file_operations_progress_set_operation_string
(NAUTILUS_FILE_OPERATIONS_PROGRESS
(xfer_info->progress_dialog),
xfer_info->cleanup_name);
}
return TRUE;
case GNOME_VFS_XFER_PHASE_COMPLETED:
nautilus_file_changes_consume_changes (TRUE);
if (xfer_info->progress_dialog != NULL) {
gtk_widget_destroy (xfer_info->progress_dialog);
}
if (xfer_info->done_callback != NULL) {
xfer_info->done_callback (xfer_info->debuting_uris, xfer_info->done_callback_data);
/* done_callback now owns (will free) debuting_uris
*/
} else {
if (xfer_info->debuting_uris != NULL) {
nautilus_g_hash_table_destroy_deep (xfer_info->debuting_uris);
}
}
g_free (xfer_info);
return TRUE;
default:
return TRUE;
}
}
static int
handle_xfer_vfs_error (const GnomeVFSXferProgressInfo *progress_info,
XferInfo *xfer_info)
{
/* Notice that the error mode in `xfer_info' is the one we have been
* requested, but the transfer is always performed in mode
* `GNOME_VFS_XFER_ERROR_MODE_QUERY'.
*/
int result;
char *text;
char *unescaped_name;
char *current_operation;
switch (xfer_info->error_mode) {
case GNOME_VFS_XFER_ERROR_MODE_QUERY:
/* transfer error, prompt the user to continue or stop */
if (progress_info->source_name == NULL) {
unescaped_name = g_strdup ("");
} else {
char *name;
name = gnome_vfs_unescape_string_for_display (progress_info->source_name);
unescaped_name = g_strdup_printf (" \"%s\"", name);
g_free (name);
}
current_operation = g_strdup (xfer_info->progress_verb);
g_strdown (current_operation);
/* special case read only target errors or non-readable sources */
if (progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM
|| progress_info->vfs_status == GNOME_VFS_ERROR_READ_ONLY
|| progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED) {
if (progress_info->vfs_status == GNOME_VFS_ERROR_ACCESS_DENIED
&& progress_info->phase == GNOME_VFS_XFER_PHASE_OPENSOURCE) {
text = g_strdup_printf
(_("Error while %s.\n"
"%s is not readable."),
current_operation, unescaped_name);
} else {
if (progress_info->target_name != NULL) {
g_free (unescaped_name);
unescaped_name = gnome_vfs_unescape_string_for_display (
progress_info->target_name);
}
text = g_strdup_printf
(_("Error while %s items to \"%s\".\n"
"The destination is read-only."),
current_operation, unescaped_name);
}
g_free (current_operation);
g_free (unescaped_name);
result = nautilus_simple_dialog
(xfer_info->parent_view, TRUE, text,
_("Error while Copying"), _("Stop"), NULL);
g_free (text);
return GNOME_VFS_XFER_ERROR_ACTION_ABORT;
}
/* special case read only target errors */
if (progress_info->vfs_status == GNOME_VFS_ERROR_NO_SPACE) {
text = g_strdup_printf
(_("Error while %s%s.\n"
"There is no space on the destination."),
current_operation,
unescaped_name);
g_free (current_operation);
g_free (unescaped_name);
result = nautilus_simple_dialog
(xfer_info->parent_view, TRUE, text,
_("Error while Copying"), _("Stop"), NULL);
g_free (text);
return GNOME_VFS_XFER_ERROR_ACTION_ABORT;
}
text = g_strdup_printf
(_("Error \"%s\" while %s%s.\n"
"Would you like to continue?"),
gnome_vfs_result_to_string (progress_info->vfs_status),
current_operation,
unescaped_name);
g_free (current_operation);
g_free (unescaped_name);
result = nautilus_simple_dialog
(xfer_info->parent_view, TRUE, text,
_("Error while Copying"),
_("Skip"), _("Retry"), _("Stop"), NULL);
g_free (text);
switch (result) {
case 0:
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
case 1:
return GNOME_VFS_XFER_ERROR_ACTION_RETRY;
default:
g_assert_not_reached ();
/* fall through */
case 2:
return GNOME_VFS_XFER_ERROR_ACTION_ABORT;
}
case GNOME_VFS_XFER_ERROR_MODE_ABORT:
default:
if (xfer_info->progress_dialog != NULL) {
nautilus_file_operations_progress_freeze
(NAUTILUS_FILE_OPERATIONS_PROGRESS (xfer_info->progress_dialog));
nautilus_file_operations_progress_thaw
(NAUTILUS_FILE_OPERATIONS_PROGRESS (xfer_info->progress_dialog));
gtk_widget_destroy (xfer_info->progress_dialog);
}
return GNOME_VFS_XFER_ERROR_ACTION_ABORT;
}
}
static int
handle_xfer_overwrite (const GnomeVFSXferProgressInfo *progress_info,
XferInfo *xfer_info)
{
/* transfer conflict, prompt the user to replace or skip */
int result;
char *text;
char *unescaped_name;
unescaped_name = gnome_vfs_unescape_string_for_display (progress_info->target_name);
text = g_strdup_printf (_("File %s already exists.\n"
"Would you like to replace it?"),
unescaped_name);
g_free (unescaped_name);
if (progress_info->duplicate_count == 1) {
/* we are going to only get one duplicate alert, don't offer
* Replace All
*/
result = nautilus_simple_dialog
(xfer_info->parent_view, TRUE, text,
_("Conflict while Copying"),
_("Replace"), _("Skip"), NULL);
switch (result) {
case 0:
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE;
default:
g_assert_not_reached ();
/* fall through */
case 1:
return GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP;
}
} else {
result = nautilus_simple_dialog
(xfer_info->parent_view, TRUE, text,
_("Conflict while Copying"),
_("Replace All"), _("Replace"), _("Skip"), NULL);
switch (result) {
case 0:
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE_ALL;
case 1:
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE;
default:
g_assert_not_reached ();
/* fall through */
case 2:
return GNOME_VFS_XFER_OVERWRITE_ACTION_SKIP;
}
}
}
/* Note that we have these two separate functions with separate format
* strings for ease of localization.
*/
static char *
get_link_name (char *name, int count)
{
char *result;
char *unescaped_name;
char *unescaped_result;
const char *format;
g_assert (name != NULL);
unescaped_name = gnome_vfs_unescape_string (name, "/");
g_free (name);
if (count < 1) {
g_warning ("bad count in get_link_name");
count = 1;
}
if (count <= 2) {
/* Handle special cases for low numbers.
* Perhaps for some locales we will need to add more.
*/
switch (count) {
default:
g_assert_not_reached ();
/* fall through */
case 1:
format = _("link to %s");
break;
case 2:
format = _("another link to %s");
break;
}
unescaped_result = g_strdup_printf (format, unescaped_name);
} else {
/* Handle special cases for the first few numbers of each ten.
* For locales where getting this exactly right is difficult,
* these can just be made all the same as the general case below.
*/
switch (count % 10) {
case 1:
/* Localizers: Feel free to leave out the "st" suffix
* if there's no way to do that nicely for a
* particular language.
*/
format = _("%dst link to %s");
break;
case 2:
format = _("%dnd link to %s");
break;
case 3:
format = _("%drd link to %s");
break;
default:
format = _("%dth link to %s");
break;
}
unescaped_result = g_strdup_printf (format, count, unescaped_name);
}
result = gnome_vfs_escape_path_string (unescaped_result);
g_free (unescaped_name);
g_free (unescaped_result);
return result;
}
/* Localizers:
* Feel free to leave out the st, nd, rd and th suffix or
* make some or all of them match.
*/
#define COPY_DUPLICATE_TAG _(" (copy)")
#define FIRST_COPY_DUPLICATE_FORMAT _("%s (copy)%s")
#define ANOTHER_COPY_DUPLICATE_TAG _(" (another copy)")
#define SECOND_COPY_DUPLICATE_FORMAT _("%s (another copy)%s")
#define ST_COPY_DUPLICATE_TAG _("st copy)")
#define ST_COPY_DUPLICATE_FORMAT _("%s (%dst copy)%s")
#define ND_COPY_DUPLICATE_TAG _("nd copy)")
#define ND_COPY_DUPLICATE_FORMAT _("%s (%dnd copy)%s")
#define RD_COPY_DUPLICATE_TAG _("rd copy)")
#define RD_COPY_DUPLICATE_FORMAT _("%s (%drd copy)%s")
#define TH_COPY_DUPLICATE_TAG _("th copy)")
#define TH_COPY_DUPLICATE_FORMAT _("%s (%dth copy)%s")
static char *
extract_string_until (const char *original, const char *until_substring)
{
char *result;
g_assert (strlen (original) >= until_substring - original);
g_assert (until_substring - original >= 0);
result = g_malloc (until_substring - original + 1);
strncpy (result, original, until_substring - original);
result[until_substring - original] = '\0';
return result;
}
/* Dismantle a file name, separating the base name, the file suffix and removing any
* (xxxcopy), etc. string. Figure out the count that corresponds to the given
* (xxxcopy) substring.
*/
static void
parse_previous_duplicate_name (const char *name, char **name_base, const char **suffix,
int *count)
{
const char *tag;
g_assert (name[0] != '\0');
*suffix = strrchr (name + 1, '.');
if (*suffix == NULL || (*suffix)[1] == '\0') {
/* no suffix */
*suffix = "";
}
tag = strstr (name, COPY_DUPLICATE_TAG);
if (tag != NULL) {
if (tag > *suffix) {
/* handle case "foo. (copy)" */
*suffix = "";
}
*name_base = extract_string_until (name, tag);
*count = 1;
return;
}
tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAG);
if (tag != NULL) {
if (tag > *suffix) {
/* handle case "foo. (another copy)" */
*suffix = "";
}
*name_base = extract_string_until (name, tag);
*count = 2;
return;
}
/* Check to see if we got one of st, nd, rd, th. */
tag = strstr (name, ST_COPY_DUPLICATE_TAG);
if (tag == NULL) {
tag = strstr (name, ND_COPY_DUPLICATE_TAG);
}
if (tag == NULL) {
tag = strstr (name, RD_COPY_DUPLICATE_TAG);
}
if (tag == NULL) {
tag = strstr (name, TH_COPY_DUPLICATE_TAG);
}
/* If we got one of st, nd, rd, th, fish out the duplicate number. */
if (tag != NULL) {
/* localizers: opening parentheses to match the "th copy)" string */
tag = strstr (name, _(" ("));
if (tag != NULL) {
if (tag > *suffix) {
/* handle case "foo. (22nd copy)" */
*suffix = "";
}
*name_base = extract_string_until (name, tag);
/* localizers: opening parentheses of the "th copy)" string */
if (sscanf (tag, _(" (%d"), count) == 1) {
if (*count < 1 || *count > 1000000) {
/* keep the count within a reasonable range */
*count = 0;
}
return;
}
*count = 0;
return;
}
}
*count = 0;
if (**suffix != '\0') {
*name_base = extract_string_until (name, *suffix);
} else {
*name_base = strdup (name);
}
}
static char *
make_next_duplicate_name (const char *base, const char *suffix, int count)
{
const char *format;
char *result;
if (count < 1) {
char buffer [256];
sprintf(buffer, "bad count %d in get_duplicate_name", count);
g_warning (buffer);
count = 1;
}
if (count <= 2) {
/* Handle special cases for low numbers.
* Perhaps for some locales we will need to add more.
*/
switch (count) {
default:
g_assert_not_reached ();
/* fall through */
case 1:
format = FIRST_COPY_DUPLICATE_FORMAT;
break;
case 2:
format = SECOND_COPY_DUPLICATE_FORMAT;
break;
}
result = g_strdup_printf (format, base, suffix);
} else {
/* Handle special cases for the first few numbers of each ten.
* For locales where getting this exactly right is difficult,
* these can just be made all the same as the general case below.
*/
switch (count % 10) {
case 1:
format = ST_COPY_DUPLICATE_FORMAT;
break;
case 2:
format = ND_COPY_DUPLICATE_FORMAT;
break;
case 3:
format = RD_COPY_DUPLICATE_FORMAT;
break;
default:
/* The general case. */
format = TH_COPY_DUPLICATE_FORMAT;
break;
}
result = g_strdup_printf (format, base, count, suffix);
}
return result;
}
static char *
get_duplicate_name (const char *name, int count_increment)
{
char *result;
char *name_base;
const char *suffix;
int count;
parse_previous_duplicate_name (name, &name_base, &suffix, &count);
result = make_next_duplicate_name (name_base, suffix, count + count_increment);
g_free (name_base);
return result;
}
static char *
get_next_duplicate_name (char *name, int count_increment)
{
char *unescaped_name;
char *unescaped_result;
char *result;
unescaped_name = gnome_vfs_unescape_string (name, "/");
g_free (name);
unescaped_result = get_duplicate_name (unescaped_name, count_increment);
g_free (unescaped_name);
result = gnome_vfs_escape_path_string (unescaped_result);
g_free (unescaped_result);
return result;
}
static int
handle_xfer_duplicate (GnomeVFSXferProgressInfo *progress_info,
XferInfo *xfer_info)
{
switch (xfer_info->kind) {
case XFER_LINK:
progress_info->duplicate_name = get_link_name
(progress_info->duplicate_name,
progress_info->duplicate_count);
break;
case XFER_COPY:
case XFER_MOVE_TO_TRASH:
progress_info->duplicate_name = get_next_duplicate_name
(progress_info->duplicate_name,
progress_info->duplicate_count);
break;
default:
/* For all other cases we use the name as-is. */
}
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
}
static int
update_xfer_callback (GnomeVFSAsyncHandle *handle,
GnomeVFSXferProgressInfo *progress_info,
gpointer data)
{
XferInfo *xfer_info;
xfer_info = (XferInfo *) data;
switch (progress_info->status) {
case GNOME_VFS_XFER_PROGRESS_STATUS_OK:
return handle_xfer_ok (progress_info, xfer_info);
case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR:
return handle_xfer_vfs_error (progress_info, xfer_info);
case GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE:
return handle_xfer_overwrite (progress_info, xfer_info);
case GNOME_VFS_XFER_PROGRESS_STATUS_DUPLICATE:
return handle_xfer_duplicate (progress_info, xfer_info);
default:
g_warning (_("Unknown GnomeVFSXferProgressStatus %d"),
progress_info->status);
return 0;
}
}
static void
apply_one_position (IconPositionIterator *position_iterator,
const char *source_name, const char *target_name)
{
const char *item_uri;
if (position_iterator == NULL || position_iterator->last_uri == NULL) {
return;
}
for (;;) {
/* Scan for the next point that matches the source_name
* uri.
*/
if (strcmp ((const char *)position_iterator->last_uri->data,
source_name) == 0) {
break;
}
/* Didn't match -- a uri must have been skipped by the copy
* engine because of a name conflict. All we need to do is
* skip ahead too.
*/
position_iterator->last_uri = position_iterator->last_uri->next;
position_iterator->last_icon_position_index++;
if (position_iterator->last_uri == NULL) {
/* we are done, no more points left */
return;
}
}
item_uri = target_name != NULL ? target_name : source_name;
/* apply the location to the target file */
nautilus_file_changes_queue_schedule_position_setting (target_name,
position_iterator->icon_positions
[position_iterator->last_icon_position_index]);
/* advance to the next point for next time */
position_iterator->last_uri = position_iterator->last_uri->next;
position_iterator->last_icon_position_index++;
}
typedef struct {
GHashTable *debuting_uris;
IconPositionIterator *iterator;
} SyncXferInfo;
/* Low-level callback, called for every copy engine operation.
* Generates notifications about new, deleted and moved files.
*/
static int
sync_xfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data)
{
GHashTable *debuting_uris;
IconPositionIterator *position_iterator;
if (data != NULL) {
debuting_uris = ((SyncXferInfo *) data)->debuting_uris;
position_iterator = ((SyncXferInfo *) data)->iterator;
} else {
debuting_uris = NULL;
position_iterator = NULL;
}
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
*/
g_assert (progress_info->source_name != NULL);
nautilus_file_changes_queue_schedule_metadata_copy
(progress_info->source_name, progress_info->target_name);
apply_one_position (position_iterator, progress_info->source_name,
progress_info->target_name);
if (debuting_uris != NULL) {
g_hash_table_insert (debuting_uris, g_strdup (progress_info->target_name), NULL);
}
}
nautilus_file_changes_queue_file_added (progress_info->target_name);
break;
case GNOME_VFS_XFER_PHASE_MOVING:
if (progress_info->top_level_item) {
g_assert (progress_info->source_name != NULL);
nautilus_file_changes_queue_schedule_metadata_move
(progress_info->source_name, progress_info->target_name);
apply_one_position (position_iterator, progress_info->source_name,
progress_info->target_name);
if (debuting_uris != NULL) {
g_hash_table_insert (debuting_uris, g_strdup (progress_info->target_name), NULL);
}
}
nautilus_file_changes_queue_file_moved (progress_info->source_name,
progress_info->target_name);
break;
case GNOME_VFS_XFER_PHASE_DELETESOURCE:
if (progress_info->top_level_item) {
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_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;
}
}
return 1;
}
static gboolean
check_target_directory_is_or_in_trash (GnomeVFSURI *trash_dir_uri, GnomeVFSURI *target_dir_uri)
{
g_assert (target_dir_uri != NULL);
if (trash_dir_uri == NULL) {
return FALSE;
}
return gnome_vfs_uri_equal (trash_dir_uri, target_dir_uri)
|| gnome_vfs_uri_is_parent (trash_dir_uri, target_dir_uri, TRUE);
}
static GnomeVFSURI *
append_basename (const GnomeVFSURI *target_directory, const GnomeVFSURI *source_directory)
{
const char *filename;
filename = gnome_vfs_uri_extract_short_name (source_directory);
if (filename != NULL) {
return gnome_vfs_uri_append_file_name (target_directory, filename);
}
return gnome_vfs_uri_dup (target_directory);
}
/* is_special_link
*
* Check and see if file is one of our special links.
* A special link ould be one of the following:
* trash, home, volume
*/
static gboolean
is_special_link (const GnomeVFSURI *uri)
{
const char *local_path;
char *escaped_path;
if (!gnome_vfs_uri_is_local (uri)) {
return FALSE;
}
local_path = gnome_vfs_uri_get_path (uri);
if (local_path == NULL) {
return FALSE;
}
escaped_path = gnome_vfs_unescape_string_for_display (local_path);
if (escaped_path == NULL) {
return FALSE;
}
if (nautilus_link_local_is_trash_link (escaped_path)) {
g_free(escaped_path);
return TRUE;
}
if (nautilus_link_local_is_home_link (escaped_path)) {
g_free(escaped_path);
return TRUE;
}
if (nautilus_link_local_is_volume_link (escaped_path)) {
g_free(escaped_path);
return TRUE;
}
g_free(escaped_path);
return FALSE;
}
void
nautilus_file_operations_copy_move (const GList *item_uris,
const GdkPoint *relative_item_points,
const char *target_dir,
int copy_action,
GtkWidget *view,
void (*done_callback) (GHashTable *debuting_uris, gpointer data),
gpointer done_callback_data)
{
const GList *p;
GnomeVFSXferOptions move_options;
GList *source_uri_list, *target_uri_list;
GnomeVFSURI *source_uri, *target_uri;
GnomeVFSURI *source_dir_uri, *target_dir_uri;
GnomeVFSURI *trash_dir_uri;
GnomeVFSURI *uri;
XferInfo *xfer_info;
SyncXferInfo *sync_xfer_info;
GnomeVFSResult result;
gboolean same_fs;
gboolean is_trash_move;
gboolean duplicate;
IconPositionIterator *icon_position_iterator;
g_assert (item_uris != NULL);
target_dir_uri = NULL;
trash_dir_uri = NULL;
icon_position_iterator = NULL;
result = GNOME_VFS_OK;
source_uri_list = NULL;
target_uri_list = NULL;
same_fs = TRUE;
is_trash_move = FALSE;
duplicate = copy_action != GDK_ACTION_MOVE;
move_options = GNOME_VFS_XFER_RECURSIVE;
if (target_dir != NULL) {
if (nautilus_uri_is_trash (target_dir)) {
is_trash_move = TRUE;
} else {
target_dir_uri = gnome_vfs_uri_new (target_dir);
}
}
/* build the source and target URI lists and figure out if all the files are on the
* same disk
*/
for (p = item_uris; p != NULL; p = p->next) {
source_uri = gnome_vfs_uri_new ((const char *)p->data);
/* Filter out special Nautilus link files */
if (!is_special_link (source_uri)) {
source_uri_list = g_list_prepend (source_uri_list, source_uri);
source_dir_uri = gnome_vfs_uri_get_parent (source_uri);
if (target_dir != NULL) {
if (is_trash_move) {
gnome_vfs_find_directory (source_uri, GNOME_VFS_DIRECTORY_KIND_TRASH,
&target_dir_uri, FALSE, FALSE, 0777);
}
target_uri = append_basename (target_dir_uri, source_uri);
} else {
/* duplication */
target_uri = gnome_vfs_uri_ref (source_uri);
if (target_dir_uri == NULL) {
target_dir_uri = gnome_vfs_uri_ref (source_dir_uri);
}
}
target_uri_list = g_list_prepend (target_uri_list, target_uri);
gnome_vfs_check_same_fs_uris (source_uri, target_uri, &same_fs);
g_assert (target_dir_uri != NULL);
duplicate &= same_fs;
duplicate &= gnome_vfs_uri_equal (source_dir_uri, target_dir_uri);
gnome_vfs_uri_unref (source_dir_uri);
}
}
if (duplicate) {
/* Copy operation, parents match -> duplicate operation. Ask gnome-vfs
* to generate unique names for target files
*/
move_options |= GNOME_VFS_XFER_USE_UNIQUE_NAMES;
}
/* List may be NULL if we filtered all items out */
if (source_uri_list == NULL) {
if (target_dir_uri != NULL) {
gnome_vfs_uri_unref (target_dir_uri);
}
if (target_uri_list != NULL) {
gnome_vfs_uri_list_free (target_uri_list);
}
return;
}
source_uri_list = g_list_reverse (source_uri_list);
target_uri_list = g_list_reverse (target_uri_list);
if (copy_action == GDK_ACTION_MOVE) {
move_options |= GNOME_VFS_XFER_REMOVESOURCE;
} else if (copy_action == GDK_ACTION_LINK) {
move_options |= GNOME_VFS_XFER_LINK_ITEMS;
}
/* set up the copy/move parameters */
xfer_info = g_new0 (XferInfo, 1);
xfer_info->parent_view = view;
xfer_info->progress_dialog = NULL;
if (relative_item_points != NULL) {
icon_position_iterator = icon_position_iterator_new (relative_item_points, item_uris);
}
if ((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) {
xfer_info->operation_title = _("Moving files");
xfer_info->action_verb =_("moved");
xfer_info->progress_verb =_("Moving");
xfer_info->preparation_name =_("Preparing To Move...");
xfer_info->cleanup_name = _("Finishing Move...");
xfer_info->kind = XFER_MOVE;
/* Do an arbitrary guess that an operation will take very little
* time and the progress shouldn't be shown.
*/
xfer_info->show_progress_dialog =
!same_fs || g_list_length ((GList *)item_uris) > 20;
} else if ((move_options & GNOME_VFS_XFER_LINK_ITEMS) != 0) {
xfer_info->operation_title = _("Creating links to files");
xfer_info->action_verb =_("linked");
xfer_info->progress_verb =_("Linking");
xfer_info->preparation_name = _("Preparing to Create Links...");
xfer_info->cleanup_name = _("Finishing Creating Links...");
xfer_info->kind = XFER_LINK;
xfer_info->show_progress_dialog =
g_list_length ((GList *)item_uris) > 20;
} else {
xfer_info->operation_title = _("Copying files");
xfer_info->action_verb =_("copied");
xfer_info->progress_verb =_("Copying");
xfer_info->preparation_name =_("Preparing To Copy...");
xfer_info->cleanup_name = "";
xfer_info->kind = XFER_COPY;
/* always show progress during copy */
xfer_info->show_progress_dialog = TRUE;
}
/* we'll need to check for copy into Trash and for moving/copying the Trash itself */
gnome_vfs_find_directory (target_dir_uri, GNOME_VFS_DIRECTORY_KIND_TRASH,
&trash_dir_uri, FALSE, FALSE, 0777);
if ((move_options & GNOME_VFS_XFER_REMOVESOURCE) == 0) {
/* don't allow copying into Trash */
if (check_target_directory_is_or_in_trash (trash_dir_uri, target_dir_uri)) {
nautilus_simple_dialog
(view,
FALSE,
_("You cannot copy items into the Trash."),
_("Can't Copy to Trash"),
GNOME_STOCK_BUTTON_OK, NULL, NULL);
result = GNOME_VFS_ERROR_NOT_PERMITTED;
}
}
if (result == GNOME_VFS_OK) {
for (p = source_uri_list; p != NULL; p = p->next) {
uri = (GnomeVFSURI *)p->data;
/* Check that the Trash is not being moved/copied */
if (trash_dir_uri != NULL && gnome_vfs_uri_equal (uri, trash_dir_uri)) {
nautilus_simple_dialog
(view,
FALSE,
((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0)
? _("The Trash must remain on the desktop.")
: _("You cannot copy the Trash."),
((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0)
? _("Can't Change Trash Location")
: _("Can't Copy Trash"),
GNOME_STOCK_BUTTON_OK, NULL, NULL);
result = GNOME_VFS_ERROR_NOT_PERMITTED;
break;
}
/* Don't allow recursive move/copy into itself.
* (We would get a file system error if we proceeded but it is nicer to
* detect and report it at this level)
*/
if ((move_options & GNOME_VFS_XFER_LINK_ITEMS) == 0
&& (gnome_vfs_uri_equal (uri, target_dir_uri)
|| gnome_vfs_uri_is_parent (uri, target_dir_uri, TRUE))) {
nautilus_simple_dialog
(view,
FALSE,
((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0)
? _("You cannot move a folder into itself.")
: _("You cannot copy a folder into itself."),
_("Can't Move Into Self"),
GNOME_STOCK_BUTTON_OK, NULL, NULL);
result = GNOME_VFS_ERROR_NOT_PERMITTED;
break;
}
}
}
xfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
xfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_QUERY;
xfer_info->done_callback = done_callback;
xfer_info->done_callback_data = done_callback_data;
xfer_info->debuting_uris = g_hash_table_new (g_str_hash, g_str_equal);
sync_xfer_info = g_new (SyncXferInfo, 1);
sync_xfer_info->iterator = icon_position_iterator;
sync_xfer_info->debuting_uris = xfer_info->debuting_uris;
if (result == GNOME_VFS_OK) {
gnome_vfs_async_xfer (&xfer_info->handle, source_uri_list, target_uri_list,
move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY,
GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
&update_xfer_callback, xfer_info,
&sync_xfer_callback, sync_xfer_info);
}
gnome_vfs_uri_list_free (source_uri_list);
gnome_vfs_uri_list_free (target_uri_list);
if (trash_dir_uri != NULL) {
gnome_vfs_uri_unref (trash_dir_uri);
}
gnome_vfs_uri_unref (target_dir_uri);
}
typedef struct {
GnomeVFSAsyncHandle *handle;
void (* done_callback)(const char *new_folder_uri, gpointer data);
gpointer data;
} NewFolderXferState;
static int
new_folder_xfer_callback (GnomeVFSAsyncHandle *handle,
GnomeVFSXferProgressInfo *progress_info, gpointer data)
{
NewFolderXferState *state;
char *temp_string;
state = (NewFolderXferState *) data;
switch (progress_info->status) {
case GNOME_VFS_XFER_PROGRESS_STATUS_OK:
nautilus_file_changes_consume_changes (TRUE);
(state->done_callback) (progress_info->target_name, state->data);
g_free (state);
return 0;
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);
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
default:
g_warning (_("Unknown GnomeVFSXferProgressStatus %d"),
progress_info->status);
return 0;
}
}
void
nautilus_file_operations_new_folder (GtkWidget *parent_view,
const char *parent_dir,
void (*done_callback)(const char *, gpointer),
gpointer data)
{
NewFolderXferState *state;
GList *target_uri_list;
GnomeVFSURI *uri, *parent_uri;
state = g_new (NewFolderXferState, 1);
state->done_callback = done_callback;
state->data = data;
/* pass in the target directory and the new folder name as a destination URI */
parent_uri = gnome_vfs_uri_new (parent_dir);
uri = gnome_vfs_uri_append_file_name (parent_uri, _("untitled folder"));
target_uri_list = g_list_append (NULL, uri);
gnome_vfs_async_xfer (&state->handle, NULL, target_uri_list,
GNOME_VFS_XFER_NEW_UNIQUE_DIRECTORY,
GNOME_VFS_XFER_ERROR_MODE_QUERY,
GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
&new_folder_xfer_callback, state,
&sync_xfer_callback, NULL);
gnome_vfs_uri_list_free (target_uri_list);
gnome_vfs_uri_unref (parent_uri);
}
void
nautilus_file_operations_move_to_trash (const GList *item_uris,
GtkWidget *parent_view)
{
const GList *p;
GnomeVFSURI *trash_dir_uri;
GnomeVFSURI *source_uri;
GList *source_uri_list, *target_uri_list;
GnomeVFSResult result;
XferInfo *xfer_info;
gboolean bail;
char *text;
char *item_name;
g_assert (item_uris != NULL);
trash_dir_uri = NULL;
source_uri_list = NULL;
target_uri_list = NULL;
result = GNOME_VFS_OK;
/* build the source and uri list, checking if any of the delete itmes are Trash */
for (p = item_uris; p != NULL; p = p->next) {
bail = FALSE;
source_uri = gnome_vfs_uri_new ((const char *)p->data);
source_uri_list = g_list_prepend (source_uri_list, source_uri);
if (trash_dir_uri == NULL) {
GnomeVFSURI *source_dir_uri;
source_dir_uri = gnome_vfs_uri_get_parent (source_uri);
result = gnome_vfs_find_directory (source_dir_uri, GNOME_VFS_DIRECTORY_KIND_TRASH,
&trash_dir_uri, FALSE, FALSE, 0777);
gnome_vfs_uri_unref (source_dir_uri);
}
if (result != GNOME_VFS_OK) {
break;
}
g_assert (trash_dir_uri != NULL);
target_uri_list = g_list_prepend (target_uri_list, append_basename (trash_dir_uri, source_uri));
if (gnome_vfs_uri_equal (source_uri, trash_dir_uri)) {
nautilus_simple_dialog
(parent_view,
FALSE,
_("The Trash must remain on the desktop."),
_("Can't Change Trash Location"),
GNOME_STOCK_BUTTON_OK, NULL, NULL);
bail = TRUE;
} else if (gnome_vfs_uri_is_parent (source_uri, trash_dir_uri, TRUE)) {
item_name = nautilus_convert_to_unescaped_string_for_display
(gnome_vfs_uri_extract_short_name (source_uri));
text = g_strdup_printf
(_("You cannot throw \"%s\" into the Trash."),
item_name);
nautilus_simple_dialog
(parent_view, FALSE, text,
_("Error Moving to Trash"),
GNOME_STOCK_BUTTON_OK, NULL, NULL);
bail = TRUE;
g_free (text);
g_free (item_name);
}
if (bail) {
result = GNOME_VFS_ERROR_NOT_PERMITTED;
break;
}
}
source_uri_list = g_list_reverse (source_uri_list);
target_uri_list = g_list_reverse (target_uri_list);
if (result == GNOME_VFS_OK) {
g_assert (trash_dir_uri != NULL);
/* set up the move parameters */
xfer_info = g_new0 (XferInfo, 1);
xfer_info->parent_view = parent_view;
xfer_info->progress_dialog = NULL;
/* Do an arbitrary guess that an operation will take very little
* time and the progress shouldn't be shown.
*/
xfer_info->show_progress_dialog = g_list_length ((GList *)item_uris) > 20;
xfer_info->operation_title = _("Moving files to the Trash");
xfer_info->action_verb =_("thrown out");
xfer_info->progress_verb =_("Moving");
xfer_info->preparation_name =_("Preparing to Move to Trash...");
xfer_info->cleanup_name ="";
xfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
xfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
xfer_info->kind = XFER_MOVE_TO_TRASH;
gnome_vfs_async_xfer (&xfer_info->handle, source_uri_list, target_uri_list,
GNOME_VFS_XFER_REMOVESOURCE | GNOME_VFS_XFER_USE_UNIQUE_NAMES,
GNOME_VFS_XFER_ERROR_MODE_QUERY,
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
&update_xfer_callback, xfer_info,
&sync_xfer_callback, NULL);
}
gnome_vfs_uri_list_free (source_uri_list);
gnome_vfs_uri_list_free (target_uri_list);
gnome_vfs_uri_unref (trash_dir_uri);
}
void
nautilus_file_operations_delete (const GList *item_uris,
GtkWidget *parent_view)
{
GList *uri_list;
const GList *p;
XferInfo *xfer_info;
uri_list = NULL;
for (p = item_uris; p != NULL; p = p->next) {
uri_list = g_list_prepend (uri_list,
gnome_vfs_uri_new ((const char *)p->data));
}
uri_list = g_list_reverse (uri_list);
xfer_info = g_new0 (XferInfo, 1);
xfer_info->parent_view = parent_view;
xfer_info->progress_dialog = NULL;
xfer_info->show_progress_dialog = TRUE;
xfer_info->operation_title = _("Deleting files");
xfer_info->action_verb =_("deleted");
xfer_info->progress_verb =_("Deleting");
xfer_info->preparation_name =_("Preparing to Delete files...");
xfer_info->cleanup_name ="";
xfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
xfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
xfer_info->kind = XFER_DELETE;
gnome_vfs_async_xfer (&xfer_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,
&update_xfer_callback, xfer_info,
&sync_xfer_callback, NULL);
gnome_vfs_uri_list_free (uri_list);
}
static void
do_empty_trash (GtkWidget *parent_view)
{
GnomeVFSURI *trash_dir_uri;
GnomeVFSResult result;
XferInfo *xfer_info;
GList *trash_dir_list;
/* FIXME bugzilla.eazel.com 638:
* add the different trash directories from the different volumes
*/
trash_dir_uri = NULL;
trash_dir_list = NULL;
result = gnome_vfs_find_directory (NULL, GNOME_VFS_DIRECTORY_KIND_TRASH,
&trash_dir_uri, FALSE, FALSE, 0777);
if (result == GNOME_VFS_OK) {
g_assert (trash_dir_uri != NULL);
/* set up the move parameters */
xfer_info = g_new0 (XferInfo, 1);
xfer_info->parent_view = parent_view;
xfer_info->progress_dialog = NULL;
xfer_info->show_progress_dialog = TRUE;
xfer_info->operation_title = _("Emptying the Trash");
xfer_info->action_verb =_("deleted");
xfer_info->progress_verb =_("Deleting");
xfer_info->preparation_name =_("Preparing to Empty the Trash...");
xfer_info->cleanup_name ="";
xfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
xfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
xfer_info->kind = XFER_EMPTY_TRASH;
trash_dir_list = g_list_append (NULL, trash_dir_uri);
gnome_vfs_async_xfer (&xfer_info->handle, trash_dir_list, NULL,
GNOME_VFS_XFER_EMPTY_DIRECTORIES,
GNOME_VFS_XFER_ERROR_MODE_QUERY,
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
&update_xfer_callback, xfer_info,
&sync_xfer_callback, NULL);
}
gnome_vfs_uri_list_free (trash_dir_list);
}
static gboolean
confirm_empty_trash (GtkWidget *parent_view)
{
GnomeDialog *dialog;
GtkWindow *parent_window;
/* Just Say Yes if the preference says not to confirm. */
if (!nautilus_preferences_get_boolean (NAUTILUS_PREFERENCES_CONFIRM_TRASH, TRUE)) {
return TRUE;
}
parent_window = GTK_WINDOW (gtk_widget_get_toplevel (parent_view));
dialog = nautilus_yes_no_dialog (
_("Are you sure you want to permanently delete "
"all of the items in the trash?"),
_("Delete Trash Contents?"),
_("Empty"),
GNOME_STOCK_BUTTON_CANCEL,
parent_window);
gnome_dialog_set_default (dialog, GNOME_CANCEL);
return gnome_dialog_run (dialog) == GNOME_OK;
}
void
nautilus_file_operations_empty_trash (GtkWidget *parent_view)
{
g_return_if_fail (parent_view != NULL);
/*
* I chose to use a modal confirmation dialog here.
* If we used a modeless dialog, we'd have to do work to
* make sure that no more than one appears on screen at
* a time. That one probably couldn't be parented, because
* otherwise you'd get into weird layer-shifting problems
* selecting "Empty Trash" from one window when there was
* already a modeless "Empty Trash" dialog parented on a
* different window. And if the dialog were not parented, it
* might show up in some weird place since window manager
* placement is unreliable (i.e., sucks). So modal it is.
*/
if (confirm_empty_trash (parent_view)) {
do_empty_trash (parent_view);
}
}
#if !defined (NAUTILUS_OMIT_SELF_CHECK)
static gboolean
test_next_duplicate_name (const char *name, const char *expected_next_name)
{
gboolean result;
char *next_name;
next_name = get_duplicate_name (name, 1);
result = strcmp (expected_next_name, next_name) == 0;
if (!result) {
printf("expected %s, got %s\n", expected_next_name, next_name);
}
g_free (next_name);
return result;
}
void
nautilus_self_check_file_operations (void)
{
/* test the next duplicate name generator */
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_(" (copy)"), _(" (another copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo"), _("foo (copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_(".bashrc"), _(".bashrc (copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_(".foo.txt"), _(".foo (copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo"), _("foo foo (copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo.txt"), _("foo (copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo.txt"), _("foo foo (copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo.txt txt"), _("foo foo (copy).txt txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo...txt"), _("foo.. (copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo..."), _("foo... (copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo. (copy)"), _("foo. (another copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (copy)"), _("foo (another copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (copy).txt"), _("foo (another copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (another copy)"), _("foo (3rd copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (another copy).txt"), _("foo (3rd copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo (another copy).txt"), _("foo foo (3rd copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (21st copy)"), _("foo (22nd copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (21st copy).txt"), _("foo (22nd copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (22nd copy)"), _("foo (23rd copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (22nd copy).txt"), _("foo (23rd copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (23rd copy)"), _("foo (24th copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (23rd copy).txt"), _("foo (24th copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (24th copy)"), _("foo (25th copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo (24th copy).txt"), _("foo (25th copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo (24th copy)"), _("foo foo (25th copy)")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo (24th copy).txt"), _("foo foo (25th copy).txt")), TRUE);
NAUTILUS_CHECK_BOOLEAN_RESULT (test_next_duplicate_name (_("foo foo (100000000000000th copy).txt"), _("foo foo (copy).txt")), TRUE);
}
#endif