view src/utilops.c @ 1:b3e0e515fabf

Initial revision
author gqview
date Mon, 03 Apr 2000 18:24:05 +0000
parents
children c0e337a01cb7
line wrap: on
line source

/*
 * GQview image viewer
 * (C)1999 John Ellis
 *
 * Author: John Ellis
 *
 */

#include "gqview.h"

enum {
	DIALOG_NEW_DIR,
	DIALOG_COPY,
	DIALOG_MOVE,
	DIALOG_DELETE,
	DIALOG_RENAME
};

typedef struct _FileDataMult FileDataMult;
struct _FileDataMult
{
	gint confirm_all;
	gint confirmed;
	gint skip;
	GList *source_list;
	GList *source_next;
	gchar *dest_base;
	gchar *source;
	gchar *dest;
	gint copy;
};

typedef struct _FileDataSingle FileDataSingle;
struct _FileDataSingle
{
	gint confirmed;
	gchar *source;
	gchar *dest;
	gint copy;
};

static FileDataMult *file_data_multiple_new(GList *source_list, gchar *dest, gint copy);
static void file_data_multiple_free(FileDataMult *fdm);
static void file_util_move_multiple(FileDataMult *fdm);
static void file_util_move_multiple_ok_cb(GtkWidget *widget, gpointer data);
static void file_util_move_multiple_all_cb(GtkWidget *widget, gpointer data);
static void file_util_move_multiple_skip_cb(GtkWidget *widget, gpointer data);
static void file_util_move_multiple_cancel_cb(GtkWidget *widget, gpointer data);
static void file_util_move_multiple(FileDataMult *fdm);

static FileDataSingle *file_data_single_new(gchar *source, gchar *dest, gint copy);
static void file_data_single_free(FileDataSingle *fds);
static void file_util_move_single_ok_cb(GtkWidget *widget, gpointer data);
static void file_util_move_single(FileDataSingle *fds);
static void file_util_move_single_cancel_cb(GtkWidget *widget, gpointer data);
static void file_util_move_do(FileDialog *fd);
static void file_util_move_check(FileDialog *fd);
static void file_util_move_cb(GtkWidget *widget, gpointer data);
static void file_util_move_enter_cb(gchar *path, gpointer data);
static void file_util_move_completion_sync_cb(gchar *path, gpointer data);
static void real_file_util_move(gchar *source_path, GList *source_list, gchar *dest_path, gint copy);

static void file_util_delete_multiple_ok_cb(GtkWidget *w, gpointer data);
static void file_util_delete_multiple_cancel_cb(GtkWidget *w, gpointer data);
static void file_util_delete_multiple(GList *source_list);
static void file_util_delete_ok_cb(GtkWidget *w, gpointer data);
static void file_util_delete_cancel_cb(GtkWidget *w, gpointer data);
static void file_util_delete_single(gchar *path);

static void file_util_rename_multiple_ok_cb(GtkWidget *w, gpointer data);
static void file_util_rename_multiple_cancel_cb(GtkWidget *w, gpointer data);
static void file_util_rename_multiple(FileDialog *fd);
static void file_util_rename_multiple_cb(GtkWidget *w, gpointer data);
static void file_util_rename_multiple_select_cb(GtkWidget *clist,
		gint row, gint column, GdkEventButton *bevent, gpointer data);
static void file_util_rename_multiple_do(GList *source_list);

static void file_util_rename_single_ok_cb(GtkWidget *w, gpointer data);
static void file_util_rename_single_cancel_cb(GtkWidget *w, gpointer data);
static void file_util_rename_single(FileDataSingle *fds);
static void file_util_rename_single_cb(GtkWidget *w, gpointer data);
static void file_util_rename_single_do(gchar *source_path);

static void file_util_create_dir_do(gchar *source, gchar *path);
static void file_util_create_dir_cb(GtkWidget *w, gpointer data);

/*
 *--------------------------------------------------------------------------
 * Move and Copy routines
 *--------------------------------------------------------------------------
 */

/*
 * Multi file move
 */

static FileDataMult *file_data_multiple_new(GList *source_list, gchar *dest, gint copy)
{
	FileDataMult *fdm = g_new0(FileDataMult, 1);
	fdm->confirm_all = FALSE;
	fdm->confirmed = FALSE;
	fdm->skip = FALSE;
	fdm->source_list = source_list;
	fdm->source_next = fdm->source_list;
	fdm->dest_base = g_strdup(dest);
	fdm->source = NULL;
	fdm->dest = NULL;
	fdm->copy = copy;
	return fdm;
}

static void file_data_multiple_free(FileDataMult *fdm)
{
	free_selected_list(fdm->source_list);
	g_free(fdm->dest_base);
	g_free(fdm->dest);
	g_free(fdm);
}

static void file_util_move_multiple_ok_cb(GtkWidget *widget, gpointer data)
{
	FileDataMult *fdm = data;
	fdm->confirmed = TRUE;
	file_util_move_multiple(fdm);
}

static void file_util_move_multiple_all_cb(GtkWidget *widget, gpointer data)
{
	FileDataMult *fdm = data;
	fdm->confirm_all = TRUE;
	file_util_move_multiple(fdm);
}

static void file_util_move_multiple_skip_cb(GtkWidget *widget, gpointer data)
{
	FileDataMult *fdm = data;
	fdm->skip = TRUE;
	file_util_move_multiple(fdm);
}

static void file_util_move_multiple_cancel_cb(GtkWidget *widget, gpointer data)
{
	FileDataMult *fdm = data;
	file_data_multiple_free(fdm);
}

static void file_util_move_multiple(FileDataMult *fdm)
{
	while (fdm->dest || fdm->source_next)
		{
		if (!fdm->dest)
			{
			GList *work = fdm->source_next;
			fdm->source = work->data;
			fdm->dest = g_strconcat(fdm->dest_base, "/", filename_from_path(fdm->source), NULL);
			fdm->source_next = work->next;
			}

		if (isfile(fdm->dest) && !fdm->confirmed && !fdm->confirm_all && !fdm->skip)
			{
			ConfirmDialog *cd;
			gchar *text = g_strdup_printf(_("Overwrite file:\n %s\n with:\b %s"), fdm->dest, fdm->source);
			cd = confirm_dialog_new(_("Overwrite file"), text, file_util_move_multiple_cancel_cb, fdm);
			confirm_dialog_add(cd, _("Skip"), file_util_move_multiple_skip_cb);
			confirm_dialog_add(cd, _("Yes to all"), file_util_move_multiple_all_cb);
			confirm_dialog_add(cd, _("Yes"), file_util_move_multiple_ok_cb);
			g_free(text);
			return;
			}
		else
			{
			gint success = FALSE;
			if (fdm->skip)
				{
				success = TRUE;
				fdm->skip = FALSE;
				}
			else
				{
				if (fdm->copy)
					{
					success = copy_file(fdm->source, fdm->dest);
					}
				else
					{
					if (move_file(fdm->source, fdm->dest))
						{
						success = TRUE;
						file_is_gone(fdm->source, fdm->source_list);
						}
					}
				}
			if (!success)
				{
				ConfirmDialog *cd;
				gchar *title;
				gchar *text;
				if (fdm->copy)
					{
					title = _("Error copying file");
					text = g_strdup_printf(_("Unable to copy file:\n%sto:\n%s\n during multiple file copy."), fdm->source, fdm->dest);
					}
				else
					{
					title = _("Error moving file");
					text = g_strdup_printf(_("Unable to move file:\n%sto:\n%s\n during multiple file move."), fdm->source, fdm->dest);
					}
				cd = confirm_dialog_new(title, text, file_util_move_multiple_cancel_cb, fdm);
				confirm_dialog_add(cd, _("Continue"), file_util_move_multiple_skip_cb);
				g_free(text);
				return;
				}
			fdm->confirmed = FALSE;
			g_free(fdm->dest);
			fdm->dest = NULL;
			}
		}

	file_data_multiple_free(fdm);
}

/*
 * Single file move
 */

static FileDataSingle *file_data_single_new(gchar *source, gchar *dest, gint copy)
{
	FileDataSingle *fds = g_new0(FileDataSingle, 1);
	fds->confirmed = FALSE;
	fds->source = g_strdup(source);
	fds->dest = g_strdup(dest);
	fds->copy = copy;
	return fds;
}

static void file_data_single_free(FileDataSingle *fds)
{
	g_free(fds->source);
	g_free(fds->dest);
	g_free(fds);
}

static void file_util_move_single_ok_cb(GtkWidget *widget, gpointer data)
{
	FileDataSingle *fds = data;
	fds->confirmed = TRUE;
	file_util_move_single(fds);
}

static void file_util_move_single_cancel_cb(GtkWidget *widget, gpointer data)
{
	FileDataSingle *fds = data;
	file_data_single_free(fds);
}

static void file_util_move_single(FileDataSingle *fds)
{
	if (isfile(fds->dest) && !fds->confirmed)
		{
		ConfirmDialog *cd;
		gchar *text = g_strdup_printf(_("Overwrite file:\n%s\n with:\n%s"), fds->dest, fds->source);
		cd = confirm_dialog_new(_("Overwrite file"), text, file_util_move_single_cancel_cb, fds);
		confirm_dialog_add(cd, _("Overwrite"), file_util_move_single_ok_cb);
		g_free(text);
		return;
		}
	else
		{
		gint success = FALSE;
		if (fds->copy)
			{
			success = copy_file(fds->source, fds->dest);
			}
		else
			{
			if (move_file(fds->source, fds->dest))
				{
				success = TRUE;
				file_is_gone(fds->source, NULL);
				}
			}
		if (!success)
			{
			gchar *title;
			gchar *text;
			if (fds->copy)
				{
				title = _("Error copying file");
				text = g_strdup_printf(_("Unable to copy file:\n%s\nto:\n%s"), fds->source, fds->dest);
				}
			else
				{
				title = _("Error moving file");
				text = g_strdup_printf(_("Unable to move file:\n%s\nto:\n%s"), fds->source, fds->dest);
				}
			warning_dialog(title, text);
			g_free(text);
			}
		file_data_single_free(fds);
		}
}

/*
 * file move dialog
 */

static void file_util_move_do(FileDialog *fd)
{
	tab_completion_append_to_history(fd->entry, fd->dest_path);
	if (fd->multiple_files)
		{
		file_util_move_multiple(file_data_multiple_new(fd->source_list, fd->dest_path, fd->type));
		fd->source_list = NULL;
		}
	else
		{
		if (isdir(fd->dest_path))
			{
			gchar *buf = g_strconcat(fd->dest_path, "/", filename_from_path(fd->source_path), NULL);
			g_free(fd->dest_path);
			fd->dest_path = buf;
			}
		file_util_move_single(file_data_single_new(fd->source_path, fd->dest_path, fd->type));
		}

	generic_dialog_close(NULL, fd);
}

static void file_util_move_check(FileDialog *fd)
{
	g_free(fd->dest_path);
	fd->dest_path = remove_trailing_slash(gtk_entry_get_text(GTK_ENTRY(fd->entry)));

	if (fd->multiple_files && !isdir(fd->dest_path))
		{
		if (isfile(fd->dest_path))
			warning_dialog(_("Invalid destination"), _("When operating with multiple files, please select\n a directory, not file."));
		else
			warning_dialog(_("Invalid directory"), _("Please select an existing directory"));
		return;
		}

	file_util_move_do(fd);
}

static void file_util_move_cb(GtkWidget *widget, gpointer data)
{
	FileDialog *fd = data;
	file_util_move_check(fd);
}

static void file_util_move_enter_cb(gchar *path, gpointer data)
{
	FileDialog *fd = data;
	file_util_move_check(fd);
}

static void file_util_move_completion_sync_cb(gchar *path, gpointer data)
{
	FileDialog *fd = data;
	destination_widget_sync_to_entry(fd->entry);
}

static void real_file_util_move(gchar *source_path, GList *source_list, gchar *dest_path, gint copy)
{
	FileDialog *fd;
	gchar *path = NULL;
	gint multiple;
	gchar *text;
	gchar *title;
	gchar *op_text;
	GtkWidget *tabcomp;
	GtkWidget *dest;
	gchar *last_path;

	if (!source_path && !source_list) return;

	if (source_path)
		{
		path = g_strdup(source_path);
		multiple = FALSE;
		}
	else if (source_list->next)
		{
		multiple = TRUE;
		}
	else
		{
		path = g_strdup(source_list->data);
		free_selected_list(source_list);
		source_list = NULL;
		multiple = FALSE;
		}

	if (copy)
		{
		title = _("GQview - copy");
		op_text = _("Copy");
		if (path)
			text = g_strdup_printf(_("Copy file:\n%s\nto:"), path);
		else
			text = g_strdup_printf(_("Copy multiple files from:\n%s\nto:"), dest_path);
		}
	else
		{
		title = _("GQview - move");
		op_text = _("Move");
		if (path)
			text = g_strdup_printf(_("Move file:\n%s\nto:"), path);
		else
			text = g_strdup_printf(_("Move multiple files from:\n%s\nto:"), dest_path);
		}

	fd = generic_dialog_new(title, text, op_text, _("Cancel"),
		file_util_move_cb, generic_dialog_close);

	g_free(text);

	fd->type = copy;
	fd->source_path = path;
	fd->source_list = source_list;
	fd->multiple_files = multiple;

	tabcomp = tab_completion_new_with_history(&fd->entry, fd->dialog, dest_path,
					   "move_copy", 32, file_util_move_enter_cb, fd);
	last_path = tab_completion_set_to_last_history(fd->entry);
	if (last_path)
		{
		fd->dest_path = g_strdup(last_path);
		}
	else
		{
		fd->dest_path = g_strdup(dest_path);
		}
					   
/*	tabcomp = tab_completion_new(&fd->entry, fd->dialog, fd->dest_path, file_util_move_enter_cb, fd);
*/
	gtk_box_pack_start(GTK_BOX(fd->vbox), tabcomp, FALSE, FALSE, 0);
	gtk_widget_show(tabcomp);

	gtk_widget_grab_focus(fd->entry);

	dest = destination_widget_new(fd->dest_path, fd->entry);

	tab_completion_add_tab_func(fd->entry, file_util_move_completion_sync_cb, fd);

	gtk_box_pack_start(GTK_BOX(fd->vbox), dest, TRUE, TRUE, 0);
}

void file_util_move(gchar *source_path, GList *source_list, gchar *dest_path)
{
	real_file_util_move(source_path, source_list, dest_path, FALSE);
}

void file_util_copy(gchar *source_path, GList *source_list, gchar *dest_path)
{
	real_file_util_move(source_path, source_list, dest_path, TRUE);
}

/*
 *--------------------------------------------------------------------------
 * Delete routines
 *--------------------------------------------------------------------------
 */

/*
 * delete multiple files
 */

static void file_util_delete_multiple_ok_cb(GtkWidget *w, gpointer data)
{
	GList *source_list = data;

	while(source_list)
		{
		gchar *path = source_list->data;
		source_list = g_list_remove(source_list, path);
		if (unlink (path) < 0)
			{
			ConfirmDialog *cd;
			gchar *text;
			if (source_list)
				{
				text = g_strdup_printf(_("Unable to delete file:\n %s\n Continue multiple delete operation?"), path);
				cd = confirm_dialog_new(_("Delete failed"), text, file_util_delete_multiple_cancel_cb, source_list);
				confirm_dialog_add(cd, _("Continue"), file_util_delete_multiple_ok_cb);
				}
			else
				{
				text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
				warning_dialog(_("Delete failed"), text);
				}
			g_free(text);
			g_free(path);
			return;
			}
		else
			{
			file_is_gone(path, source_list);
			}
		g_free(path);
		}
}

static void file_util_delete_multiple_cancel_cb(GtkWidget *w, gpointer data)
{
	GList *source_list = data;
	free_selected_list(source_list);
}

static void file_util_delete_multiple(GList *source_list)
{
	if (!confirm_delete)
		{
		file_util_delete_multiple_ok_cb(NULL, source_list);
		}
	else
		{
		ConfirmDialog *cd;
		cd = confirm_dialog_new(_("Delete files"), _("About to delete multiple files..."), file_util_delete_multiple_cancel_cb, source_list);
		confirm_dialog_add(cd, _("Delete"), file_util_delete_multiple_ok_cb);
		}
}

/*
 * delete single file
 */

static void file_util_delete_ok_cb(GtkWidget *w, gpointer data)
{
	gchar *path = data;

	if (unlink (path) < 0)
		{
		gchar *text = g_strdup_printf(_("Unable to delete file:\n%s"), path);
		warning_dialog(_("File deletion failed"), text);
		g_free(text);
		}
	else
		{
		file_is_gone(path, NULL);
		}

	g_free(path);
}

static void file_util_delete_cancel_cb(GtkWidget *w, gpointer data)
{
	gchar *path = data;
	g_free(path);
}

static void file_util_delete_single(gchar *path)
{
	gchar *buf = g_strdup(path);

	if (!confirm_delete)
		{
		file_util_delete_ok_cb(NULL, buf);
		}
	else
		{
		ConfirmDialog *cd;
		gchar *text = g_strdup_printf(_("About to delete the file:\n %s"), buf);
		cd = confirm_dialog_new(_("Delete file"), text, file_util_delete_cancel_cb, buf);
		confirm_dialog_add(cd, _("Delete"), file_util_delete_ok_cb);
		g_free(text);
		}
}

void file_util_delete(gchar *source_path, GList *source_list)
{
	if (!source_path && !source_list) return;

	if (source_path)
		{
		file_util_delete_single(source_path);
		}
	else if (!source_list->next)
		{
		file_util_delete_single(source_list->data);
		free_selected_list(source_list);
		}
	else
		{
		file_util_delete_multiple(source_list);
		}
}

/*
 *--------------------------------------------------------------------------
 * Rename routines
 *--------------------------------------------------------------------------
 */

/*
 * rename multiple files
 */

static void file_util_rename_multiple_ok_cb(GtkWidget *w, gpointer data)
{
	FileDialog *fd = data;
	if (!GTK_WIDGET_VISIBLE(fd->dialog)) gtk_widget_show(fd->dialog);
	fd->type = TRUE;
	file_util_rename_multiple(fd);
}

static void file_util_rename_multiple_cancel_cb(GtkWidget *w, gpointer data)
{
	FileDialog *fd = data;
	if (!GTK_WIDGET_VISIBLE(fd->dialog)) gtk_widget_show(fd->dialog);
	return;
}

static void file_util_rename_multiple(FileDialog *fd)
{
	if (isfile(fd->dest_path) && !fd->type)
		{
		ConfirmDialog *cd;
		gchar *text = g_strdup_printf(_("Overwrite file:\n%s\nby renaming:\n%s"), fd->dest_path, fd->source_path);
		cd = confirm_dialog_new(_("Overwrite file"), text, file_util_rename_multiple_cancel_cb, fd);
		confirm_dialog_add(cd, _("Overwrite"), file_util_rename_multiple_ok_cb);
		g_free(text);
		gtk_widget_hide(fd->dialog);
		return;
		}
	else
		{
		if (rename (fd->source_path, fd->dest_path) < 0)
			{
			gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\n to:\n%s"), filename_from_path(fd->source_path), filename_from_path(fd->dest_path));
			warning_dialog(_("Error renaming file"), text);
			g_free(text);
			}
		else
			{
			gint row;
			gint n;
			GtkWidget *clist;
			gchar *path;

			file_is_renamed(fd->source_path, fd->dest_path);

			clist = gtk_object_get_user_data(GTK_OBJECT(fd->entry));
			path = gtk_object_get_user_data(GTK_OBJECT(clist));
			row = gtk_clist_find_row_from_data(GTK_CLIST(clist), path);

			n = g_list_length(GTK_CLIST(clist)->row_list);
			if (debug) printf("r=%d n=%d\n", row, n);
			if (n - 1 > row)
				n = row;
			else if (n > 1)
				n = row - 1;
			else
				n = -1;

			if (n >= 0)
				{
				gtk_object_set_user_data(GTK_OBJECT(clist), NULL);
				gtk_clist_remove(GTK_CLIST(clist), row);
				gtk_clist_select_row(GTK_CLIST(clist), n, -1);
				}
			else
				{
				if (debug) printf("closed by #%d\n", n);
				generic_dialog_close(NULL, fd);
				}
			}
		}
}

static void file_util_rename_multiple_cb(GtkWidget *w, gpointer data)
{
	FileDialog *fd = data;
	gchar *base;
	gchar *name;

	name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
	base = remove_level_from_path(fd->source_path);
	g_free(fd->dest_path);
	fd->dest_path = g_strconcat(base, "/", name, NULL);
	g_free(base);

	if (strlen(name) == 0 || strcmp(fd->source_path, fd->dest_path) == 0)
		{
		return;
		}

	fd->type = FALSE;
	file_util_rename_multiple(fd);
}

static void file_util_rename_multiple_select_cb(GtkWidget *clist,
		gint row, gint column, GdkEventButton *bevent, gpointer data)
{
	FileDialog *fd = data;
	GtkWidget *label;
	gchar *name;
	gchar *path;

	label = gtk_object_get_user_data(GTK_OBJECT(fd->dialog));
	path = gtk_clist_get_row_data(GTK_CLIST(clist), row);
	g_free(fd->source_path);
	fd->source_path = g_strdup(path);
	gtk_object_set_user_data(GTK_OBJECT(clist), path);
	name = filename_from_path(fd->source_path);

	gtk_label_set(GTK_LABEL(label), name);
	gtk_entry_set_text(GTK_ENTRY(fd->entry), name);

	gtk_widget_grab_focus(fd->entry);
}

static void file_util_rename_multiple_do(GList *source_list)
{
	FileDialog *fd;
	GtkWidget *scrolled;
	GtkWidget *clist;
	GtkWidget *label;
	GList *work;

	fd = generic_dialog_new(_("GQview - rename"), _("Rename multiple files:"), _("Rename"), _("Cancel"),
		file_util_rename_multiple_cb, generic_dialog_close);

	fd->source_path = g_strdup(source_list->data);
	fd->dest_path = NULL;

	scrolled = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
				GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_box_pack_start(GTK_BOX(fd->vbox), scrolled, TRUE, TRUE, 0);
	gtk_widget_show(scrolled);

	clist=gtk_clist_new (1);
	gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 0, TRUE);
	gtk_signal_connect (GTK_OBJECT (clist), "select_row",(GtkSignalFunc) file_util_rename_multiple_select_cb, fd);
	gtk_widget_set_usize(clist, 250, 150);
	gtk_container_add (GTK_CONTAINER (scrolled), clist);
	gtk_widget_show (clist);

	gtk_object_set_user_data(GTK_OBJECT(clist), source_list->data);

	work = source_list;
	while(work)
		{
		gint row;
		gchar *buf[2];
		buf[0] = filename_from_path(work->data);
		buf[1] = NULL;
		row = gtk_clist_append(GTK_CLIST(clist), buf);
		gtk_clist_set_row_data_full(GTK_CLIST(clist), row,
				work->data, (GtkDestroyNotify) g_free);
		work = work->next;
		}

	g_list_free(source_list);

	label = gtk_label_new(_("Rename:"));
	gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
	gtk_widget_show(label);

	label = gtk_label_new(filename_from_path(fd->source_path));
	gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
	gtk_widget_show(label);
	gtk_object_set_user_data(GTK_OBJECT(fd->dialog), label);

	label = gtk_label_new(_("to:"));
	gtk_box_pack_start(GTK_BOX(fd->vbox), label, FALSE, FALSE, 0);
	gtk_widget_show(label);

	fd->entry = gtk_entry_new();
	gtk_entry_set_text(GTK_ENTRY(fd->entry), filename_from_path(fd->source_path));
	gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
	gtk_widget_grab_focus(fd->entry);
	gtk_widget_show(fd->entry);

	gtk_object_set_user_data(GTK_OBJECT(fd->entry), clist);
}

/*
 * rename single file
 */

static void file_util_rename_single_ok_cb(GtkWidget *w, gpointer data)
{
	FileDataSingle *fds = data;
	fds->confirmed = TRUE;
	file_util_rename_single(fds);
}

static void file_util_rename_single_cancel_cb(GtkWidget *w, gpointer data)
{
	FileDataSingle *fds = data;
	file_data_single_free(fds);
}

static void file_util_rename_single(FileDataSingle *fds)
{
	if (isfile(fds->dest) && !fds->confirmed)
		{
		ConfirmDialog *cd;
		gchar *text = g_strdup_printf(_("Overwrite file:\n%s\nwith:\n%s"), fds->dest,fds->source);
		cd = confirm_dialog_new(_("Overwrite file"), text, file_util_rename_single_cancel_cb, fds);
		confirm_dialog_add(cd, _("Overwrite"), file_util_rename_single_ok_cb);
		g_free(text);
		return;
		}
	else
		{
		if (rename (fds->source, fds->dest) < 0)
			{
			gchar *text = g_strdup_printf(_("Unable to rename file:\n%s\nto:\n%s"), filename_from_path(fds->source), filename_from_path(fds->dest));
			warning_dialog(_("Error renaming file"), text);
			g_free(text);
			}
		else
			{
			file_is_renamed(fds->source, fds->dest);
			}
		}
	file_data_single_free(fds);
}

static void file_util_rename_single_cb(GtkWidget *w, gpointer data)
{
	FileDialog *fd = data;
	gchar *name = gtk_entry_get_text(GTK_ENTRY(fd->entry));
	gchar *buf = g_strconcat(fd->dest_path, "/", name, NULL);

	if (strlen(name) == 0 || strcmp(fd->source_path, buf) == 0)
		{
		g_free(buf);
		return;
		}

	g_free(fd->dest_path);
	fd->dest_path = buf;

	file_util_rename_single(file_data_single_new(fd->source_path, fd->dest_path, fd->type));

	generic_dialog_close(NULL, fd);
}

static void file_util_rename_single_do(gchar *source_path)
{
	FileDialog *fd;
	gchar *text;
	gchar *name = filename_from_path(source_path);

	text = g_strdup_printf(_("Rename file:\n%s\nto:"), name);
	fd = generic_dialog_new(_("GQview - rename"), text, _("Rename"), _("Cancel"),
		file_util_rename_single_cb, generic_dialog_close);
	g_free(text);

	fd->source_path = g_strdup(source_path);
	fd->dest_path = remove_level_from_path(source_path);

	fd->entry = gtk_entry_new();
	gtk_entry_set_text(GTK_ENTRY(fd->entry), name);
	gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
	gtk_widget_grab_focus(fd->entry);
	gtk_widget_show(fd->entry);
}

void file_util_rename(gchar *source_path, GList *source_list)
{
	if (!source_path && !source_list) return;

	if (source_path)
		{
		file_util_rename_single_do(source_path);
		}
	else if (!source_list->next)
		{
		file_util_rename_single_do(source_list->data);
		free_selected_list(source_list);
		}
	else
		{
		file_util_rename_multiple_do(source_list);
		}
}

/*
 *--------------------------------------------------------------------------
 * Create directory routines
 *--------------------------------------------------------------------------
 */

static void file_util_create_dir_do(gchar *source, gchar *path)
{
	if (isfile(path))
		{
		gchar *text = g_strdup_printf(_("The path:\n%s\nalready exists as a file."), filename_from_path(path));
		warning_dialog(_("Could not create directory"), text);
		g_free(text);
		}
	else if (isdir(path))
		{
		gchar *text = g_strdup_printf(_("The directory:\n%s\nalready exists."), filename_from_path(path));
		warning_dialog(_("Directory exists"), text);
		g_free(text);
		}
	else
		{
		if (mkdir (path, 0755) < 0)
			{
			gchar *text = g_strdup_printf(_("Unable to create directory:\n%s"), filename_from_path(path));
			warning_dialog(_("Error creating directory"), text);
			g_free(text);
			}
		else
			{
			if (strcmp(source, current_path) == 0)
				{
				gchar *buf = g_strdup(current_path);
				filelist_change_to(buf);
				g_free(buf);
				}
			}
		}
}

static void file_util_create_dir_cb(GtkWidget *w, gpointer data)
{
	FileDialog *fd = data;
	gchar *name = gtk_entry_get_text(GTK_ENTRY(fd->entry));

	if (strlen(name) == 0) return;

	g_free(fd->dest_path);
	fd->dest_path = g_strconcat(fd->source_path, "/", name, NULL);

	file_util_create_dir_do(fd->source_path, fd->dest_path);

	generic_dialog_close(NULL, fd);
}

void file_util_create_dir(gchar *path)
{
	FileDialog *fd;
	gchar *text;
	gchar *name;

	if (!isdir(path)) return;
	name = filename_from_path(path);

	text = g_strdup_printf(_("Create directory in:\n%s\nnamed:"), path);
	fd = generic_dialog_new(_("GQview - new directory"), text, _("Create"), _("Cancel"),
		file_util_create_dir_cb, generic_dialog_close);
	g_free(text);

	fd->source_path = g_strdup(path);
	fd->dest_path = NULL;

	fd->entry = gtk_entry_new();
	gtk_box_pack_start(GTK_BOX(fd->vbox), fd->entry, FALSE, FALSE, 0);
	gtk_widget_grab_focus(fd->entry);
	gtk_widget_show(fd->entry);
}