#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "guiutils.h"
#include "cdialog.h"
#include "fb.h"
#include "progressdialog.h"
#include "pulist.h"

#include "edvtypes.h"
#include "edvid.h"
#include "edvobj.h"
#include "fopdlg.h"
#include "endeavour.h"
#include "edvfop.h"
#include "edvcb.h"
#include "edvop.h"
#include "edvutils.h"
#include "edvutilsgtk.h"
#include "config.h"

#include "images/icon_cancel_20x20.xpm"
#include "images/icon_browse_20x20.xpm"
#include "images/icon_move_file_20x20.xpm"
#include "images/icon_copy_file_20x20.xpm"
#include "images/icon_link2_20x20.xpm"
#include "images/icon_move_file_32x32.xpm"
#include "images/icon_copy_file_32x32.xpm"
#include "images/icon_link2_32x32.xpm"
#include "images/icon_chmod_20x20.xpm"
#include "images/icon_chmod_32x32.xpm"
#include "images/icon_owned_20x20.xpm"
#include "images/icon_owned_32x32.xpm"


static gint EDVFOPDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static void EDVFOPDlgProcessCB(GtkWidget *widget, gpointer data);
static void EDVFOPDlgCancelCB(GtkWidget *widget, gpointer data);
static void EDVFOPDlgBrowseCB(GtkWidget *widget, gpointer data);

static void EDVFOPDlgOwnerMapPUListCB(GtkWidget *widget, gpointer data);
static void EDVFOPDlgGroupMapPUListCB(GtkWidget *widget, gpointer data);

edv_fopdlg_struct *EDVFOPDlgNew(gpointer core_ptr);
void EDVFOPDlgReset(edv_fopdlg_struct *d);
void EDVFOPDlgSetBusy(edv_fopdlg_struct *d, gboolean is_busy);
gboolean EDVFOPDlgIsMapped(edv_fopdlg_struct *d);
void EDVFOPDlgMapValues(
	edv_fopdlg_struct *d,
	edv_fopdlg_op op,	/* One of EDV_FOPDLG_OP_* */
	edv_object_struct **src_obj,	/* Source list, will be coppied */
	gint src_obj_total,
	const gchar *src_dir,
	GtkWidget *toplevel
);
void EDVFOPDlgUnmap(edv_fopdlg_struct *d);
void EDVFOPDlgDelete(edv_fopdlg_struct *d);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


#define FOPDLG_USE_PERMISSION_CHECK_BUTTON	FALSE


/*
 *	"delete_event" signal callback.
 */
static gint EDVFOPDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	edv_fopdlg_struct *d = EDV_FOPDLG(data);
	if(d == NULL)
	    return(FALSE);

	EDVFOPDlgCancelCB(NULL, d);

	return(TRUE);
}

/*
 *	Opaque process callback for move, copy, link, chmod, and chown 
 *	operatios.
 */
static void EDVFOPDlgProcessCB(GtkWidget *widget, gpointer data)
{
	gint i;
	edv_fopdlg_op op;
	edv_object_struct **object, *obj;
	gint total_objects;
	gchar *tar_path;
	edv_permission_flags permissions = 0x00000000;
	gint owner_id = 0, group_id = 0;
	GtkWidget *w, *toplevel;
	edv_core_struct *core_ptr;
	edv_fopdlg_struct *d = EDV_FOPDLG(data);
	if(d == NULL)
	    return;

	core_ptr = EDV_CORE(d->core_ptr);
	if(core_ptr == NULL)
	    return;

	/* Check and warn if write protect is enabled */
	if(EDVCheckWriteProtect(core_ptr, TRUE, d->toplevel))
	    return;


	/* Get operation code */
	op = d->op;

	/* Get reference toplevel widget for transiency of dialogs that
	 * will be used during the file operation
	 */
	toplevel = d->ref_toplevel;

	/* Get source list of disk object structures */
	total_objects = d->src_obj_total;
	object = d->src_obj;

	/* Get copy of parsed and simplified target path */
	w = d->target_entry;
	tar_path = (w != NULL) ?
	    EDVCopyEvaluateInputPath(
		d->src_dir,
		gtk_entry_get_text(GTK_ENTRY(w))
	    ) : NULL;

	/* Get permissions */
	w = d->target_chmod_parent;
	if(w != NULL)
	{
	    w = d->target_uread_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_UREAD;
	    w = d->target_uwrite_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_UWRITE;
	    w = d->target_uexecute_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_UEXECUTE;

	    w = d->target_gread_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_GREAD;
	    w = d->target_gwrite_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_GWRITE;
	    w = d->target_gexecute_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_GEXECUTE;

	    w = d->target_aread_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_AREAD;
	    w = d->target_awrite_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_AWRITE;
	    w = d->target_aexecute_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_AEXECUTE;

	    w = d->target_setuid_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_SETUID;
	    w = d->target_setgid_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_SETGID;
	    w = d->target_sticky_check;
	    if((w != NULL) ? GTK_TOGGLE_BUTTON(w)->active : FALSE)
		permissions |= EDV_PERMISSION_STICKY;

	}

	/* Get owner and group */
	w = d->target_chown_parent;
	if(w != NULL)
	{
	    /* Get user id from user entry */
	    w = d->target_owner_entry;
	    if(w != NULL)
	    {
		owner_id = EDVUIDNameToUID(
		    core_ptr->uid, core_ptr->total_uids,
		    gtk_entry_get_text(GTK_ENTRY(w))
		);
	    }

	    /* Get group id from group entry */
	    w = d->target_group_entry;
	    if(w != NULL)
	    {
		group_id = EDVGIDNameToGID(
		    core_ptr->gid, core_ptr->total_gids,
		    gtk_entry_get_text(GTK_ENTRY(w))
		);
	    }
	}


	/* Unmap dialog */
	EDVFOPDlgUnmap(d);


	/* Process */
	if(TRUE)
	{
	    gboolean	yes_to_all = FALSE,
			need_emit_modified = FALSE;
	    gint status = -1;
	    const gchar *src_path;
	    gchar *new_path;
	    const gchar *error_mesg;
	    struct stat lstat_buf;
	    gint src_lstat_result;


	    /* Iterate through source objects */
	    for(i = 0; i < total_objects; i++)
	    {
		obj = object[i];
		if(obj == NULL)
		    continue;

		src_path = obj->full_path;
		if(STRISEMPTY(src_path))
		    continue;

		/* Handle by operation type */
		status = -1;
		new_path = NULL;
		error_mesg = NULL;
		switch(op)
		{
		  case EDV_FOPDLG_OP_COPY:
		    status = EDVFOPCopy(
			core_ptr, src_path, tar_path,
			&new_path, toplevel,
			TRUE, TRUE,
			&yes_to_all
		    );
		    break;

		  case EDV_FOPDLG_OP_MOVE:
		    status = EDVFOPMove(
			core_ptr, src_path, tar_path,
			&new_path, toplevel,
			TRUE, TRUE,
			&yes_to_all
		    );
		    break;

		  case EDV_FOPDLG_OP_LINK:
		    status = EDVFOPLink(
			core_ptr, src_path, tar_path,
			&new_path, toplevel,
			TRUE, TRUE,
			&yes_to_all
		    );
		    break;

		  case EDV_FOPDLG_OP_CHMOD:
		    if(TRUE)
		    {
			gfloat progress = (total_objects > 0) ?
			    ((gfloat)i / (gfloat)total_objects) : 0.0f;
			gchar *p1 = EDVCopyShortenPath(
			    src_path, EDV_DEF_PROGRESS_BAR_PATH_DISPLAY_MAX
			);
			gchar *buf = g_strdup_printf(
"Changing permissions of:\n\
\n\
    %s\n",
			    p1
			);

		        if(ProgressDialogIsQuery())
			{
			    ProgressDialogUpdate(
				NULL, buf, NULL, NULL,
				progress, EDV_DEF_PROGRESS_BAR_TICKS, TRUE
			    );
			}
			else
			{
			    ProgressDialogSetTransientFor(toplevel);
			    ProgressDialogMap(
				"Changing Permissions",
				buf,
				(const guint8 **)icon_chmod_32x32_xpm,
				"Stop"
			    );
			    ProgressDialogUpdate(
				NULL, NULL, NULL, NULL,
				progress, EDV_DEF_PROGRESS_BAR_TICKS, TRUE
			    );
			}
			g_free(buf);
			g_free(p1);
		    }
		    if(ProgressDialogStopCount() > 0)
			status = -4;
		    else
			status = EDVFOPChmod(
			    core_ptr, src_path,
			    permissions,
			    toplevel,
			    FALSE, TRUE, &yes_to_all
			);
		    need_emit_modified = TRUE;
		    break;

		  case EDV_FOPDLG_OP_CHOWN:
		    if(TRUE)
		    {
			gfloat progress = (total_objects > 0) ?
			    ((gfloat)i / (gfloat)total_objects) : 0.0f;
			gchar *p1 = EDVCopyShortenPath(
			    src_path, EDV_DEF_PROGRESS_BAR_PATH_DISPLAY_MAX
			);
			gchar *buf = g_strdup_printf(
"Chowning:\n\
\n\
    %s\n",
			    p1
			);

			if(ProgressDialogIsQuery())
			{
			    ProgressDialogUpdate(
				NULL, buf, NULL, NULL,
				progress, EDV_DEF_PROGRESS_BAR_TICKS, TRUE
			    );
			}
			else
			{
			    ProgressDialogSetTransientFor(toplevel);
			    ProgressDialogMap(
				"Chowning",
				buf,
				(const guint8 **)icon_owned_32x32_xpm,
				"Stop"
			    );
			    ProgressDialogUpdate(
				NULL, NULL, NULL, NULL,
				progress, EDV_DEF_PROGRESS_BAR_TICKS, TRUE
			    );
			}
			g_free(buf);
			g_free(p1);
		    }
		    if(ProgressDialogStopCount() > 0)
			status = -4;
		    else
			status = EDVFOPChown(
			    core_ptr, src_path,
			    owner_id, group_id,
			    toplevel,
			    FALSE, TRUE, &yes_to_all
			);
		    need_emit_modified = TRUE;
		    break;

		  default:
		    error_mesg = "Unsupported operation";
 		    break;
		}

		/* Get error message (if any) describing the error that
		 * might have occured in the above operation
		 */   
		if(error_mesg == NULL)
		    error_mesg = EDVFOPGetError();
		if(!STRISEMPTY(error_mesg) && (status != -4))
		{
		    EDVPlaySoundError(core_ptr);
		    EDVMessageError(
			"Operation Error",
			error_mesg,
			NULL,
			toplevel
		    );
		}

		/* Check if new_path is valid and that no error
		 * occured
		 *
		 * This implies the operation was successful
		 * and that we need to emit an object added signal 
		 */
		if((!STRISEMPTY(new_path) && !status) ?
		    !lstat(new_path, &lstat_buf) : FALSE
		)
		    EDVObjectAddedEmit(
			core_ptr, new_path, &lstat_buf
		    );

		/* Get local stats for the source object (possibly
		 * overwriting lstat_buf of any data obtained from the
		 * local stats of new_path above)
		 */
		src_lstat_result = lstat(src_path, &lstat_buf);

		/* Need to emit an object modified signal? (For cases of
		 * chmod or chown operations?
		 */
		if(need_emit_modified && !status)
		{
		    if(!src_lstat_result)
			EDVObjectModifiedEmit(
			    core_ptr, src_path, src_path,
			    &lstat_buf
			);
		}

		/* Check if the object no longer exists locally, if it
		 * no longer exists then emit an object removed signal to
		 * all of endeavour's resources
		 *
		 * Note that this will work out if the operation was a
		 * copy, link, chmod, or chown since it dosen't emit an
		 * object removed signal if the object still exists
		 */
		if(src_lstat_result)
		    EDVObjectRemovedEmit(core_ptr, src_path);


		/* Delete new object path */
		g_free(new_path);
		new_path = NULL;

		/* Skip handling of the rest of the objects on error
		 * (status != 0) and that the error was not a user
		 * response of no (status != -5)
		 */
		if(status && (status != -5))
		    break;
	    }

	    /* Unmap progress dialog, it may have been mapped if any
	     * operations occured in the above loop
	     */
	    ProgressDialogBreakQuery(TRUE);
	    ProgressDialogSetTransientFor(NULL);

	    /* Play completed sound on success */
	    if(status == 0)
		EDVPlaySoundCompleted(core_ptr);
	}

	/* Delete copy of target path */
	g_free(tar_path);
	tar_path = NULL;

	/* From this point on these variables are invalid, and they
	 * will be deallocated when EDVFOPDlgReset() is called
	 * further below
	 */
	total_objects = 0;
	object = NULL;

	/* Deallocate source disk objects structure list and current
	 * source directory on the dialog
	 */
	EDVFOPDlgReset(d);
}

/*
 *      Cancel callback.
 */
static void EDVFOPDlgCancelCB(GtkWidget *widget, gpointer data)
{
	edv_fopdlg_struct *d = EDV_FOPDLG(data);
	if(d == NULL)
	    return;

	/* Unmap dialog */
	EDVFOPDlgUnmap(d);

	/* Deallocate source disk objects structure list and current
	 * source directory on the dialog
	 */
	EDVFOPDlgReset(d);
}

/*
 *	Browse callback.
 */
static void EDVFOPDlgBrowseCB(GtkWidget *widget, gpointer data)
{
	gboolean status;
	GtkWidget *toplevel;
	fb_type_struct **ftype = NULL, *ftype_rtn = NULL;
	gint total_ftypes = 0;
	gchar **path_rtn = NULL;
	gint total_path_rtns = 0;
	GtkEntry *entry = (GtkEntry *)data;
	if((entry == NULL) || FileBrowserIsQuery())
	    return;

	toplevel = gtk_widget_get_toplevel(GTK_WIDGET(entry));

	/* Create file types list */
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    "*.*", "All files"
	);

	/* Query user for target object */
	FileBrowserSetTransientFor(toplevel);
	status = FileBrowserGetResponse(
	    "Select Target Object",
	    "Select", "Cancel",
	    gtk_entry_get_text(entry),          /* Startup path */
	    ftype, total_ftypes,
	    &path_rtn, &total_path_rtns,
	    &ftype_rtn
	);
	FileBrowserSetTransientFor(NULL);

	/* Got user response? */
	if(status)
	{
	    const gchar *new_path = (total_path_rtns > 0) ?
		path_rtn[0] : NULL;
	    if(!STRISEMPTY(new_path))
	    {
		gtk_entry_set_text(entry, new_path);
		gtk_entry_set_position(entry, -1);
	    }
	}

	/* Delete file types list */
	FileBrowserDeleteTypeList(ftype, total_ftypes);

	/* Reset due to possible file related change */
	FileBrowserReset();
}


/*
 *      Maps the popup list for the owner entry.
 */
static void EDVFOPDlgOwnerMapPUListCB(GtkWidget *widget, gpointer data)
{
	const gchar *value;
	GtkEntry *entry;
	pulist_struct *pulist;
	edv_core_struct *core_ptr;
	edv_fopdlg_struct *d = EDV_FOPDLG(data);
	if(d == NULL)
	    return;

	entry = (GtkEntry *)d->target_owner_entry;
	core_ptr = EDV_CORE(d->core_ptr);
	if((entry == NULL) || (core_ptr == NULL))
	    return;

	pulist = core_ptr->users_pulist;
	if(PUListIsQuery(pulist))
	    return;

	/* Block input and get value */
	value = PUListMapQuery(
	    pulist,			/* Popup List */
	    gtk_entry_get_text(entry),	/* Initial Value */
	    15,				/* Lines Visible */
	    PULIST_RELATIVE_CENTER,	/* Relativity */
	    GTK_WIDGET(entry),		/* Relative Widget */
	    widget			/* Map Trigger Widget */
	);
	/* Got value? */
	if(value != NULL)
	    gtk_entry_set_text(entry, value);
}

/*
 *      Maps the popup list for the group entry.
 */
static void EDVFOPDlgGroupMapPUListCB(GtkWidget *widget, gpointer data)
{
	const gchar *value;
	GtkEntry *entry;
	pulist_struct *pulist;
	edv_core_struct *core_ptr;
	edv_fopdlg_struct *d = EDV_FOPDLG(data);
	if(d == NULL)
	    return;

	entry = (GtkEntry *)d->target_group_entry;
	core_ptr = EDV_CORE(d->core_ptr);
	if((entry == NULL) || (core_ptr == NULL))
	    return;

	pulist = core_ptr->groups_pulist;
	if(PUListIsQuery(pulist))
	    return;

	/* Block input and get value */
	value = PUListMapQuery(
	    pulist,			/* Popup List */
	    gtk_entry_get_text(entry),	/* Initial Value */
	    15,				/* Lines Visible */
	    PULIST_RELATIVE_CENTER,	/* Popup Relativity */
	    GTK_WIDGET(entry),		/* Relative Widget */
	    widget			/* Map Trigger Widget */
	);
	/* Got value? */
	if(value != NULL)
	    gtk_entry_set_text(entry, value);
}


/*
 *	Creates a new edv_fopdlg_struct.
 */
edv_fopdlg_struct *EDVFOPDlgNew(gpointer core_ptr)
{
	const gint	border_major = 5,
			border_minor = 2;
	GdkWindow *window;
	GtkAccelGroup *accelgrp;
	GtkStyle *style;
	GtkWidget	*w, *parent, *parent2, *parent3, *parent4,
			*parent5, *parent6, *parent7;
	edv_fopdlg_struct *d = EDV_FOPDLG(
	    g_malloc0(sizeof(edv_fopdlg_struct))
	);
	if(d == NULL)
	    return(NULL);

	d->accelgrp = accelgrp = gtk_accel_group_new();
	d->processing = FALSE;
	d->busy_count = 0;
	d->freeze_count = 0;
	d->core_ptr = core_ptr;

	d->ref_toplevel = NULL;
	d->op = EDV_FOPDLG_OP_MOVE;
	d->src_obj = NULL;
	d->src_obj_total = 0;
	d->src_dir = NULL;


	/* Begin creating widgets */

	/* Toplevel */
	d->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
	gtk_widget_realize(w);
	window = w->window;
	if(window != NULL)
	{
	    gdk_window_set_decorations(
		window,
		GDK_DECOR_BORDER | GDK_DECOR_TITLE | GDK_DECOR_MENU |
		GDK_DECOR_MINIMIZE
	    );
	    gdk_window_set_functions(
		window,
		GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
	    );
	}
	gtk_signal_connect(
	    GTK_OBJECT(w), "delete_event",
	    GTK_SIGNAL_FUNC(EDVFOPDlgDeleteEventCB), d
	);
	gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
	style = gtk_widget_get_style(w);
	parent = w;


	/* Main vbox */
	d->main_vbox = w = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(parent), w);
	gtk_widget_show(w);
	parent = w;


	/* Hbox to hold icon and message label */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, border_major);
	gtk_widget_show(w);
	parent2 = w;


	/* Vbox to hold icon fixed */
	w = gtk_vbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, border_major);
	gtk_widget_show(w);
	parent3 = w;

	d->icon_fixed = w = gtk_fixed_new();
	d->icon_pm = NULL;
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
	gtk_widget_realize(w);
	gtk_widget_show(w);


	/* Vbox for label and entry */
	w = gtk_vbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, border_major);
	gtk_widget_show(w);
	parent3 = w;

	/* Label hbox */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Label */
	d->label = w = gtk_label_new("Are you sure?");
	gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Hbox for target widgets */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Label alignment */
	w = gtk_alignment_new(1.0, 0.0, 0.0, 0.0);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Label */
	w = gtk_label_new("To:");
	gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	gtk_container_add(GTK_CONTAINER(parent5), w);
	gtk_widget_show(w);


	/* Target path entry */
	d->target_entry = w = gtk_entry_new();
	gtk_widget_set_usize(w, 350, -1);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, TRUE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "activate",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	EDVEntrySetDND(EDV_CORE(core_ptr), w);
	EDVEntrySetCompletePath(EDV_CORE(core_ptr), w);


	/* Browse button */
	d->target_browse_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_browse_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgBrowseCB), d->target_entry
	);

	/* Vbox for target chmod labels and check buttons */
	d->target_chmod_parent = w = gtk_vbox_new(FALSE, border_minor);
	gtk_widget_set_usize(w, 300, -1);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	parent5 = w;

	/* Labels hbox */
	w = gtk_hbox_new(TRUE, border_major);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent6 = w;
	w = gtk_label_new("Owner");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	w = gtk_label_new("Group");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	w = gtk_label_new("Other");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);

	/* Check buttons hbox */
	w = gtk_hbox_new(TRUE, border_major);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent6 = w;

#define NEW_PERMISSION_TOGGLE_BUTTON(_label_,_tip_,_active_,_parent_)   {\
 if(FOPDLG_USE_PERMISSION_CHECK_BUTTON) {			\
  /* Create permission button as a GtkCheckButton */		\
  w = gtk_check_button_new_with_label(_label_);			\
 } else {							\
  /* Create permission button as a GtkToggleButton */		\
  GdkFont *font = style->font;					\
  const gint font_height = (font != NULL) ?			\
   (font->ascent + font->descent) : 0;				\
  w = gtk_toggle_button_new_with_label(_label_);		\
  if(font_height > 0)						\
   gtk_widget_set_usize(					\
    w, MIN(font_height + 5, 20), MIN(font_height + 5, 20)	\
   );								\
 }								\
 GTK_TOGGLE_BUTTON(w)->active = (_active_) ? TRUE : FALSE;	\
 gtk_box_pack_start(GTK_BOX(_parent_), w, FALSE, FALSE, 0);	\
 GUISetWidgetTip(w, (_tip_));					\
 gtk_widget_show(w);						\
}

	/* Owner check button set hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent7 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    FALSE,
	    parent7
	)
	d->target_uread_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    FALSE,
	    parent7
	)
	d->target_uwrite_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    FALSE,
	    parent7
	)
	d->target_uexecute_check = w;

	/* Group check button set hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent7 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    FALSE,
	    parent7 
	)
	d->target_gread_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    FALSE,
	    parent7
	)
	d->target_gwrite_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    FALSE,  
	    parent7
	)
	d->target_gexecute_check = w;

	/* Other check button set hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent7 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    FALSE,
	    parent7
	)
	d->target_aread_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    FALSE,
	    parent7
	)
	d->target_awrite_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    FALSE,  
	    parent7
	)
	d->target_aexecute_check = w;

#undef NEW_PERMISSION_TOGGLE_BUTTON

	/* Hbox for setuid, setgid, and sticky permission check buttons */
	w = gtk_hbox_new(TRUE, border_major);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent6 = w;

	/* Setuid check button */
	d->target_setuid_check = w = gtk_check_button_new_with_label("SetUID");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	GUISetWidgetTip(w, "Set owner's permission on use");
	gtk_widget_show(w);

	/* Setgid check button */
	d->target_setgid_check = w = gtk_check_button_new_with_label("SetGID");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	GUISetWidgetTip(w, "Set group's permissions on use");
	gtk_widget_show(w);

	/* Sticky check button */
	d->target_sticky_check = w = gtk_check_button_new_with_label("Sticky");
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, FALSE, 0);
	GUISetWidgetTip(w, "Set user's permissions on use");
	gtk_widget_show(w);


	/* Vbox for target owned label, entry, and buttons */
	d->target_chown_parent = w = gtk_vbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	parent5 = w;

	/* Owner entry hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent6 = w;
	/* Prefix label */
	w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);
	gtk_widget_set_usize(w, 60, -1);
	gtk_box_pack_start(GTK_BOX(parent6), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent7 = w;
	w = gtk_label_new("Owner:");
	gtk_container_add(GTK_CONTAINER(parent7), w);
	gtk_widget_show(w);
	/* Owner entry */
 	d->target_owner_entry = w = gtk_entry_new();
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(w, 250, -1);
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, TRUE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "activate",
            GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
        );
	gtk_widget_show(w);
	/* Popup list map button */
	d->target_owner_btn = w = PUListNewMapButton(
	    EDVFOPDlgOwnerMapPUListCB, d
	);
	gtk_box_pack_start(GTK_BOX(parent6), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Group entry hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent6 = w;
	/* Prefix label */
	w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);
	gtk_widget_set_usize(w, 60, -1);
	gtk_box_pack_start(GTK_BOX(parent6), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent7 = w;
	w = gtk_label_new("Group:");
	gtk_container_add(GTK_CONTAINER(parent7), w);
	gtk_widget_show(w);
	/* Group entry */
	d->target_group_entry = w = gtk_entry_new();
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(w, 250, -1);
	gtk_box_pack_start(GTK_BOX(parent6), w, TRUE, TRUE, 0);
        gtk_signal_connect(                                    
            GTK_OBJECT(w), "activate",
            GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
        );
	gtk_widget_show(w);
	/* Popup list map button */
	d->target_group_btn = w = PUListNewMapButton(
	    EDVFOPDlgGroupMapPUListCB, d
	);
	gtk_box_pack_start(GTK_BOX(parent6), w, FALSE, FALSE, 0);
	gtk_widget_show(w);





	/* Separator */
	w = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Buttons hbox */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Move button */
	d->move_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_move_file_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Mueva"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Mouvement"
#elif defined(PROG_LANGUAGE_GERMAN)
"Bewegung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Movimento"
#elif defined(PROG_LANGUAGE_DUTCH)
"Beweging"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mova"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Trekk"
#else
"Move"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_m, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_m);

	/* Copy button */
	d->copy_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_copy_file_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"La Copia"
#elif defined(PROG_LANGUAGE_FRENCH)
"Copie"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kopie"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Copia"
#elif defined(PROG_LANGUAGE_DUTCH)
"Kopie"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Cópia"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kopi"
#else
"Copy"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_o);

	/* Link button */
	d->link_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_link2_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"El Eslabón"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Lien"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kettenglied"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Maglia"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schakel"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Elo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ledd"
#else
"Link"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_l, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"         
	);
	GUIButtonLabelUnderline(w, GDK_l);

	/* ChMod button */
	d->chmod_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_chmod_20x20_xpm, "ChMod", NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_h, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_h);

	/* Chown button */
	d->chown_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_owned_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Propio"
#elif defined(PROG_LANGUAGE_FRENCH)
"Propre"
#elif defined(PROG_LANGUAGE_GERMAN)
"Eigen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Proprio"
#elif defined(PROG_LANGUAGE_DUTCH)
"Eigen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Próprio"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Egen"
#else
"Chown"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgProcessCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_h, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_h);

	/* Cancel button */
	d->cancel_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Cancela"
#elif defined(PROG_LANGUAGE_FRENCH)
"Annuler"
#elif defined(PROG_LANGUAGE_GERMAN)
"Heben"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Annulla"
#elif defined(PROG_LANGUAGE_DUTCH)
"Annuleer"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Cancelamento"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kanseller"
#else
"Cancel"
#endif
	    , NULL
	);
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH_DEF, GUI_BUTTON_HLABEL_HEIGHT_DEF
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVFOPDlgCancelCB), d
	);
	gtk_accel_group_add(
	    accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	gtk_accel_group_add(
	    accelgrp, GDK_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"         
	);
	GUIButtonLabelUnderline(w, GDK_c);
	gtk_widget_show(w);



	return(d);
}


/*
 *	Deallocates source disk object structure list and current
 *	source directory on the given dialog.
 */
void EDVFOPDlgReset(edv_fopdlg_struct *d)
{
	gint i;

	if(d == NULL)
	    return;

	for(i = 0; i < d->src_obj_total; i++)
	    EDVObjectDelete(d->src_obj[i]);
	g_free(d->src_obj);
	d->src_obj = NULL;
	d->src_obj_total = 0;

	g_free(d->src_dir);
	d->src_dir = NULL;
}

/*
 *	Sets the File Operation Dialog as busy or ready.
 */
void EDVFOPDlgSetBusy(edv_fopdlg_struct *d, gboolean is_busy)
{
	GdkCursor *cursor;
	GtkWidget *w;
	edv_core_struct *core_ptr;

	if(d == NULL)
	    return;

	core_ptr = EDV_CORE(d->core_ptr);
	if(core_ptr == NULL)
	    return;

	w = d->toplevel;
	if(w != NULL)
	{
	    if(is_busy)
	    {
		/* Increase busy count */
		d->busy_count++;

		/* If already busy then don't change anything */
		if(d->busy_count > 1)
		    return;

		cursor = EDVGetCursor(core_ptr, EDV_CURSOR_CODE_BUSY);
	    }
	    else
	    {
		/* Reduce busy count */
		d->busy_count--;
		if(d->busy_count < 0)
		    d->busy_count = 0;

		/* If still busy do not change anything */
		if(d->busy_count > 0)
		    return;

		cursor = NULL;  /* Use default cursor */
	    }

	    /* Update toplevel window's cursor */
	    if(w->window != NULL)
	    {
		gdk_window_set_cursor(w->window, cursor);
		gdk_flush();
	    }
	}
}

/*
 *	Checks if the File Operation Dialog is mapped.
 */
gboolean EDVFOPDlgIsMapped(edv_fopdlg_struct *d)
{
	GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
	return((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE);
}

/*
 *	Maps the File Operation Dialog with the specified values.
 *
 *	The given list of src_obj must contain atleast one object, this
 *	list will not be modified by this function.
 */
void EDVFOPDlgMapValues(
	edv_fopdlg_struct *d,
	edv_fopdlg_op op,	/* One of EDV_FOPDLG_OP_* */
	edv_object_struct **src_obj,	/* Source list, will be coppied */
	gint src_obj_total,
	const gchar *src_dir,
	GtkWidget *toplevel
)
{
	gint i;
	gboolean need_warn_chmod_link = FALSE;
	const gchar *title = NULL;
	gchar *buf = NULL;
	const gchar *src_obj_full_path, *src_obj_name;
	guint8 **icon_data = NULL;
	const gchar *icon_name = NULL;
	edv_object_struct *obj;
	edv_core_struct *core_ptr;
	gboolean map_browse_btn = FALSE;
	GtkWidget *w, *parent, *button = NULL, *target_w = NULL;

	if(d == NULL)
	    return;

	core_ptr = EDV_CORE(d->core_ptr);
	if(core_ptr == NULL)
	    return;

	/* Delete the Dialog's source objects list and current
	 * source directory
	 */
	EDVFOPDlgReset(d);

	/* If there is exactly one object in the source object list
	 * then get its full path and name
	 *
	 * Otherwise set the single object full path and name to NULL
	 */
	if(src_obj_total == 1)
	{
	    obj = src_obj[0];
	    src_obj_name = (obj != NULL) ? obj->name : NULL;
	    src_obj_full_path = (obj != NULL) ? obj->full_path : NULL;
	}
	else
	{
	    obj = NULL;
	    src_obj_name = NULL;
	    src_obj_full_path = NULL;
	}


	/* Set operation code */
	d->op = op;

	/* Update widgets based on operation code */
	switch(op)
	{
	  case EDV_FOPDLG_OP_MOVE:
	    title =
#if defined(PROG_LANGUAGE_SPANISH)
"Mueva"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Mouvement"
#elif defined(PROG_LANGUAGE_GERMAN)
"Bewegung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Movimento"
#elif defined(PROG_LANGUAGE_DUTCH)
"Beweging"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mova"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Trekk"
#else
"Move"
#endif
	    ;
	    icon_data = (guint8 **)icon_move_file_32x32_xpm;
	    icon_name = "icon_move_file_32x32_xpm";
	    if(src_obj_name != NULL)
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Mueva:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Mouvement:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Bewegung:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Movimento:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Beweging:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mova:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Trekk:\n\
\n\
    %s\n"
#else
"Move:\n\
\n\
    %s\n"
#endif
		    , src_obj_name
		);
	    else
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Mueva %i objetos\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Déplacer %i objets\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Bewegen sie %i objekte\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Muovere %i oggetti\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Beweeg %i voorwerpen\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mova %i objetos\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Flytt %i objekt\n"
#else
"Move %i objects\n"
#endif
		    , src_obj_total
		);
	    button = d->move_btn;
	    target_w = d->target_entry;
	    map_browse_btn = TRUE;
	    break;

	  case EDV_FOPDLG_OP_COPY:
	    title =
#if defined(PROG_LANGUAGE_SPANISH)
"La Copia"
#elif defined(PROG_LANGUAGE_FRENCH)
"Copie"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kopie"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Copia"
#elif defined(PROG_LANGUAGE_DUTCH)
"Kopie"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Cópia"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kopi"
#else
"Copy"
#endif
	    ;
	    icon_data = (guint8 **)icon_copy_file_32x32_xpm;
	    icon_name = "icon_copy_file_32x32_xpm";
	    if(src_obj_name != NULL)
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"La Copia:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Copie:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kopie:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Copia:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Kopie:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Cópia:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kopi:\n\
\n\
    %s\n"
#else
"Copy:\n\
\n\
    %s\n"
#endif
		    , src_obj_name
		);
	    else
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Copie %i objetos\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"La copie %i objets\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kopieren sie %i objekte\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Copiare %i oggetti\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Kopieer %i voorwerpen\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Copie %i objetos\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Kopier %i objekt\n"
#else
"Copy %i objects\n"
#endif
		    , src_obj_total
		);
	    button = d->copy_btn;
	    target_w = d->target_entry;
	    map_browse_btn = TRUE;
	    break;

	  case EDV_FOPDLG_OP_LINK:
	    title =
#if defined(PROG_LANGUAGE_SPANISH)
"El Eslabón"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Lien"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kettenglied"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Maglia"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schakel"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Elo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ledd"
#else
"Link"
#endif
	    ;
	    icon_data = (guint8 **)icon_link2_32x32_xpm;
	    icon_name = "icon_link2_32x32_xpm";
	    if(src_obj_name != NULL)
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"El Eslabón:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le Lien:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Kettenglied:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Maglia:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schakel:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Elo:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Ledd:\n\
\n\
    %s\n"
#else
"Link:\n\
\n\
    %s\n"
#endif
		    , src_obj_name
		);
	    else
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Trabe %i objetos\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le lien %i objets\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Verknüpfen sie %i objekte\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Concatenare %i oggetti\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verbind %i voorwerpen\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Ligue %i objetos\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forbind %i objekt\n"
#else
"Link %i objects\n"
#endif
		    , src_obj_total
		);
	    button = d->link_btn;
	    target_w = d->target_entry;
	    map_browse_btn = TRUE;
	    break;

	  case EDV_FOPDLG_OP_CHMOD:
	    title =
#if defined(PROG_LANGUAGE_SPANISH)
"Cambie Los Permisos"
#elif defined(PROG_LANGUAGE_FRENCH)
"Changer Des Permissions"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ändern Sie Erlaubnis"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cambiare I Permessi"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verandeer Toestemmingen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mude Permissões"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forandr Permissions"
#else
"Change Permissions"
#endif
	    ;
	    icon_data = (guint8 **)icon_chmod_32x32_xpm;
	    icon_name = "icon_chmod_32x32_xpm";
	    if(src_obj_name != NULL)
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Cambie los permisos de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Changer des permissions de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ändern sie erlaubnis von:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cambiare i permessi di:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verandeer toestemmingen van:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mude permissões de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forandr tillatelse av:\n\
\n\
    %s\n"
#else
"Change permissions of:\n\
\n\
    %s\n"
#endif
		    , src_obj_name
		);
	    else
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Cambie los permisos de %i objetos\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Changer des permissions de %i objets\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ändern sie erlaubnis von %i objekten\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cambiare i permessi di %i oggetti\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verandeer toestemmingen van %i voorwerpen\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mude permissões de %i objetos\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forandr tillatelse av %i objekt\n"
#else
"Change permissions of %i objects\n"
#endif
		    , src_obj_total
		);
	    button = d->chmod_btn;
	    target_w = d->target_chmod_parent;
	    break;

	  case EDV_FOPDLG_OP_CHOWN:
	    title =
#if defined(PROG_LANGUAGE_SPANISH)
"Propio"
#elif defined(PROG_LANGUAGE_FRENCH)
"Propre"
#elif defined(PROG_LANGUAGE_GERMAN)
"Eigen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Proprio"
#elif defined(PROG_LANGUAGE_DUTCH)
"Eigen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Próprio"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Egen"
#else
"Chown"
#endif
	    ;
	    icon_data = (guint8 **)icon_owned_32x32_xpm;
	    icon_name = "icon_owned_32x32_xpm";
	    if(src_obj_name != NULL)
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Cambie la propiedad de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Changer la possession de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ändern sie eigentumsrecht von:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cambiare la proprietà di:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verandeer eigendomsrecht van:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mude posse de:\n\
\n\
    %s\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forandr eiendomsrett av:\n\
\n\
    %s\n"
#else
"Chown:\n\
\n\
    %s\n"
#endif
		    , src_obj_name
		);
	    else
		buf = g_strdup_printf(
#if defined(PROG_LANGUAGE_SPANISH)
"Cambie la propiedad de %i objetos\n"
#elif defined(PROG_LANGUAGE_FRENCH)
"Changer la possession de %i objetos\n"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ändern sie eigentumsrecht von %i objetos\n"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cambiare la proprietà di %i objetos\n"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verandeer eigendomsrecht van %i objetos\n"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Mude posse de %i objetos\n"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Forandr eiendomsrett av %i objetos\n"
#else
"Chown %i objects\n"
#endif
		    , src_obj_total
		);
	    button = d->chown_btn;
	    target_w = d->target_chown_parent;
	    break;

	}

	/* Update icon */
	parent = d->icon_fixed;
	if((icon_data != NULL) && (parent != NULL))
	{
	    GdkBitmap *mask;
	    GdkPixmap *pixmap;

	    /* Create new pixmap from icon_data */
	    EDVLoadPixmap(
		core_ptr,
		icon_data, icon_name,
		&pixmap, &mask
	    );
	    if(pixmap != NULL)
	    {
		gint width, height;

		/* Get size of new pixmap and mask pair */
		gdk_window_get_size(pixmap, &width, &height);

		/* Get icon GtkPixmap, create it as needed */
		w = d->icon_pm;
		if(w == NULL)
		{
		    d->icon_pm = w = gtk_pixmap_new(pixmap, mask);
		    gtk_fixed_put(GTK_FIXED(parent), w, 0, 0);
		    gtk_widget_show(w);
		}
		else
		{
		    gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
		}

		/* Adjust size of fixed widget to fit pixmap */
		gtk_widget_set_usize(parent, width, height);
		gtk_widget_queue_resize(parent);
		gtk_widget_shape_combine_mask(parent, mask, 0, 0);

		GDK_PIXMAP_UNREF(pixmap)
		GDK_BITMAP_UNREF(mask)
	    }

	    /* Update toplevel GdkWindow's WM icon */
	    w = d->toplevel;
	    if(w != NULL)
		GUISetWMIcon(w->window, (guint8 **)icon_data);
	}

	/* Update label */
	if(buf != NULL)
	{
	    w = d->label;
	    if(w != NULL)
		gtk_label_set_text(GTK_LABEL(w), buf);

	    /* Delete message, it is no longer needed */
	    g_free(buf);
	    buf = NULL;
	}


	/* Update source directory */
	g_free(d->src_dir);
	d->src_dir = STRDUP(src_dir);

	/* Update target entry */
	w = d->target_entry;
	if((w != NULL) && (w == target_w))
	{
	    if(GTK_IS_ENTRY(w))
		gtk_entry_set_text(
		    GTK_ENTRY(w), (src_dir != NULL) ? src_dir : ""
		);
	    if(GTK_WIDGET_CAN_FOCUS(w))
		gtk_widget_grab_focus(w);
	    if(GTK_WIDGET_CAN_DEFAULT(w))
		gtk_widget_grab_default(w);
	}


	/* Copy the specified objects list to the Dialog's objects
	 * list
	 */
	d->src_obj_total = src_obj_total;
	if(d->src_obj_total > 0)
	{
	    d->src_obj = (edv_object_struct **)g_malloc(
		d->src_obj_total * sizeof(edv_object_struct *)
	    );
	    if(d->src_obj != NULL)
	    {
		for(i = 0; i < d->src_obj_total; i++)
		    d->src_obj[i] = EDVObjectCopy(src_obj[i]);
	    }
	    else
	    {
		d->src_obj_total = 0;
	    }
	}
	else
	{
	    d->src_obj_total = 0;
	}


	/* Update permissions? */
	w = d->target_chmod_parent;
	if((w != NULL) && (w == target_w))
	{
	    /* Connect permissions from the list of objects coppied to our
	     * dialog structure. Gather accumulative permissions mask to
	     * contain all permissions that the objects posess
	     */
	    edv_permission_flags permissions = 0x00000000;
	    edv_object_struct *obj_ptr;

	    /* Iterate through objects */
	    for(i = 0; i < d->src_obj_total; i++)
	    {
		obj_ptr = d->src_obj[i];
		if(obj_ptr == NULL)
		    continue;

		/* Do a quick check to see if the object to change
		 * permissions of is a symbolic link
		 *
		 * If this is a symbolic link then a warning needs to
		 * be issued about changing a symbolic link's
		 * permissions that will actually change its
		 * destination permissions
		 */
		if(obj_ptr->type == EDV_OBJECT_TYPE_LINK)
		    need_warn_chmod_link = TRUE;

		/* Gather permissions from this object */
		permissions |= obj_ptr->permissions;
	    }

	    /* Begin setting permission check widgets */
#define SET_ACTIVE(_w_,_b_)	{		\
 if((_w_) != NULL)				\
  gtk_toggle_button_set_active(			\
   GTK_TOGGLE_BUTTON(_w_), (_b_) ? TRUE : FALSE	\
  );						\
}
	    SET_ACTIVE(
		d->target_uread_check,
		permissions & EDV_PERMISSION_UREAD
	    )
	    if(GTK_WIDGET_CAN_FOCUS(d->target_uread_check))
		gtk_widget_grab_focus(d->target_uread_check);
	    if(GTK_WIDGET_CAN_DEFAULT(d->target_uread_check))
		gtk_widget_grab_default(d->target_uread_check);
	    SET_ACTIVE(
		d->target_uwrite_check,
		permissions & EDV_PERMISSION_UWRITE
	    )
	    SET_ACTIVE(
		d->target_uexecute_check,
		permissions & EDV_PERMISSION_UEXECUTE
	    )

	    SET_ACTIVE(
		d->target_gread_check,
		permissions & EDV_PERMISSION_GREAD
	    )
	    SET_ACTIVE(
		d->target_gwrite_check,
		permissions & EDV_PERMISSION_GWRITE
	    )
	    SET_ACTIVE(
		d->target_gexecute_check,
		permissions & EDV_PERMISSION_GEXECUTE
	    )

	    SET_ACTIVE(
		d->target_aread_check,
		permissions & EDV_PERMISSION_AREAD
	    )
	    SET_ACTIVE(
		d->target_awrite_check,
		permissions & EDV_PERMISSION_AWRITE
	    )
	    SET_ACTIVE(
		d->target_aexecute_check,
		permissions & EDV_PERMISSION_AEXECUTE
	    )

	    SET_ACTIVE(
		d->target_setuid_check,
		permissions & EDV_PERMISSION_SETUID
	    )
	    SET_ACTIVE(
		d->target_setgid_check,
		permissions & EDV_PERMISSION_SETGID
	    )
	    SET_ACTIVE(
		d->target_sticky_check,
		permissions & EDV_PERMISSION_STICKY
	    )
#undef SET_ACTIVE
	}

	/* Update owner and group? */
	w = d->target_chown_parent;
	if((w != NULL) && (w == target_w))
	{
	    w = d->target_owner_entry;
	    if(w != NULL)
	    {
		gtk_entry_set_text(
		    GTK_ENTRY(w),
		    EDVUIDGetNameFromUID(
			core_ptr->uid, core_ptr->total_uids,
			(obj != NULL) ?
			    obj->owner_id : core_ptr->effective_user_id,
			NULL
		    )
		);
		if(GTK_WIDGET_CAN_FOCUS(w))
		    gtk_widget_grab_focus(w);
		if(GTK_WIDGET_CAN_DEFAULT(w))
		    gtk_widget_grab_default(w);
	    }

	    w = d->target_group_entry;
	    if(w != NULL)
	    {
		gtk_entry_set_text(
		    GTK_ENTRY(w),
		    EDVGIDGetNameFromGID(
			core_ptr->gid, core_ptr->total_gids,
			(obj != NULL) ?
			    obj->group_id : core_ptr->effective_group_id,
			NULL
		    )
		);
	    }
	}


	/* Unmap all buttons */
	w = d->move_btn;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->copy_btn;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->link_btn;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->chmod_btn;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->chown_btn;
	if(w != NULL)
	    gtk_widget_hide(w);

	/* Check if button to be mapped is valid and map it */
	if(button != NULL)
	    gtk_widget_show(button);


	/* Unmap all target widgets */
	w = d->target_entry;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->target_chmod_parent;
	if(w != NULL)
	    gtk_widget_hide(w);
	w = d->target_chown_parent;
	if(w != NULL)
	    gtk_widget_hide(w);

	/* Check if target widget to be mapped is valid and map it */
	if(target_w != NULL)
	    gtk_widget_show(target_w);

	/* Map/unmap browse button */
	w = d->target_browse_btn;
	if(w != NULL)
	{
	    if(map_browse_btn)
		gtk_widget_show(w);
	    else
		gtk_widget_hide(w);
	}

	/* Need to print warning about changing permissions on link
	 * objects?
	 */
	if(need_warn_chmod_link)
	{
	    EDVPlaySoundWarning(core_ptr);
	    EDVMessageWarning(
"Changing Permissions Warning",
"Changing the permissions on a symbolic link object\n\
will effectively change the permissions of its destination\n\
object.",
"One or more of the selected object(s) are of type\n\
symbolic link. Symbolic links do not have permissions,\n\
instead their permissions are determined by the permissions\n\
of the destination object. So changing the permissions on a\n\
symbolic link will effectively change the permissions of its\n\
destination object.",
		toplevel
	    );
	}


	/* Update toplevel */
	w = d->toplevel;
	if(w != NULL)
	{
	    /* Update title? */
	    if(title != NULL)
		gtk_window_set_title(GTK_WINDOW(w), title);

	    /* If given toplevel is not NULL then set transient for */
	    if((toplevel != NULL) ? GTK_IS_WINDOW(toplevel) : FALSE)
	    {
		gtk_window_set_transient_for(
		    GTK_WINDOW(w), GTK_WINDOW(toplevel)
		);
		d->ref_toplevel = toplevel;
	    }

	    /* Map toplevel */
	    gtk_widget_show_raise(w);
	}
}

/*
 *	Unmaps the File Operation Dialog.
 */
void EDVFOPDlgUnmap(edv_fopdlg_struct *d)
{
	GtkWidget *w = (d != NULL) ? d->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);

	/* Unset transient for */
	gtk_window_set_transient_for(GTK_WINDOW(w), NULL);
	d->ref_toplevel = NULL;
}

/*
 *	Deletes the File Operation Dialog.
 */
void EDVFOPDlgDelete(edv_fopdlg_struct *d)
{
	if(d == NULL)
	    return;

	/* Delete object list and source directory */
	EDVFOPDlgReset(d);

	d->ref_toplevel = NULL;		/* Shared */

	/* Begin destroying widgets */
	GTK_WIDGET_DESTROY(d->icon_pm)
	d->icon_pm = NULL;
	GTK_WIDGET_DESTROY(d->icon_fixed)
	d->icon_fixed = NULL;

	GTK_WIDGET_DESTROY(d->target_browse_btn)
	d->target_browse_btn = NULL;

	GTK_WIDGET_DESTROY(d->target_owner_btn)
	d->target_owner_btn = NULL;
	GTK_WIDGET_DESTROY(d->target_group_btn)
	d->target_group_btn = NULL;

	GTK_WIDGET_DESTROY(d->target_uread_check)
	d->target_uread_check = NULL;
	GTK_WIDGET_DESTROY(d->target_uwrite_check)
	d->target_uwrite_check = NULL;
	GTK_WIDGET_DESTROY(d->target_uexecute_check)
	d->target_uexecute_check = NULL;
	GTK_WIDGET_DESTROY(d->target_gread_check)
	d->target_gread_check = NULL;
	GTK_WIDGET_DESTROY(d->target_gwrite_check)
	d->target_gwrite_check = NULL;
	GTK_WIDGET_DESTROY(d->target_gexecute_check)
	d->target_gexecute_check = NULL;
	GTK_WIDGET_DESTROY(d->target_aread_check)
	d->target_aread_check = NULL;
	GTK_WIDGET_DESTROY(d->target_awrite_check)
	d->target_awrite_check = NULL;
	GTK_WIDGET_DESTROY(d->target_aexecute_check)
	d->target_aexecute_check = NULL;
	GTK_WIDGET_DESTROY(d->target_setuid_check)
	d->target_setuid_check = NULL;
	GTK_WIDGET_DESTROY(d->target_setgid_check)
	d->target_setgid_check = NULL;
	GTK_WIDGET_DESTROY(d->target_sticky_check)
	d->target_sticky_check = NULL;

	GTK_WIDGET_DESTROY(d->move_btn)
	d->move_btn = NULL;
	GTK_WIDGET_DESTROY(d->copy_btn)
	d->copy_btn = NULL;
	GTK_WIDGET_DESTROY(d->link_btn)
	d->link_btn = NULL;
	GTK_WIDGET_DESTROY(d->chmod_btn)
	d->chmod_btn = NULL;
	GTK_WIDGET_DESTROY(d->chown_btn)
	d->chown_btn = NULL;
	GTK_WIDGET_DESTROY(d->cancel_btn)
	d->cancel_btn = NULL;

	GTK_WIDGET_DESTROY(d->toplevel)
	d->toplevel = NULL;

	GTK_ACCEL_GROUP_UNREF(d->accelgrp)
	d->accelgrp = NULL;

	g_free(d);
}
