diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/utilops.c	Mon Apr 03 18:24:05 2000 +0000
@@ -0,0 +1,961 @@
+/*
+ * 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);
+}
+