#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <unistd.h>

#include "../include/string.h"
#include "../include/disk.h"

#include "guiutils.h"
#include "menubutton.h"
#include "pie_chart.h"
#include "cdialog.h"
#include "pdialog.h"
#include "progressdialog.h"

#include "cfg.h"
#include "edv_types.h"
#include "edv_date.h"
#include "edv_id.h"
#include "edv_obj.h"
#include "edv_device.h"
#include "edv_devices_list.h"
#include "edv_mime_type.h"
#include "prop_dlg.h"
#include "endeavour2.h"
#include "edv_device_mount.h"
#include "edv_obj_op.h"
#include "edv_cb.h"
#include "edv_op.h"
#include "edv_utils.h"
#include "edv_utils_gtk.h"
#include "edv_cfg_list.h"
#include "config.h"

#include "images/icon_ok_20x20.xpm"
#include "images/icon_select_20x20.xpm"
#include "images/icon_cancel_20x20.xpm"
#include "images/icon_close_20x20.xpm"
#include "images/icon_link2_20x20.xpm"
#include "images/icon_link_broken_20x20.xpm"
#include "images/icon_time_stamp_20x20.xpm"
#include "images/icon_mount_20x20.xpm"
#include "images/icon_unmount_20x20.xpm"
#include "images/icon_eject_20x20.xpm" 
#include "images/icon_fsck_48x48.xpm"
#include "images/icon_tools_48x48.xpm"
#include "images/icon_floppy_48x48.xpm"
#include "images/icon_properties2_20x20.xpm"
#include "images/icon_properties2_48x48.xpm"


/* Callbacks */
static gint EDVPropDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
static void EDVPropDlgSwitchPageCB(
	GtkNotebook *notebook, GtkNotebookPage *page, guint page_num,
	gpointer data
);

static void EDVPropDlgAnyChangedCB(GtkWidget *widget, gpointer data);

static void EDVPropDlgOKCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgApplyCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgCancelCB(GtkWidget *widget, gpointer data);

static void EDVPropDlgDateTouchCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgDateTouchSpecificCB(GtkWidget *widget, gpointer data);

static void EDVPropDlgDetailsVerboseToggledCB(
	GtkWidget *widget, gpointer data
);
static void EDVPropDlgDetailsRawToggledCB(
	GtkWidget *widget, gpointer data
);

static void EDVPropDlgMountCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgEjectCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgRunCheckCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgRunToolsCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgRunFormatCB(GtkWidget *widget, gpointer data);

static void EDVPropDlgOwnerMapPUListCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgGroupMapPUListCB(GtkWidget *widget, gpointer data);

static void EDVPropDlgLinkDestinationChangeCB(GtkWidget *widget, gpointer data);
static void EDVPropDlgDestinationPropertiesCB(GtkWidget *widget, gpointer data);


/* Apply */
static void EDVPropDlgDoApply(edv_propdlg_struct *pd);


/* Utilities */
static void EDVPropDlgSetWidgetChangedSignal(
	edv_propdlg_struct *pd, GtkWidget *w
);


/* Page Creation */
static void EDVPropDlgCreateGeneralPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
);
static void EDVPropDlgCreateDetailsPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
);
static void EDVPropDlgCreateDetailsLabels(
	edv_propdlg_struct *pd, const struct stat *lstat_buf
);
static void EDVPropDlgCreateLinkPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
);
static void EDVPropDlgCreateDevicePage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj,
	gint dev_num, edv_device_struct *dev
);
static void EDVPropDlgCreateDeviceUsage(
	edv_propdlg_struct *pd, edv_device_struct *dev
);
static void EDVPropDlgCreateDeviceNodePage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
);


/* Callbacks */
void EDVPropDlgObjectAddedNotifyCB(
	edv_propdlg_struct *pd, const gchar *path,
	const struct stat *lstat_buf
);
void EDVPropDlgObjectModifiedNotifyCB(
	edv_propdlg_struct *pd,
	const gchar *path, const gchar *new_path,
	const struct stat *lstat_buf
);
void EDVPropDlgObjectRemovedNotifyCB(
	edv_propdlg_struct *pd, const gchar *path
);
void EDVPropDlgMountNotifyCB(
	edv_propdlg_struct *pd,
	gint dev_num, edv_device_struct *dev,
	gboolean is_mounted
);
void EDVPropDlgWriteProtectChangedCB(edv_propdlg_struct *pd, gboolean state);
void EDVPropDlgReconfiguredNotifyCB(edv_propdlg_struct *pd);


/* Front Ends */
edv_propdlg_struct *EDVPropDlgNew(
	edv_core_struct *core, edv_object_struct *obj
);
void EDVPropDlgResetHasChanges(
	edv_propdlg_struct *pd, gboolean has_changes
);
void EDVPropDlgUpdateMenus(edv_propdlg_struct *pd);
void EDVPropDlgSetBusy(edv_propdlg_struct *pd, gboolean is_busy);
gboolean EDVPropDlgIsMapped(edv_propdlg_struct *pd);
void EDVPropDlgMap(edv_propdlg_struct *pd);
void EDVPropDlgUnmap(edv_propdlg_struct *pd);
void EDVPropDlgDelete(edv_propdlg_struct *pd);


#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 PROPDLG_TITLE		"Properties"

#define PROPDLG_WIDTH		380
#define PROPDLG_HEIGHT		445

#define PROGDLG_USE_PERMISSION_CHECK_BUTTON	FALSE


/*
 *	GtkWindow "delete_event" signal callback.
 */
static gint EDVPropDlgDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return(TRUE);

	EDVPropDlgCancelCB(NULL, pd);

	return(TRUE);
}

/*
 *      GtkNotebook "switch_page" signal callback.
 */
static void EDVPropDlgSwitchPageCB(
	GtkNotebook *notebook, GtkNotebookPage *page, guint page_num,
	gpointer data
)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;
}

/*
 *	Properties Dialog any widget changed signal callback.
 */
static void EDVPropDlgAnyChangedCB(GtkWidget *widget, gpointer data)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	if(pd->freeze_count > 0)
	    return;

	if(!pd->has_changes)
	    EDVPropDlgResetHasChanges(pd, TRUE);
}


/*
 *      OK button callback.
 */
static void EDVPropDlgOKCB(GtkWidget *widget, gpointer data)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	EDVPropDlgDoApply(pd);
	EDVPropDlgUnmap(pd);
	EDVPropDlgResetHasChanges(pd, FALSE);

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *      Apply button callback.
 */
static void EDVPropDlgApplyCB(GtkWidget *widget, gpointer data)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	EDVPropDlgDoApply(pd);
	EDVPropDlgResetHasChanges(pd, FALSE);

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *      Cancel button callback.
 */
static void EDVPropDlgCancelCB(GtkWidget *widget, gpointer data)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	EDVPropDlgUnmap(pd);
}


/*
 *	Updates the time stamps of the object to the current date &
 *	time.
 */
static void EDVPropDlgDateTouchCB(GtkWidget *widget, gpointer data)
{
	const gulong	time_start = (gulong)time(NULL),
			cur_time = time_start;
	gboolean yes_to_all = FALSE;
	struct stat stat_buf;
	gint status;
	const gchar *path, *error_msg;
	GList *paths_list, *modified_paths_list;
	GtkWidget *w, *toplevel;
	edv_object_type type;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	toplevel = pd->toplevel;
	type = pd->type;
	path = pd->path;
	core = pd->core;
	if(STRISEMPTY(path) || (core == NULL))
	    return;

	/* If the touch button is not sensitive, then it means that
	 * the date cannot be modified (and this function should never
	 * have been called)
	 */
	w = pd->gen_date_touch_btn;
	if((w != NULL) ? !GTK_WIDGET_SENSITIVE(w) : TRUE)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	/* If this is a link then warn about changing the time
	 * stamps of links
	 */
	if(type == EDV_OBJECT_TYPE_LINK)
	{
	    gint response;
	    EDVPlaySoundWarning(core);
	    CDialogSetTransientFor(toplevel);
	    response = CDialogGetResponse(
"Changing Time Stamps Warning",
"Changing the time stamps on a link will effectively\n\
change the time stamps of its destination object.\n\
\n\
Are you sure you want to change the time stamps?",
		NULL,
		CDIALOG_ICON_WARNING,
		CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO,
		CDIALOG_BTNFLAG_YES
	    );
	    CDialogSetTransientFor(NULL);
	    if(response != CDIALOG_RESPONSE_YES)
	    {
		EDVPropDlgSetBusy(pd, FALSE);
		return;
	    }
	}

	/* Create the paths list */
	paths_list = NULL;
	paths_list = g_list_append(paths_list, STRDUP(path));

	/* Set the time stamps to the current time */
	status = EDVObjectOPChTime(
	    core,
	    paths_list, cur_time, cur_time,
	    &modified_paths_list,
	    toplevel,
	    TRUE,			/* Show progress */
	    TRUE,			/* Interactive */
	    &yes_to_all,
	    FALSE,			/* Not recursive */
	    TRUE			/* Archive */
	);

	/* Unmap the progress dialog */
	ProgressDialogBreakQuery(FALSE);
	ProgressDialogSetTransientFor(NULL);

	/* Get the error message (if any) */
	error_msg = EDVObjectOPGetError();
	if(!STRISEMPTY(error_msg))
	{
	    /* Print the error message */
	    EDVPlaySoundError(core);
	    EDVMessageError(
		"Change Time Stamps Error",
		error_msg,
		NULL,
		toplevel
	    );
	}

	/* Notify about the object being modified */
	if(modified_paths_list != NULL)
	{
	    const gchar *modified_path;
	    GList *glist;

	    for(glist = modified_paths_list;
		glist != NULL;
		glist = g_list_next(glist)
	    )
	    {
		modified_path = (const gchar *)glist->data;
		if(modified_path == NULL)
		    continue;

		if(!lstat((const char *)modified_path, &stat_buf))
		    EDVObjectModifiedEmit(
			core,
			modified_path,
			modified_path,
			&stat_buf
		    );
	    }

	    g_list_foreach(modified_paths_list, (GFunc)g_free, NULL);
	    g_list_free(modified_paths_list);
	}

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

	/* Delete the paths list */
	if(paths_list != NULL)
	{
	    g_list_foreach(paths_list, (GFunc)g_free, NULL);
	    g_list_free(paths_list);
	}
 
	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *      Queries user for specific date & time to set for the 
 *	object.
 */
static void EDVPropDlgDateTouchSpecificCB(GtkWidget *widget, gpointer data)
{
	edv_date_relativity relativity;
	const gchar *format, *path;
	GtkWidget *w, *toplevel;
	const cfg_item_struct *cfg_list;
	edv_object_type type;
	edv_object_struct *obj;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	toplevel = pd->toplevel;
	path = pd->path;
	type = pd->type;
	core = pd->core;
	if(PDialogIsQuery() || STRISEMPTY(path) || (core == NULL))
	    return;

	cfg_list = core->cfg_list;

	/* If the touch button is not sensitive, then it means that
	 * the date cannot be modified (and this function should never
	 * have been called)
	 */
	w = pd->gen_date_touch_btn;
	if((w != NULL) ? !GTK_WIDGET_SENSITIVE(w) : TRUE)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	/* Get the date & time format options */
	relativity = (edv_date_relativity)EDV_GET_I(
	    EDV_CFG_PARM_DATE_RELATIVITY
	);
	format = EDV_GET_S(EDV_CFG_PARM_DATE_FORMAT);

	/* Create a new tempory object and obtain the current stats */
	obj = EDVObjectNew();
	if(obj != NULL)
	{
	    struct stat lstat_buf;

	    /* Set the object's stats */
	    if(!lstat((const char *)path, &lstat_buf))
	    {
		edv_object_struct *obj_list[1];
		edv_obj_op_dlg_struct *d = pd->obj_op_dlg;
		if(d == NULL)
		    pd->obj_op_dlg = d = EDVObjOpDlgNew(core);

		EDVObjectSetPath(obj, path);
		EDVObjectSetStat(obj, &lstat_buf);
		EDVObjectUpdateLinkFlags(obj);

		/* Map the object operations dialog to change time
		 * stamps
		 */
		obj_list[0] = obj;
		EDVObjOpDlgMapValues(
		    d, EDV_OBJ_OP_DLG_OP_CHTIME,
		    obj_list, 1,
		    NULL,
		    toplevel
		);

	    }   /* Get the object's stats */

	    /* Delete the tempory object */
	    EDVObjectDelete(obj);
	}

	EDVPropDlgSetBusy(pd, FALSE);
}


/*
 *	Details verbose radio "toggled" signal callback.
 */
static void EDVPropDlgDetailsVerboseToggledCB(
	GtkWidget *widget, gpointer data
)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	if(pd->freeze_count > 0)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);
	pd->freeze_count++;

	if(!STRISEMPTY(pd->path))
	{
	    struct stat lstat_buf;
	    if(!lstat((const char *)pd->path, &lstat_buf))
		EDVPropDlgCreateDetailsLabels(pd, &lstat_buf);
	}

	pd->freeze_count--;
	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *	Details raw radio "toggled" signal callback.
 */
static void EDVPropDlgDetailsRawToggledCB(
	GtkWidget *widget, gpointer data
)
{
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	if(pd->freeze_count > 0)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);
	pd->freeze_count++;

	if(!STRISEMPTY(pd->path))
	{
	    struct stat lstat_buf;
	    if(!lstat((const char *)pd->path, &lstat_buf))
		EDVPropDlgCreateDetailsLabels(pd, &lstat_buf);
	}

	pd->freeze_count--;
	EDVPropDlgSetBusy(pd, FALSE);
}


/*
 *	Mount/Unmount Device callback.
 */
static void EDVPropDlgMountCB(GtkWidget *widget, gpointer data)
{
	gboolean original_mount_state;
	gint status, dev_num;
	GtkWidget *toplevel;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	toplevel = pd->toplevel;
	core = pd->core;
	if(core == NULL)
	    return;

	dev_num = pd->dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	original_mount_state = EDV_DEVICE_IS_MOUNTED(dev);

	/* Unmount or mount? */
 	if(EDV_DEVICE_IS_MOUNTED(dev))
	    status = EDVDeviceUnmount(
		core, dev,
		TRUE, TRUE,
		toplevel
	    );
	else
	    status = EDVDeviceMount(
		core, dev,
		TRUE, TRUE,
		toplevel
	    );

	/* Update all device mount states and stats */
	EDVDevicesListUpdateMountStates(
	    core->device, core->total_devices
	);
	EDVDevicesListUpdateStats(
	    core->device, core->total_devices
	);

	/* Mount/unmount error? */
	if(status)
	{
	    /* Get the error message (if any) */
	    const gchar *last_error = EDVDeviceUnmountGetError();
	    if(!STRISEMPTY(last_error))
	    {
		EDVPlaySoundError(core);
		EDVMessageError(
		    original_mount_state ?
			"Unmount Failed" : "Mount Failed",
		    last_error,
		    NULL,
		    toplevel
		);
	    }
	}
	else
	{
	    /* Report mount signal to all of endeavour's resources */
	    EDVObjectMountEmit(
		core, dev_num, dev, EDV_DEVICE_IS_MOUNTED(dev)
	    );

/* Warning, some widgets on the Propeties Dialog may be invalid at this
 * point if fetched earlier in this function
 */
	}

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *	Eject Device callback.
 */
static void EDVPropDlgEjectCB(GtkWidget *widget, gpointer data)
{
	gboolean original_mount_state;
	gint status, dev_num;
	GtkWidget *toplevel;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	toplevel = pd->toplevel;
	core = pd->core;
	if(core == NULL)
	    return;

	dev_num = pd->dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	original_mount_state = EDV_DEVICE_IS_MOUNTED(dev);

	/* Need to unmount first? */
	if(EDV_DEVICE_IS_MOUNTED(dev))
	    EDVDeviceUnmount(
		core, dev,
		TRUE, TRUE,
		toplevel
	    );

	/* Eject */
	status = EDVDeviceEject(
	    core, dev,
	    TRUE, TRUE,
	    toplevel
	);

	/* Update all device mount states and stats */
	EDVDevicesListUpdateMountStates(
	    core->device, core->total_devices
	);
	EDVDevicesListUpdateStats(
	    core->device, core->total_devices
	);

	/* Eject error? */
	if(status)
	{
	    /* Get the error message (if any) */
	    const gchar *last_error = EDVDeviceUnmountGetError();
	    if(!STRISEMPTY(last_error))
	    {
		EDVPlaySoundError(core);
		EDVMessageError(
		    "Eject Failed",
		    last_error,
		    NULL,
		    toplevel
		);
	    }
	}
	else
	{   
	    /* Report eject (unmount) signal to all of endeavour'sz
	     * resources
	     */
	    EDVObjectMountEmit(
		core, dev_num, dev, EDV_DEVICE_IS_MOUNTED(dev)
	    );
	}

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *      Runs the file system check command.
 */
static void EDVPropDlgRunCheckCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	dev_num = pd->dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL)
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	EDVRunDeviceCheck(core, dev, pd->toplevel);

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *	Runs the device tools command.
 */
static void EDVPropDlgRunToolsCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	dev_num = pd->dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL) 
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	EDVRunDeviceTools(core, dev, pd->toplevel);

	EDVPropDlgSetBusy(pd, FALSE);
}

/*
 *      Runs the device format command.
 */
static void EDVPropDlgRunFormatCB(GtkWidget *widget, gpointer data)
{
	gint dev_num;
	edv_device_struct *dev;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	dev_num = pd->dev_num;
	dev = ((dev_num >= 0) && (dev_num < core->total_devices)) ?
	    core->device[dev_num] : NULL;
	if(dev == NULL) 
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	EDVRunDeviceFormat(core, dev, pd->toplevel);

	EDVPropDlgSetBusy(pd, FALSE);
}


/*
 *	Maps the popup list for the owner entry.
 */
static void EDVPropDlgOwnerMapPUListCB(GtkWidget *widget, gpointer data)
{
	gint nitems, nitems_visible;
	gchar *old_value;
	const gchar *value;
	GtkEntry *entry;
	pulist_struct *pulist;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	entry = (GtkEntry *)pd->gen_owner_entry;
	if((core == NULL) || (entry == NULL))
	    return;

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

	old_value = STRDUP(gtk_entry_get_text(entry));

        nitems = PUListGetTotalItems(pulist);
        nitems_visible = MIN(15, nitems);

	/* Block input and get value */
	value = PUListMapQuery(
	    pulist,			/* Popup List */
	    old_value,			/* Initial Value */
	    nitems_visible,
	    PULIST_RELATIVE_BELOW,	/* Popup Relativity */
	    GTK_WIDGET(entry),		/* Relative Widget */
	    widget			/* Map Trigger Widget */
	);
	if(value != NULL)
	{
	    /* Set new value if it is different from the old value  */
	    if((old_value != NULL) ? strcmp(old_value, value) : TRUE)
		gtk_entry_set_text(entry, value);
	}

	g_free(old_value);
}

/*
 *      Maps the popup list for the group entry.
 */
static void EDVPropDlgGroupMapPUListCB(GtkWidget *widget, gpointer data)
{
	gint nitems, nitems_visible;
	gchar *old_value;
	const gchar *value;
	GtkEntry *entry;
	pulist_struct *pulist;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	entry = (GtkEntry *)pd->gen_group_entry;
	if((core == NULL) || (entry == NULL))
	    return;

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

	old_value = STRDUP(gtk_entry_get_text(entry));

        nitems = PUListGetTotalItems(pulist);
        nitems_visible = MIN(15, nitems);

	/* Block input and get value */
	value = PUListMapQuery(
	    pulist,			/* Popup List */
	    old_value,			/* Initial Value */
	    nitems_visible,
	    PULIST_RELATIVE_BELOW,	/* Popup Relativity */
	    GTK_WIDGET(entry),		/* Relative Widget */
	    widget			/* Map Trigger Widget */
	);
	if(value != NULL)
	{
	    /* Set new value if it is different from the old value  */
	    if((old_value != NULL) ? strcmp(old_value, value) : TRUE)
		gtk_entry_set_text(entry, value);
	}

	g_free(old_value);
}

/*
 *	Link destination entry "changed" callback.
 */
static void EDVPropDlgLinkDestinationChangeCB(GtkWidget *widget, gpointer data)
{
	const gchar *value;
	GtkEntry *entry;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	entry = (GtkEntry *)pd->link_dest_entry;
	if((core == NULL) || (entry == NULL))
	    return;

	/* Get link destination value */
	value = gtk_entry_get_text(entry);
	if(!STRISEMPTY(value))
	{
	    const gchar *dest_path;

	    /* Is link destination value an absolute path? */
	    if(g_path_is_absolute(value))
	    {
		dest_path = value;
	    }
	    else
	    {
		/* Link destination is not an absolute path, so prefix
		 * the parent path of the link to the link destination 
		 * path
		 */
		gchar *parent_path = (pd->path != NULL) ?
		    g_dirname(pd->path) : NULL;
		dest_path = PrefixPaths(parent_path, value);
		g_free(parent_path);
	    }
	    /* Got link destination path? */
	    if(dest_path != NULL)
	    {
		gboolean sensitive;
		GtkWidget *w;
		struct stat lstat_buf;


		/* Check if link destination path exists locally */
		if(lstat((const char *)dest_path, &lstat_buf))
		    sensitive = FALSE;
		else
		    sensitive = TRUE;

		/* Show or hide link connected & link broken icons */
		w = pd->link_connected_icon;
		if(w != NULL)
		{
		    if(sensitive)
			gtk_widget_show(w);
		    else
			gtk_widget_hide(w);
		}
		w = pd->link_broken_icon;
		if(w != NULL)
		{
		    if(sensitive)
			gtk_widget_hide(w);
		    else
			gtk_widget_show(w);
		}

		/* Update link destination properties button sensitivity
		 * based on existance of link destination path object
		 */
		GTK_WIDGET_SET_SENSITIVE(
		    pd->link_dest_properties_btn, sensitive
		)
	    }
	}
}

/*
 *	Destination properties callback.
 */
static void EDVPropDlgDestinationPropertiesCB(GtkWidget *widget, gpointer data)
{
	const gchar *value;
	GtkEntry *entry;
	edv_core_struct *core;
	edv_propdlg_struct *pd = EDV_PROPDLG(data);
	if(pd == NULL)
	    return;

	core = pd->core;
	entry = (GtkEntry *)pd->link_dest_entry;
	if((core == NULL) || (entry == NULL))
	    return;

	EDVPropDlgSetBusy(pd, TRUE);

	/* Get link destination value */
	value = gtk_entry_get_text(entry);
	if(!STRISEMPTY(value))
	{
	    gchar *dest_path;

	    /* Is link destination value an absolute path? */
	    if(g_path_is_absolute(value))
	    {
		dest_path = STRDUP(value);
	    }
	    else
	    {
		/* Link destination is not an absolute path, so prefix
		 * the parent path of the link to the link destination
		 * path
		 */
		gchar *parent_path = (pd->path != NULL) ?
		    g_dirname(pd->path) : NULL;
		dest_path = STRDUP(PrefixPaths(parent_path, value));
		g_free(parent_path);
		SimplifyPath(dest_path);
	    }
	    /* Got link destination path? */
	    if(!STRISEMPTY(dest_path))
	    {
		struct stat lstat_buf;

		/* Check if link destination path exists locally */
		if(!lstat((const char *)dest_path, &lstat_buf))
		{
		    edv_object_struct *obj = EDVObjectNew();
		    if(obj != NULL)
		    {
			EDVObjectSetPath(obj, dest_path);
			EDVObjectSetStat(obj, &lstat_buf);
			EDVObjectUpdateLinkFlags(obj);

			/* Create a new Properties Dialog and instruct
			 * it to load the destination object
			 */
			EDVNewPropertiesDialog(
			    core,
			    obj,
			    pd->toplevel
			);
		    }
		    EDVObjectDelete(obj);
		    obj = NULL;
		}
	    }

	    g_free(dest_path);
	}

	EDVPropDlgSetBusy(pd, FALSE);
}


/*
 *	Applies values from the property window to the disk object
 *	specified on the property window.
 */
static void EDVPropDlgDoApply(edv_propdlg_struct *pd)
{
	struct stat lstat_buf;
	GtkWidget *w, *toplevel;
	const gchar *path;
	edv_core_struct *core;

	if(pd == NULL)
	    return;

	toplevel = pd->toplevel;
	path = pd->path;
	core = pd->core;
	if(STRISEMPTY(path) || (core == NULL))
	    return;

	/* Check if the global write protect is on */
	if(EDVCheckWriteProtect(core, TRUE, pd->toplevel))
	    return;

	/* Check if the device major & minor number widgets are
	 * valid, implying that the device needs to be recreated
	 */
	w = pd->dev_node_major_entry;
	if((w != NULL) ? GTK_WIDGET_SENSITIVE(w) : FALSE)
	{
	    gint new_major = 0, new_minor = 0;

	    /* Get the new major & minor numbers */
	    w = pd->dev_node_major_entry;
	    if(w != NULL)
		new_major = ATOI(gtk_entry_get_text(GTK_ENTRY(w)));

	    w = pd->dev_node_minor_entry;
	    if(w != NULL)
	        new_minor = ATOI(gtk_entry_get_text(GTK_ENTRY(w)));

	    /* Get the device's statistics */
	    if(lstat((const char *)path, &lstat_buf) == 0)
	    {
		gint major = 0, minor = 0;

		/* Get the current major & minor numbers */
		EDVGetDeviceNumbers(lstat_buf.st_rdev, &major, &minor);

		/* Original device node numbers different from the
		 * new device node numbers?
		 */
		if((new_major != major) || (new_minor != minor))
		{
		    /* Set the device number by recreating the device
		     * node
		     */
		    const gint rdev = EDVFormatDeviceNumbers(
			new_major, new_minor
		    );

		    /* Remove the existing device */
		    if(unlink((const char *)path))
		    {
			const gint error_code = (gint)errno;
			gchar *error_msg = STRDUP(g_strerror(error_code));
			EDVPlaySoundError(core);
			EDVMessageError(
			    "Change Device Numbers Error",
			    error_msg,
			    NULL,
			    toplevel
			);
			g_free(error_msg);
		    }
		    /* Recreate the device */
		    else if(mknod(
			(const char *)path,
			lstat_buf.st_mode,
			(dev_t)rdev
		    ))
		    {
			const gint error_code = (gint)errno;
			gchar *error_msg = STRDUP(g_strerror(error_code));
			EDVPlaySoundError(core);
			EDVMessageError(
			    "Change Device Numbers Error",
			    error_msg,
			    NULL,
			    toplevel
			);
			g_free(error_msg);
		    }
		    else
		    {
			struct utimbuf utime_buf;

			/* Restore the ownership */
			lchown(
			    (const char *)path,
			    lstat_buf.st_uid, lstat_buf.st_gid
			);

			/* Restore the time stamps */
			utime_buf.actime = lstat_buf.st_atime;
			utime_buf.modtime = lstat_buf.st_mtime;
			utime((const char *)path, &utime_buf);
		    }
		}
	    }
	    else
	    {
		/* Unable to get the device node's stats */
		const gint error_code = (gint)errno;
		gchar *error_msg = STRDUP(g_strerror(error_code));
		EDVPlaySoundError(core);
		EDVMessageError(
		    "Change Device Numbers Error",
		    error_msg,
		    NULL,
		    toplevel
		);
		g_free(error_msg);
	    }
	}

	/* If the link destination entry exists then that implies
	 * that there is a new link destination to set
	 */
	w = pd->link_dest_entry;
	if((w != NULL) ? GTK_WIDGET_SENSITIVE(w) : FALSE)
	{
	    gboolean yes_to_all = FALSE;
	    const gchar *error_msg;
	    gchar *value = STRDUP(gtk_entry_get_text(GTK_ENTRY(w)));
	    GList *modified_paths_list;

	    /* Links may not have empty values */
	    if(STRISEMPTY(value))
	    {
		g_free(value);
		value = STRDUP("undefined");
	    }

	    /* Relink */
	    EDVObjectOPRelink(
		core,
		path,				/* Link */
		value,				/* Value */
		&modified_paths_list,
		pd->toplevel,
		TRUE, TRUE,
		&yes_to_all
	    );

	    g_free(value);

	    /* Unmap the progress dialog just in case */
	    ProgressDialogBreakQuery(FALSE);
	    ProgressDialogSetTransientFor(NULL);

	    /* Get the error message (if any) */
	    error_msg = EDVObjectOPGetError();
	    if(!STRISEMPTY(error_msg))
	    {
		EDVPlaySoundError(core);
		EDVMessageError(
		    "Change Link Destination Error",
		    error_msg,
		    NULL,
		    toplevel
		);
	    }

	    if(modified_paths_list != NULL)
	    {
		g_list_foreach(modified_paths_list, (GFunc)g_free, NULL);
		g_list_free(modified_paths_list);
	    }
	}

	/* If the permissions frame is sensitive then that implies
	 * that there are permissions to be set
	 */
	w = pd->gen_permissions_frame;
	if((w != NULL) ? GTK_WIDGET_SENSITIVE(w) : FALSE)
	{
	    gboolean yes_to_all = FALSE;
	    const gchar *error_msg;
	    GList *paths_list, *modified_paths_list;
	    edv_permission_flags permissions = 0x00000000;

	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_ur_check))
		permissions |= EDV_PERMISSION_UREAD;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_uw_check))
		permissions |= EDV_PERMISSION_UWRITE;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_ux_check))
		permissions |= EDV_PERMISSION_UEXECUTE;

	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_gr_check))
		permissions |= EDV_PERMISSION_GREAD;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_gw_check))
		permissions |= EDV_PERMISSION_GWRITE;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_gx_check))
		permissions |= EDV_PERMISSION_GEXECUTE;

	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_or_check))
		permissions |= EDV_PERMISSION_AREAD;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_ow_check))
		permissions |= EDV_PERMISSION_AWRITE;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_ox_check))
		permissions |= EDV_PERMISSION_AEXECUTE;

	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_suid_check))
		permissions |= EDV_PERMISSION_SETUID;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_sgid_check))
		permissions |= EDV_PERMISSION_SETGID;
	    if(GTK_TOGGLE_BUTTON_GET_ACTIVE(pd->gen_sticky_check))
		permissions |= EDV_PERMISSION_STICKY;

	    /* Create the paths list */
	    paths_list = NULL;
	    paths_list = g_list_append(paths_list, STRDUP(path));

	    /* Change the permissions */
	    EDVObjectOPChMod(
		core,
		paths_list, permissions,
		&modified_paths_list,
		pd->toplevel,
		FALSE,			/* Do not show progress */
		TRUE,			/* Interactive */
		&yes_to_all,
		FALSE,			/* Not recursive */
		TRUE			/* Archive */
	    );

	    /* Unmap the progress dialog just in case */
	    ProgressDialogBreakQuery(FALSE);
	    ProgressDialogSetTransientFor(NULL);

	    /* Get the error message (if any) */
	    error_msg = EDVObjectOPGetError();
	    if(!STRISEMPTY(error_msg))
	    {
		EDVPlaySoundError(core);
		EDVMessageError(
		    "Change Permissions Error",
		    error_msg,
		    NULL,
		    toplevel
		);
	    }

	    if(modified_paths_list != NULL)
	    {
		g_list_foreach(modified_paths_list, (GFunc)g_free, NULL);
		g_list_free(modified_paths_list);
	    }

	    if(paths_list != NULL)
	    {
		g_list_foreach(paths_list, (GFunc)g_free, NULL);
		g_list_free(paths_list);
	    }
	}

	/* Begin setting owner */
	w = pd->gen_ownership_frame;
	if((w != NULL) ? GTK_WIDGET_SENSITIVE(w) : FALSE)
	{
	    gboolean yes_to_all = FALSE;
	    gint owner_id = 0, group_id = 0;
	    const gchar *error_msg;

	    /* Get user id from user entry */
	    w = pd->gen_owner_entry;
	    if(w != NULL)
	    {
		owner_id = EDVUIDNameToUID(
		    core->uid, core->total_uids,
		    gtk_entry_get_text(GTK_ENTRY(w))
		);
	    }

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

	    /* Get original stats before changing owners */
	    if(!lstat((const char *)path, &lstat_buf))
	    {
		/* Original owner or group different from new owner or group? */
		if((owner_id != (gint)lstat_buf.st_uid) ||
		   (group_id != (gint)lstat_buf.st_gid)
		)
		{
		    GList *paths_list, *modified_paths_list;

		    /* Create the paths list */
		    paths_list = NULL;
		    paths_list = g_list_append(paths_list, STRDUP(path));

		    /* Change the ownership */
		    EDVObjectOPChOwn(
			core,
			paths_list, owner_id, group_id,
			&modified_paths_list,
			pd->toplevel,
			FALSE,			/* Do not show progress */
			TRUE,			/* Interactive */
			&yes_to_all,
			FALSE,			/* Not recursive */
			TRUE			/* Archive */
		    );

		    /* Unmap the progress dialog */
		    ProgressDialogBreakQuery(FALSE);
		    ProgressDialogSetTransientFor(NULL);

		    /* Get the error message (if any) */
		    error_msg = EDVObjectOPGetError();
		    if(!STRISEMPTY(error_msg))
		    {
			EDVPlaySoundError(core);
			EDVMessageError(
			    "Change Ownership Error",
			    error_msg,
			    NULL,
			    toplevel
			);
		    }

		    if(modified_paths_list != NULL)
		    {
			g_list_foreach(modified_paths_list, (GFunc)g_free, NULL);
			g_list_free(modified_paths_list);
		    }

		    if(paths_list != NULL)
		    {
			g_list_foreach(paths_list, (GFunc)g_free, NULL);
			g_list_free(paths_list);
		    }
		}
	    }
	}

	/* Notify about the object being modified */
	if(!lstat((const char *)path, &lstat_buf))
	    EDVObjectModifiedEmit(
		core, path, path, &lstat_buf
	    );
}


/*
 *	Connects the GtkWidget to the EDVPropDlgAnyChangedCB signal
 *	callback.
 */
static void EDVPropDlgSetWidgetChangedSignal(
	edv_propdlg_struct *pd, GtkWidget *w
)
{
	void (*func_cb)(GtkWidget *, gpointer) = EDVPropDlgAnyChangedCB;
	gpointer data = pd;

	if(w == NULL)
	    return;

	if(GTK_IS_EDITABLE(w))
	    gtk_signal_connect(
		GTK_OBJECT(w), "changed",
		GTK_SIGNAL_FUNC(func_cb), data
	    );
	else if(GTK_IS_TOGGLE_BUTTON(w))
	    gtk_signal_connect(
		GTK_OBJECT(w), "toggled",
		GTK_SIGNAL_FUNC(func_cb), data
	    );

}


/*
 * 	Creates the general page parented to the given GtkVBox parent
 *	with respect to the given disk object structure values.
 */
static void EDVPropDlgCreateGeneralPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
)
{
	const gint	border_major = 5,
			border_minor = 2;
	gchar *s, *s2;
	edv_permission_flags permissions;
	GdkPixmap *pixmap, *pixmap_hid;
	GdkBitmap *mask, *mask_hid;
	GtkRcStyle *rcstyle;
	GtkStyle *style;
	GtkAccelGroup *accelgrp = pd->accelgrp;
	GtkWidget *w, *menu, *parent2, *parent3, *parent4, *parent5;
	if(obj == NULL)
	    return;

	/* Get object's permissions */
	permissions = obj->permissions;

	/* Get toplevel widget's style */
	style = gtk_widget_get_style(pd->toplevel);

	/* Get medium pixmap and mask pair for this object */
	EDVMatchObjectIcon(
	    core->device, core->total_devices,
	    core->mimetype, core->total_mimetypes,
	    obj->type,
	    obj->full_path,
	    TRUE, permissions,
	    1,			/* Medium icons */
	    &pixmap, &mask,
	    NULL, NULL,
	    NULL, NULL,
	    &pixmap_hid, &mask_hid
	);

	if(EDVIsObjectHidden(obj) && (pixmap_hid != NULL))
	{
	    pixmap = pixmap_hid;
	    mask = mask_hid;
	}


	/* Identification Frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Identificación"
#elif defined(PROG_LANGUAGE_FRENCH)
"Identification"
#elif defined(PROG_LANGUAGE_GERMAN)
"Identifikation"
#elif defined(PROG_LANGUAGE_ITALIAN)
"L'Identificazione"
#elif defined(PROG_LANGUAGE_DUTCH)
"Identificatie"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Identificação"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Identification"
#else
"Identification"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_vbox_new(FALSE, border_minor);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Name hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Icon */
	if(pixmap != NULL)
	{
	    pd->gen_icon_pm = w = gtk_pixmap_new(pixmap, mask);
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	}
	/* Name label */
	rcstyle = gtk_rc_style_new();
	rcstyle->font_name = STRDUP(
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1"
	);
	s = EDVShortenPath(obj->name, 40);
	pd->gen_name_label = w = gtk_label_new(s);
	g_free(s);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_modify_style(w, rcstyle);
	gtk_widget_show(w);
	GTK_RC_STYLE_UNREF(rcstyle)


	/* Location hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Label */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"La Ubicación"
#elif defined(PROG_LANGUAGE_FRENCH)
"Emplacement"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ort"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Posizione"
#elif defined(PROG_LANGUAGE_DUTCH)
"Plaats"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Localidade"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Plassering"
#else
"Location"
#endif
	    ":"
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	/* Location Label */
	s2 = (obj->full_path != NULL) ?
	    g_dirname(obj->full_path) : NULL;
	s = EDVShortenPath(s2, 45);
	pd->gen_location_label = w = gtk_label_new(s);
	g_free(s);
	g_free(s2);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	if(obj->type == EDV_OBJECT_TYPE_FILE)
	{
	    /* File size hbox */
	    w = gtk_hbox_new(FALSE, border_major);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;
	    /* Label */
	    w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Tamaño"
#elif defined(PROG_LANGUAGE_FRENCH)
"Taille"
#elif defined(PROG_LANGUAGE_GERMAN)
"Größe"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Misura"
#elif defined(PROG_LANGUAGE_DUTCH)
"Maat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Tamanho"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Størrelse"
#else
"Size"
#endif
		":"
	    );
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    /* Size Label */
	    pd->gen_size_label = w = gtk_label_new("");
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    /* Units Label */
	    w = gtk_label_new("bytes");
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	}
	else
	{
	    /* File size hbox */
	    w = gtk_hbox_new(FALSE, border_major);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;
	    /* Label */
	    w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Tamaño"
#elif defined(PROG_LANGUAGE_FRENCH)
"Taille"
#elif defined(PROG_LANGUAGE_GERMAN)
"Größe"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Misura"
#elif defined(PROG_LANGUAGE_DUTCH)
"Maat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Tamanho"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Størrelse"
#else
"Size"
#endif
		":"
	    );
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    GTK_WIDGET_SET_SENSITIVE(w, FALSE)
	    gtk_widget_show(w);
	}

	/* Time stamps frame */
	pd->gen_timestamps_frame = w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El tiempo Estampa"
#elif defined(PROG_LANGUAGE_FRENCH)
"Horodateur"
#elif defined(PROG_LANGUAGE_GERMAN)
"Zeit Stempelt"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Tempo Timbra"
#elif defined(PROG_LANGUAGE_DUTCH)
"Tijd Stempelt"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Tempo Sela"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Tid Stamps"
#else
"Time Stamps"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	/* Hbox to separate date labels and touch button */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Vbox for date labels */
	w = gtk_vbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Last accessed hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Prefix label */
	w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);
	gtk_widget_set_usize(w, 100, -1);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Dure Accesado"
#elif defined(PROG_LANGUAGE_FRENCH)
"Dernier Accès"
#elif defined(PROG_LANGUAGE_GERMAN)
"Leisten Zugegriffen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Durare Accesso"
#elif defined(PROG_LANGUAGE_DUTCH)
"Leest Had Toegang Tot"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Dure Acedido"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Siste Accessed"
#else
"Last Accessed"
#endif
	    ":"
	);
	gtk_container_add(GTK_CONTAINER(parent5), w);
	gtk_widget_show(w);
	/* Date label */
	pd->gen_date_access_label = w = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Last modified hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Prefix label */
	w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);
	gtk_widget_set_usize(w, 100, -1);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Dure Modificado"
#elif defined(PROG_LANGUAGE_FRENCH)
"Derniére Modification"
#elif defined(PROG_LANGUAGE_GERMAN)
"Dauern Modifiziert"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Durare Modificato"
#elif defined(PROG_LANGUAGE_DUTCH)
"Duur Wijzigde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Dure Modificado"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Siste Modified"
#else
"Last Modified"
#endif
	    ":"
	);
	gtk_container_add(GTK_CONTAINER(parent5), w);
	gtk_widget_show(w);
	/* Date label */
	pd->gen_date_modify_label = w = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Last changed hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Prefix label */
	w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);
	gtk_widget_set_usize(w, 100, -1);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Dure Cambiado"
#elif defined(PROG_LANGUAGE_FRENCH)
"Dernier changement"
#elif defined(PROG_LANGUAGE_GERMAN)
"Dauern Geändert"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Durare Cambiato"
#elif defined(PROG_LANGUAGE_DUTCH)
"Duur Veranderde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Dure Mudado"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Siste Changed"
#else
"Last Changed"
#endif
	    ":"
	);
	gtk_container_add(GTK_CONTAINER(parent5), w);
	gtk_widget_show(w);
	/* Date label */
	pd->gen_date_change_label = w = gtk_label_new("");
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Alignment for touch button */
	w = gtk_alignment_new(1.0f, 0.0f, 0.0f, 0.0f);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Touch button */
	pd->gen_date_touch_btn = w = MenuButtonNewH(
#if defined(PROG_LANGUAGE_SPANISH)
"Toque"
#elif defined(PROG_LANGUAGE_FRENCH)
"Maintenant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Berührung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Tocco"
#elif defined(PROG_LANGUAGE_DUTCH)
"Aanraking"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Toque"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Berøring"
#else
"Touch"
#endif
	    ,
	    (guint8 **)icon_time_stamp_20x20_xpm,
	    &menu
	);
	gtk_widget_set_usize(
	    w,
	    GUI_BUTTON_HLABEL_WIDTH, GUI_BUTTON_HLABEL_HEIGHT
	);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVPropDlgDateTouchCB), pd
	);
	MenuButtonSetMapTrigger(w, MENU_BUTTON_MAP_TYPE_PRESSED_DRAG);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Modifique Sellos De Tiempo (el clic y el obstáculo para el menú)"
#elif defined(PROG_LANGUAGE_FRENCH)
"Modifier la datation (déclic et traîne pour le menu)"
#elif defined(PROG_LANGUAGE_GERMAN)
"Modifizieren Sie Zeit Briefmarken (klicken und widerstand für menü)"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Modificare I Francobolli Di Tempo (lo scatto e trascinare per il menu)"
#elif defined(PROG_LANGUAGE_DUTCH)
"Wijziig Tijd Stempels (klik en ruk voor menu)"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Modifique Selos De Tempo (estalido e arrasta para cardápio)"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Modifiser Time Stamps (klikk og hindring for meny)"
#else
"Modify Time Stamps (click and drag for menu)"
#endif
	);
	gtk_widget_show(w);
	/* Touch menu */
	if(menu != NULL)
	{
	    guint8 **icon;
	    const gchar *label;
	    guint accel_key, accel_mods;
	    gpointer mclient_data = pd;
	    void (*func_cb)(GtkWidget *w, gpointer);

#define DO_ADD_MENU_ITEM_LABEL	{		\
 w = GUIMenuItemCreate(				\
  menu, GUI_MENU_ITEM_TYPE_LABEL, accelgrp,	\
  icon, label, accel_key, accel_mods, NULL,	\
  mclient_data, func_cb				\
 );						\
}
#define DO_ADD_MENU_SEP		{		\
 w = GUIMenuItemCreate(				\
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL,	\
  NULL, NULL, 0, 0, NULL,			\
  NULL, NULL					\
 );						\
}
	    icon = NULL;
	    label =
#if defined(PROG_LANGUAGE_SPANISH)
"La Fecha Actual & Tiempo"
#elif defined(PROG_LANGUAGE_FRENCH)
"La Date & heure courante"
#elif defined(PROG_LANGUAGE_GERMAN)
"Jetziges Datum & Zeit"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Data Attuale & Il Tempo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Huidig Datum & Tijd"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Data Atual & Tempo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Nåværende Date & Time"
#else
"Current Date & Time"
#endif
	    ;
	    accel_key = 0;
	    accel_mods = 0;
	    func_cb = EDVPropDlgDateTouchCB;
	    DO_ADD_MENU_ITEM_LABEL

	    icon = NULL;
	    label =
#if defined(PROG_LANGUAGE_SPANISH)
"La Fecha Fija & Tiempo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Régler ~La date & l'heure"
#elif defined(PROG_LANGUAGE_GERMAN)
"Festes Datum & Zei"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Ha Regolato La Data & Il Tempo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Vast Datum & Tijd"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Data fixa & Tempo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Fast Date & Time"
#else
"Set Date & Time"
#endif
	    "...";
	    accel_key = 0;
	    accel_mods = 0;
	    func_cb = EDVPropDlgDateTouchSpecificCB;
	    DO_ADD_MENU_ITEM_LABEL

#undef DO_ADD_MENU_SEP
#undef DO_ADD_MENU_ITEM_LABEL
	}


	/* Ownership frame */
	pd->gen_ownership_frame = w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Propiedad"
#elif defined(PROG_LANGUAGE_FRENCH)
"Propriétaire"
#elif defined(PROG_LANGUAGE_GERMAN)
"Eigentumsrecht"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Proprietà"
#elif defined(PROG_LANGUAGE_DUTCH)
"Eigendomsrecht"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Posse"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Eiendomsrett"
#else
"Ownership"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_vbox_new(FALSE, border_minor);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Hbox for owner and group */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Hbox for owner */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Label */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Dueño"
#elif defined(PROG_LANGUAGE_FRENCH)
"Propriétaire"
#elif defined(PROG_LANGUAGE_GERMAN)
"Eigentümer"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Proprietario"
#elif defined(PROG_LANGUAGE_DUTCH)
"Eigenaar"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Proprietário"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Eier"
#else
"Owner"
#endif
	    ":"
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	/* Entry and map button hbox */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Entry */
	pd->gen_owner_entry = w = gtk_entry_new();
	gtk_entry_set_text(
	    GTK_ENTRY(w),
	    EDVUIDGetNameFromUID(
		core->uid, core->total_uids,
		obj->owner_id, NULL
	    )
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, TRUE, TRUE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	gtk_widget_show(w);
	/* Popup list map button */
	pd->gen_owner_btn = w = PUListNewMapButtonArrow(
	    GTK_ARROW_DOWN, GTK_SHADOW_OUT,
	    EDVPropDlgOwnerMapPUListCB, pd
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Hbox for group */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Label */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Grupo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Groupe de propriétaire"
#elif defined(PROG_LANGUAGE_GERMAN)
"Gruppe"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Gruppo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Groep"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Grupo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gruppe"
#else
"Group"
#endif
	    ":"
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	/* Entry and map button hbox */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Entry */
	pd->gen_group_entry = w = gtk_entry_new();
	gtk_entry_set_text(
	    GTK_ENTRY(w),
	    EDVGIDGetNameFromGID(
		core->gid, core->total_gids,
		obj->group_id, NULL
	    )
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, TRUE, TRUE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	gtk_widget_show(w);
	/* Popup list map button */
	pd->gen_group_btn = w = PUListNewMapButtonArrow(
	    GTK_ARROW_DOWN, GTK_SHADOW_OUT,
	    EDVPropDlgGroupMapPUListCB, pd
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Permissions frame */
	pd->gen_permissions_frame = w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
	    "Los Permisos"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Permissions"
#else
	    "Permissions"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	/* Set permissions frame insensitive for object types that do
	 * not have permissions
	 */
	if(obj->type == EDV_OBJECT_TYPE_LINK)
	    GTK_WIDGET_SET_SENSITIVE(w, FALSE)

	w = gtk_vbox_new(FALSE, border_major);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Vbox for standard permission labels and check buttons */
	w = gtk_vbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Labels hbox */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
	    "El Dueño"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Propriétaire"
#else
	    "Owner"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
	    "El Grupo"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Groupe"
#else
	    "Group"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
	    "Otro"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Autre"
#else
	    "Other"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);

	/* Check buttons hbox */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;

#define NEW_PERMISSION_TOGGLE_BUTTON(_label_,_tip_,_active_,_parent_)	{\
 if(PROGDLG_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_set_active(					\
  GTK_TOGGLE_BUTTON(w), (_active_) ? TRUE : FALSE		\
 );								\
 gtk_box_pack_start(GTK_BOX(_parent_), w, FALSE, FALSE, 0);	\
 EDVPropDlgSetWidgetChangedSignal(pd, w);			\
 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(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    permissions & EDV_PERMISSION_UREAD,
	    parent5
	)
	pd->gen_ur_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    permissions & EDV_PERMISSION_UWRITE,
	    parent5
	)
	pd->gen_uw_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    permissions & EDV_PERMISSION_UEXECUTE,
	    parent5
	)
	pd->gen_ux_check = w;

	/* Group check button set hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    permissions & EDV_PERMISSION_GREAD,
	    parent5
	)
	pd->gen_gr_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    permissions & EDV_PERMISSION_GWRITE,
	    parent5
	)
	pd->gen_gw_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    permissions & EDV_PERMISSION_GEXECUTE,
	    parent5
	)
	pd->gen_gx_check = w;

	/* Other/Anonymous check button set hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	/* Read check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "R", "Read",
	    permissions & EDV_PERMISSION_AREAD,
	    parent5
	)
	pd->gen_or_check = w;
	/* Write check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "W", "Write",
	    permissions & EDV_PERMISSION_AWRITE,
	    parent5
	)
	pd->gen_ow_check = w;
	/* Execute check button */
	NEW_PERMISSION_TOGGLE_BUTTON(
	    "X", "Execute",
	    permissions & EDV_PERMISSION_AEXECUTE,
	    parent5
	)
	pd->gen_ox_check = w;

#undef NEW_PERMISSION_TOGGLE_BUTTON

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

	/* Setuid check button */
	pd->gen_suid_check = w = gtk_check_button_new_with_label("SetUID");
	gtk_toggle_button_set_active(
	    GTK_TOGGLE_BUTTON(w), 
	    (permissions & EDV_PERMISSION_SETUID) ? TRUE : FALSE
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	GUISetWidgetTip(w, "Set owner's permission on use");
	gtk_widget_show(w);

	/* Setgid check button */
	pd->gen_sgid_check = w = gtk_check_button_new_with_label("SetGID");
	gtk_toggle_button_set_active(
	    GTK_TOGGLE_BUTTON(w), 
	    (permissions & EDV_PERMISSION_SETGID) ? TRUE : FALSE
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	GUISetWidgetTip(w, "Set group's permissions on use");
	gtk_widget_show(w);

	/* Sticky check button */
	pd->gen_sticky_check = w = gtk_check_button_new_with_label(
#if defined(PROG_LANGUAGE_SPANISH)
	    "Pegajoso"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Collant"
#else
	    "Sticky"
#endif
	);
	gtk_toggle_button_set_active(
	    GTK_TOGGLE_BUTTON(w), 
	    (permissions & EDV_PERMISSION_STICKY) ? TRUE : FALSE
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	GUISetWidgetTip(w, "Set user's permissions on use");
	gtk_widget_show(w);


}

/*
 *	Creates the Details Page parented to the given GtkVBox parent
 *	with respect to the given object.
 */
static void EDVPropDlgCreateDetailsPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
)
{
	const gint	border_major = 5,
			border_minor = 2;
	GSList *gslist;
	GtkWidget *w, *parent2, *parent3;


	/* Details Frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Los Detalles"
#elif defined(PROG_LANGUAGE_FRENCH)
"Détails"
#elif defined(PROG_LANGUAGE_GERMAN)
"Statistik"
#elif defined(PROG_LANGUAGE_ITALIAN)
"I Dettagli"
#elif defined(PROG_LANGUAGE_DUTCH)
"Statistieken"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Os Detalhes"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Detaljer"
#else
"Details"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	/* Details main vbox */
	pd->det_vbox = w = gtk_vbox_new(FALSE, border_major);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Hbox for radios */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_end(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Despliegue"
#elif defined(PROG_LANGUAGE_FRENCH)
"Affichage"
#elif defined(PROG_LANGUAGE_GERMAN)
"Ausstellung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Mostra"
#elif defined(PROG_LANGUAGE_DUTCH)
"Tentoonstelling"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Exposição"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Utstilling"
#else
"Display"
#endif
	    ":"
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Verbose Radio */
	gslist = NULL;
	pd->det_verbose_radio = w = gtk_radio_button_new_with_label(
	    gslist,
#if defined(PROG_LANGUAGE_SPANISH)
"Detallado"
#elif defined(PROG_LANGUAGE_FRENCH)
"Détaillé"
#elif defined(PROG_LANGUAGE_GERMAN)
"Verbos"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Dettagliato"
#elif defined(PROG_LANGUAGE_DUTCH)
"Verbose"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Verbose"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Verbose"
#else
"Verbose"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "toggled",
	    GTK_SIGNAL_FUNC(EDVPropDlgDetailsVerboseToggledCB), pd
	);
	gtk_widget_show(w);
	gslist = gtk_radio_button_group(GTK_RADIO_BUTTON(w));

	/* Raw Radio */
	pd->det_raw_radio = w = gtk_radio_button_new_with_label(
	    gslist,
#if defined(PROG_LANGUAGE_SPANISH)
"Crudo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Brute"
#elif defined(PROG_LANGUAGE_GERMAN)
"Roh"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Crudo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Rauw"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Cru"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Rå"
#else
"Raw"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "toggled",
	    GTK_SIGNAL_FUNC(EDVPropDlgDetailsRawToggledCB), pd
	);
	gtk_widget_show(w);

	pd->freeze_count++;
	gtk_toggle_button_set_active(
	    GTK_TOGGLE_BUTTON(pd->det_verbose_radio),
	    TRUE
	);
	pd->freeze_count--;
	EDVPropDlgDetailsVerboseToggledCB(
	    pd->det_verbose_radio, pd
	);
}

/*
 *	Recreates the detail labels on the Details Page, the
 *	det_table wll be destroyed and recreated.
 */
static void EDVPropDlgCreateDetailsLabels(
	edv_propdlg_struct *pd, const struct stat *lstat_buf
)
{
	const gint	border_major = 5,
			border_minor = 2;
	gboolean verbose = FALSE;
	edv_date_relativity date_relativity;
	const gchar *date_format;
	mode_t m;
	gchar *s;
	gint row;
	GtkRcStyle *rcstyle, *standard_rcstyle;
	GtkWidget *w, *w2, *parent, *parent2;
	const cfg_item_struct *cfg_list;
	edv_core_struct *core;

	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	cfg_list = core->cfg_list;
	standard_rcstyle = core->standard_rcstyle;

	/* Destroy detail labels table, thus destroying all the detail
	 * labels since they are all child widgets
	 */
	w = pd->det_table;
	if(w != NULL)
	{
	    gtk_widget_destroy(w);
	    pd->det_table = NULL;
	}

	/* Get details parent vbox, if it is not available or the
	 * object stats are not available then do not create detail
	 * labels
	 */
	parent = pd->det_vbox;
	if((parent == NULL) || (lstat_buf == NULL))
	    return;

	/* Get options */
	date_relativity = (edv_date_relativity)EDV_GET_I(
	    EDV_CFG_PARM_DATE_RELATIVITY
	);
	date_format = EDV_GET_S(EDV_CFG_PARM_DATE_FORMAT);

	/* Check if verbose or raw is toggled */
	w = pd->det_verbose_radio;
	if(w != NULL)
	    verbose = GTK_TOGGLE_BUTTON(w)->active;

	/* Get type and permissions */
	m = lstat_buf->st_mode;

	/* Create details table as the parent for detail labels */
	pd->det_table = w = gtk_table_new(14, 2, FALSE);
	gtk_table_set_row_spacings(GTK_TABLE(w), border_minor);
	gtk_table_set_col_spacings(GTK_TABLE(w), border_major);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent = w;


#define ADD_LINE(row,name,value)	{			\
 GtkAttachOptions	x_attach_opt = 0,			\
			y_attach_opt = 0;			\
 guint	x_pad = 0, y_pad = 0;					\
								\
 /* Alignment for name label */					\
 w = gtk_alignment_new(1.0f, 0.5f, 0.0f, 0.0f);			\
 gtk_widget_set_usize(w, 120, -1);				\
 gtk_table_attach(						\
  GTK_TABLE(parent), w,						\
  0, 1, (row), (row) + 1,					\
  x_attach_opt, y_attach_opt, x_pad, y_pad			\
 );								\
 gtk_widget_show(w);						\
 parent2 = w;							\
 /* Name label */						\
 w = gtk_label_new((name));					\
 gtk_container_add(GTK_CONTAINER(parent2), w);			\
 gtk_widget_show(w);						\
								\
 /* Alignment for value */					\
 w = gtk_alignment_new(0.0f, 0.5f, 0.0f, 0.0f);			\
 gtk_widget_set_usize(w, 250, -1);				\
 gtk_table_attach(						\
  GTK_TABLE(parent), w,						\
  1, 2, (row), (row) + 1,					\
  x_attach_opt, y_attach_opt, x_pad, y_pad			\
 );								\
 gtk_widget_show(w);						\
 parent2 = w;							\
 /* Value label */						\
 w2 = w = gtk_label_new((value));				\
 gtk_container_add(GTK_CONTAINER(parent2), w);			\
 gtk_widget_modify_style(w, rcstyle);				\
 gtk_widget_show(w);						\
}

	if(standard_rcstyle != NULL)
	    rcstyle = gtk_rc_style_copy(standard_rcstyle);
	else
	    rcstyle = gtk_rc_style_new();
	g_free(rcstyle->font_name);
	rcstyle->font_name = STRDUP(
"-adobe-courier-medium-r-normal-*-12-*-*-*-*-*-iso8859-1"
	);

	/* Device */
	row = 0;
	if(verbose)
	    s = g_strdup_printf(
		"%ld",
		(gulong)lstat_buf->st_dev
	    );
	else
	    s = g_strdup_printf(
		"0x%.8x",
		(guint)lstat_buf->st_dev
	    );
	ADD_LINE(row, "Device:", s);
	g_free(s);
	pd->det_device_label = w2;

	/* INode */
	row++;
	if(verbose)
	    s = g_strdup_printf(
		"%ld",
		(gulong)lstat_buf->st_ino
	    );
	else
	    s = g_strdup_printf(
		"0x%.8x",
		(guint)lstat_buf->st_ino
	    );
	ADD_LINE(row, "INode:", s);
	g_free(s);
	pd->det_inode_label = w2;

	/* Type */
	row++;
#ifdef S_ISREG
	if(S_ISREG(m))
#else
	if(TRUE)
#endif
	    s = "File";
#ifdef S_ISDIR
	else if(S_ISDIR(m))
	    s = "Directory";
#endif
#ifdef S_ISLNK
	else if(S_ISLNK(m))
	    s = "Link";
#endif
#ifdef S_ISCHR
	else if(S_ISCHR(m))
	    s = "Character Device";
#endif
#ifdef S_ISBLK
	else if(S_ISBLK(m))
	    s = "Block Device";
#endif
#ifdef S_ISFIFO
	else if(S_ISFIFO(m))
	    s = "FIFO Pipe";
#endif
#ifdef S_ISSOCK
	else if(S_ISSOCK(m))
	    s = "Socket";
#endif
	else
	    s = "Unknown";
	ADD_LINE(row, "Type:", s);
	pd->det_type_label = w2;

	/* Permissions */
	row++;
#if defined(S_IRUSR) && defined(S_IWUSR) && defined(S_IXUSR) && defined(S_IRGRP) && defined(S_IWGRP) && defined(S_IXGRP) && defined(S_IROTH) && defined(S_IWOTH) && defined(S_IXOTH) && defined(S_ISUID) && defined(S_ISGID) && defined(S_ISVTX)
	if(verbose)
	    s = g_strdup_printf(
		"%c%c%c%c%c%c%c%c%c",
		(S_IRUSR & m) ? 'r' : '-',
		(S_IWUSR & m) ? 'w' : '-',
		(S_ISUID & m) ? 'S' : ((S_IXUSR & m) ? 'x' : '-'),
		(S_IRGRP & m) ? 'r' : '-',
		(S_IWGRP & m) ? 'w' : '-',
		(S_ISGID & m) ? 'G' : ((S_IXGRP & m) ? 'x' : '-'),
		(S_IROTH & m) ? 'r' : '-',
		(S_IWOTH & m) ? 'w' : '-',
		(S_ISVTX & m) ? 'T' : ((S_IXOTH & m) ? 'x' : '-')
	    );
	else
	    s = g_strdup_printf(
		"0x%.8x",
		(guint32)m
	    );
#else
	s = g_strdup_printf(
	    "0x%.8x",
	    (guint32)m
	);
#endif
	ADD_LINE(row, "Permissions:", s);
	g_free(s);
	pd->det_permissions_label = w2;

	/* Hard Links */
	row++;
	s = g_strdup_printf(
	    "%i", (guint)lstat_buf->st_nlink
	);
	ADD_LINE(row, "Hard Links:", s);
	g_free(s);
	pd->det_hard_links_label = w2;


	/* Owner */
	row++;
	if(verbose)
	{
	    const gchar *name = EDVUIDGetNameFromUID(
		core->uid, core->total_uids,
		lstat_buf->st_uid, NULL
	    );
	    if(!STRISEMPTY(name))
		s = STRDUP(name);
	    else
		s = g_strdup_printf(
		    "%i", (guint)lstat_buf->st_uid
		);
	}
	else
	    s = g_strdup_printf(
		"%i", (guint)lstat_buf->st_uid
	    );
	ADD_LINE(row, "Owner:", s);
	g_free(s);
	pd->det_uid_label = w2;

	/* Group */
	row++;
	if(verbose)
	{
	    const gchar *name = EDVGIDGetNameFromGID(
		core->gid, core->total_gids,
		lstat_buf->st_gid, NULL
	    );
	    if(!STRISEMPTY(name))
		s = STRDUP(name);
	    else
		s = g_strdup_printf(
		    "%i", (guint)lstat_buf->st_gid
		);
	}
	else
	    s = g_strdup_printf(
		"%i", (guint)lstat_buf->st_gid
	    );
	ADD_LINE(row, "Group:", s);
	g_free(s);
	pd->det_gid_label = w2;

	/* Device Type */
	if(TRUE)
	{
	    row++;
	    if(verbose)
		s = g_strdup_printf(
		    "%i", (guint)lstat_buf->st_rdev
		);
	    else
		s = g_strdup_printf(
		    "0x%.8x", (guint)lstat_buf->st_rdev
		);
	    ADD_LINE(row, "Device Type:", s);
	    g_free(s);
	    pd->det_device_type_label = w2;
	}

	/* Size */
	row++;
	s = g_strdup_printf(
	    "%s byte%s",
	    EDVGetObjectSizeStr(core, lstat_buf->st_size),
	    (lstat_buf->st_size == 1) ? "" : "s"
	);
	ADD_LINE(row, "Size:", s);
	g_free(s);
	pd->det_size_label = w2;

	/* IO Block Size */
	row++;
	s = g_strdup_printf(
	    "%s byte%s",
	    EDVGetObjectSizeStr(core, lstat_buf->st_blksize),
	    (lstat_buf->st_blksize == 1) ? "" : "s"
	);
	ADD_LINE(row, "IO Block Size:", s);
	g_free(s);
	pd->det_io_block_size_label = w2;

	/* Blocks Allocated */
	row++;
	s = g_strdup_printf(
	    "%ld", lstat_buf->st_blocks
	);
	ADD_LINE(row, "Blocks Allocated:", s);
	g_free(s);
	pd->det_blocks_label = w2;

	/* Date Access */
	row++;
	if(verbose)
	    s = STRDUP(EDVDateFormatString(
		(gulong)lstat_buf->st_atime,
		date_format, date_relativity
	    ));
	else
	    s = g_strdup_printf(
	    "%ld", (gulong)lstat_buf->st_atime
	);
	ADD_LINE(row, "Last Accessed:", s);
	g_free(s);
	pd->det_access_time_label = w2;

	/* Date Modify */
	row++;
	if(verbose)
	    s = STRDUP(EDVDateFormatString(
		(gulong)lstat_buf->st_mtime,
		date_format, date_relativity
	    ));
	else
	    s = g_strdup_printf(
	    "%ld", (gulong)lstat_buf->st_mtime
	);
	ADD_LINE(row, "Last Modified:", s);
	g_free(s);
	pd->det_modify_time_label = w2;

	/* Date Change */
	row++;
	if(verbose)
	    s = STRDUP(EDVDateFormatString(
		(gulong)lstat_buf->st_ctime,
		date_format, date_relativity
	    ));
	else
	    s = g_strdup_printf(
	    "%ld", (gulong)lstat_buf->st_ctime
	);
	ADD_LINE(row, "Last Changed:", s);
	g_free(s);
	pd->det_change_time_label = w2;



	GTK_RC_STYLE_UNREF(rcstyle)

#undef ADD_LINE
}

/*
 *      Creates the link page parented to the given GtkVBox parent
 *      with respect to the given disk object structure values.
 */
static void EDVPropDlgCreateLinkPage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
)
{
	const gint	border_major = 5,
			border_minor = 2;
	GtkWidget *w, *parent2, *parent3;

	/* Destination frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
	    "El Destino"
#elif defined(PROG_LANGUAGE_FRENCH)
	    "Destination"
#elif defined(PROG_LANGUAGE_GERMAN)
	    "Destinaion"
#elif defined(PROG_LANGUAGE_ITALIAN)
	    "Destinaion"
#elif defined(PROG_LANGUAGE_DUTCH)
	    "Destinaion"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
	    "Destinaion"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
	    "Destinaion"
#else
	    "Destination"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_vbox_new(FALSE, border_minor);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Hbox to hold destination value */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Link connected & broken icons */
	pd->link_connected_icon = w = EDVNewPixmapWidget(
	    core,
	    (guint8 **)icon_link2_20x20_xpm,
	    "icon_link2_20x20_xpm"
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);

	pd->link_broken_icon = w = EDVNewPixmapWidget(
	    core,
	    (guint8 **)icon_link_broken_20x20_xpm,
	    "icon_link_broken_20x20_xpm"
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);

	/* Entry */
	pd->link_dest_entry = w = gtk_entry_new();
	if(obj->link_value != NULL)
	    gtk_entry_set_text(GTK_ENTRY(w), obj->link_value);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "changed",
	    GTK_SIGNAL_FUNC(EDVPropDlgLinkDestinationChangeCB), pd
	);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Entre el valor del destino de la conexión"
#elif defined(PROG_LANGUAGE_FRENCH)
"Entrer la valeur de destination du lien"
#elif defined(PROG_LANGUAGE_GERMAN)
"Tragen Sie das Reiseziel der valueEnter von dem Kettenglied\
 das Reiseziel der Wert von dem Kettenglied ein"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Entrare il valueEnter di destinazione della maglia il valore di\
 destinazione della maglia"
#elif defined(PROG_LANGUAGE_DUTCH)
"Ga de bestemming van de schakel valueenter de bestemming van de\
 schakel waarde binnen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Entre o valueEnter de destino do elo o valor de destino do elo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gå inn i leddets destinasjon valueenter leddets\
 destinasjonsverdi"
#else
"Enter the link's destination value"
#endif
	);
	gtk_widget_show(w);

	/* Link destination properties button */
	pd->link_dest_properties_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_properties2_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVPropDlgDestinationPropertiesCB), pd
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Las Propiedades Del Destino"
#elif defined(PROG_LANGUAGE_FRENCH)
"Propriétés De Destination"
#elif defined(PROG_LANGUAGE_GERMAN)
"Reiseziel Eigentümer"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Le Proprietì Di Destinazione"
#elif defined(PROG_LANGUAGE_DUTCH)
"Bestemming Eigendommen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"As Propriedades De Destino"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Destinasjon Properties"
#else
"Destination Properties"
#endif
	);
	gtk_widget_show(w);


	/* Since we set the link value for the first time we need to
	 * report the change so that the link connected/broken icons are
	 * updated properly
	 */
	EDVPropDlgLinkDestinationChangeCB(
	    pd->link_dest_entry, pd
	);
}

/*
 *      Creates the device page parented to the given GtkVBox parent
 *      with respect to the given disk object structure values.
 *
 *	Note that this is for objects who are directories and are mount
 *	paths for the given device. For device nodes see
 *	EDVPropDlgCreateDeviceNodePage().
 */
static void EDVPropDlgCreateDevicePage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj,
	gint dev_num, edv_device_struct *dev
)
{
	const gint	border_major = 5,
			border_minor = 2;
	gint i;
	gchar *s;
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;
	GtkWidget *w, *parent2, *parent3, *parent4, *parent5;

	if(obj == NULL)
	    return;

	/* Record device reference number */
	pd->dev_num = dev_num;

	/* Get icon for this device (if any) */
	if(TRUE)
	{
	    for(i = 0; i < EDV_DEVICE_TOTAL_ICON_STATES; i++)
	    {
		if(pixmap != NULL)
		    break;

		pixmap = dev->medium_pixmap[i];
		mask = dev->medium_mask[i];
	    }
	    for(i = 0; i < EDV_DEVICE_TOTAL_ICON_STATES; i++)
	    {
		if(pixmap != NULL)
		    break;

		pixmap = dev->large_pixmap[i];
		mask = dev->large_mask[i];
	    }
	    for(i = 0; i < EDV_DEVICE_TOTAL_ICON_STATES; i++)
	    {
		if(pixmap != NULL)
		    break;

		pixmap = dev->small_pixmap[i];
		mask = dev->small_mask[i];
	    }
	}


	/* Identification frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Identificación"
#elif defined(PROG_LANGUAGE_FRENCH)
"Identification"
#elif defined(PROG_LANGUAGE_GERMAN)
"Identifikation"
#elif defined(PROG_LANGUAGE_ITALIAN)
"L'Identificazione"
#elif defined(PROG_LANGUAGE_DUTCH)
"Identificatie"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Identificação"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Identification"
#else
"Identification"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_vbox_new(FALSE, border_minor);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Device path, mount path, and fs type hbox */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Icon */
	if(pixmap != NULL)
	{
	    w = gtk_vbox_new(TRUE, border_minor);
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent4 = w;

	    pd->dev_icon_pm = w = gtk_pixmap_new(pixmap, mask);
	    gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, FALSE, 0);
	    gtk_widget_show(w);
	}

	/* Device path and mount path vbox */
	w = gtk_vbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;

	/* Device path hbox and label */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;

	if(dev->name != NULL)
	    s = g_strdup_printf("%s (%s)",
		dev->name, 
		(dev->device_path != NULL) ?
		    dev->device_path : ""
	    );
	else
	    s = STRDUP(
		(dev->device_path != NULL) ?
		    dev->device_path : ""
	    );
	pd->dev_device_path_label = w = gtk_label_new(s);
	g_free(s);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Mount path hbox and label */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent5 = w;
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Monte Sendero:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Point de montage:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Stellen Sie Pfad Auf:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Montare Il Sentiero:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Bestijg Pad:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Monte Caminho:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Monter Path:"
#else
"Mount Path:"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	pd->dev_mount_path_label = w = gtk_label_new(
	    (dev->mount_path != NULL) ?
		dev->mount_path : ""
	);
	gtk_box_pack_start(GTK_BOX(parent5), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Filesystem type hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Archive El Tipo De Sistema:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Type du Système de fichier:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Dateisystem Typ:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Schedare Il Tipo Di Sistema:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Archiveer Systeem Type:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Arquive Tipo De Sistema:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Arkiver System Type:"
#else
"File System Type:"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	w = gtk_label_new(
	    EDVDeviceGetFSNameFromType(dev->fs_type)
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);


	/* Usage frame */
	pd->dev_usage_frame = w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Uso"
#elif defined(PROG_LANGUAGE_FRENCH)
"Usage"
#elif defined(PROG_LANGUAGE_GERMAN)
"Brauch"
#elif defined(PROG_LANGUAGE_ITALIAN)
"L'Uso"
#elif defined(PROG_LANGUAGE_DUTCH)
"Gebruik"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Uso"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Praksis"
#else
"Usage"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	/* Create the usage widgets */
	pd->dev_usage_vbox = NULL;
	EDVPropDlgCreateDeviceUsage(pd, dev);


	/* Tools frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Mantenga"
#elif defined(PROG_LANGUAGE_FRENCH)
"Maintenance"
#elif defined(PROG_LANGUAGE_GERMAN)
"Maintainance"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Maintainance"
#elif defined(PROG_LANGUAGE_DUTCH)
"Maintainance"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Maintainance"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Maintainance"
#else
"Maintainance"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_hbox_new(TRUE, 0);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;


	/* File system check button */
	pd->dev_check_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_fsck_48x48_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVPropDlgRunCheckCB), pd
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Archive Cheque De Sistema"
#elif defined(PROG_LANGUAGE_FRENCH)
"Controler le système de fichier"
#elif defined(PROG_LANGUAGE_GERMAN)
"Dateisystem Kontrolle"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Schedare L'Assegno Di Sistema"
#elif defined(PROG_LANGUAGE_DUTCH)
"Archiveer Systeemcontrole"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Arquive Sistema Verificar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Arkiver Systemkontroll"
#else
"File System Check"
#endif
	);
	gtk_widget_show(w);
	if(STRISEMPTY(dev->command_check))
	    GTK_WIDGET_SET_SENSITIVE(w, FALSE)


	/* Tools button */
	pd->dev_tools_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_tools_48x48_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVPropDlgRunToolsCB), pd
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Las Herramientas"
#elif defined(PROG_LANGUAGE_FRENCH)
"Outils"
#elif defined(PROG_LANGUAGE_GERMAN)
"Werkzeuge"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Gli Attrezzi"
#elif defined(PROG_LANGUAGE_DUTCH)
"Werktuigen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"As Ferramentas"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Redskaper"
#else
"Tools"
#endif
	);
	gtk_widget_show(w);
	if(STRISEMPTY(dev->command_tools))
	    GTK_WIDGET_SET_SENSITIVE(w, FALSE)


	/* Format button */
	pd->dev_format_btn = w = GUIButtonPixmap(
	    (guint8 **)icon_floppy_48x48_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(EDVPropDlgRunFormatCB), pd
	);
	GUISetWidgetTip(
	    w,
#if defined(PROG_LANGUAGE_SPANISH)
"Formatear Medios"
#elif defined(PROG_LANGUAGE_FRENCH)
"Formatter"
#elif defined(PROG_LANGUAGE_GERMAN)
"Formatieren Sie Medien"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Stampa Di Formato"
#elif defined(PROG_LANGUAGE_DUTCH)
"Formatteer Media"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"A Imprensa De Formato"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Formater Media"
#else
"Format Media"
#endif
	);
	gtk_widget_show(w);
	if(STRISEMPTY(dev->command_format))
	    GTK_WIDGET_SET_SENSITIVE(w, FALSE)
}

/*
 *	Recreates the device usage widgets on the Devices Page.
 */
static void EDVPropDlgCreateDeviceUsage(
	edv_propdlg_struct *pd, edv_device_struct *dev
)
{
	const gint	border_major = 5,
			border_minor = 2;
	GtkRcStyle *standard_rcstyle;
	GtkWidget *w, *parent, *parent2, *parent3;
	edv_core_struct *core = pd->core;


	/* Destroy any existing usage widgets */
	PieChartDelete(pd->dev_usage_pc);
	pd->dev_usage_pc = NULL;
	GTK_WIDGET_DESTROY(pd->dev_mount_btn)
	pd->dev_mount_btn = NULL;
	GTK_WIDGET_DESTROY(pd->dev_eject_btn)
	pd->dev_eject_btn = NULL;
	GTK_WIDGET_DESTROY(pd->dev_usage_vbox)
	pd->dev_usage_vbox = NULL;


	standard_rcstyle = core->standard_rcstyle;

	/* Get parent for usage widgets */
	parent = pd->dev_usage_frame;

	/* Vbox for usage widgets */
	pd->dev_usage_vbox = w = gtk_vbox_new(FALSE, border_major);
	gtk_container_add(GTK_CONTAINER(parent), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent = w;

	/* Create the Usage Pie Chart if mounted */
	if(EDV_DEVICE_IS_MOUNTED(dev))
	{
	    const gulong	adj_division = 10l,
				total_kb = dev->blocks_total,
				free_kb = dev->blocks_free,
				available_kb = dev->blocks_available,
				used_kb = MAX(total_kb - free_kb, 0l);
	    gchar *ss_kb, *ss_mb, *text, *text2;
	    GdkColor c;
	    GtkAdjustment *adj;
	    pie_chart_struct *pc;

	    /* Hbox for multiple columns */
	    w = gtk_hbox_new(FALSE, 0);
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent2 = w;

	    /* Hbox to center the Usage Pie Chart */
	    w = gtk_hbox_new(TRUE, 0);
	    gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	    gtk_widget_show(w);
	    parent3 = w;


	    adj = (GtkAdjustment *)gtk_adjustment_new(
		0.0f, 0.0f,
		(gfloat)(total_kb / adj_division),
		0.0f, 0.0f, 0.0f
	    );
	    GDK_COLOR_SET_COEFF(&c, 0.0f, 0.0f, 1.0f)
	    ss_kb = STRDUP(
		EDVGetObjectSizeStr(core, total_kb)
	    );
	    ss_mb = STRDUP(
		EDVGetObjectSizeStr(core, total_kb / 1000l)
	    );
	    text = g_strdup_printf(
		"%s: %s kb (%s mb)",
#if defined(PROG_LANGUAGE_SPANISH)
"La Capacidad Total"
#elif defined(PROG_LANGUAGE_FRENCH)
"Capacité Totale"
#elif defined(PROG_LANGUAGE_GERMAN)
"Gesamte Kapazität"
#elif defined(PROG_LANGUAGE_ITALIAN)
"La Capacità Totale"
#elif defined(PROG_LANGUAGE_DUTCH)
"Totale Capaciteit"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Capacidade Total"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Total Capacity"
#else
"Total Capacity"
#endif
		, ss_kb, ss_mb   
	    );
	    g_free(ss_kb);
	    g_free(ss_mb);

	    ss_kb = STRDUP(
		EDVGetObjectSizeStr(core, free_kb)
	    );
	    ss_mb = STRDUP(
		EDVGetObjectSizeStr(core, free_kb / 1000l)
	    );
	    text2 = g_strdup_printf(
		"%s kb (%s mb)",
		ss_kb, ss_mb
	    );
	    g_free(ss_kb);
	    g_free(ss_mb);

	    pd->dev_usage_pc = pc = PieChartNew(
		adj, &c, 110, 70,
		NULL, text,
#if defined(PROG_LANGUAGE_SPANISH)
"Libre:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Libre:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Frei:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Libero:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Vrij:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Livre:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Fri:"
#else
"Free:"
#endif
		, text2
	    );
	    GTK_OBJECT_UNREF(adj)
	    g_free(text);
	    g_free(text2);
	    w = pc->toplevel;
	    gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	    gtk_widget_show(w); 

	    GDK_COLOR_SET_COEFF(&c, 0.0f, 1.0f, 1.0f)
	    adj = (GtkAdjustment *)gtk_adjustment_new(
		0.0f, 0.0f,
		(gfloat)(available_kb / adj_division),
		0.0f, 0.0f, 0.0f
	    );
	    ss_kb = STRDUP(
		EDVGetObjectSizeStr(core, available_kb)
	    );
	    ss_mb = STRDUP(
		EDVGetObjectSizeStr(core, available_kb / 1000l)
	    );
	    text = g_strdup_printf(
		"%s kb (%s mb)",
		ss_kb, ss_mb
	    );
	    g_free(ss_kb);
	    g_free(ss_mb);
	    PieChartValueAdd(
		pc, adj, &c,
#if defined(PROG_LANGUAGE_SPANISH)
"Libre & Disponible:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Libre & Disponible:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Frei & Verfügbar:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Libero & Disponibile:"                           
#elif defined(PROG_LANGUAGE_DUTCH)
"Vrij & Verkrijgbare:"              
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Livre & Disponível:"            
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Fri & Available:"             
#else           
"Free & Available:"         
#endif
		, text 
	    );
	    GTK_OBJECT_UNREF(adj)
	    g_free(text);

	    GDK_COLOR_SET_COEFF(&c, 1.0f, 0.0f, 1.0f)
	    adj = (GtkAdjustment *)gtk_adjustment_new(
		0.0f, 0.0f,
		(gfloat)(used_kb / adj_division),
		0.0f, 0.0f, 0.0f
	    );
	    ss_kb = STRDUP(
		EDVGetObjectSizeStr(core, used_kb)
	    );
	    ss_mb = STRDUP(
		EDVGetObjectSizeStr(core, used_kb / 1000l)
	    );
	    text = g_strdup_printf(
		"%s kb (%s mb)",
		ss_kb, ss_mb
	    );
	    g_free(ss_kb);
	    g_free(ss_mb);
	    PieChartValueAdd(
		pc, adj, &c,
#if defined(PROG_LANGUAGE_SPANISH)
"Usado:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Utilisé:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Benutzt:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Usato:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Gebruikt:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Usado:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Brukt:"
#else           
"Used:"
#endif
		, text 
	    );
	    GTK_OBJECT_UNREF(adj);
	    g_free(text);


	    /* Right column vbox for buttons */
	    w = gtk_vbox_new(FALSE, border_minor);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent3 = w;

	    /* Unmount button */
	    pd->dev_mount_btn = w = GUIButtonPixmap(
		(guint8 **)icon_unmount_20x20_xpm
	    );
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_signal_connect(
		GTK_OBJECT(w), "clicked",
		GTK_SIGNAL_FUNC(EDVPropDlgMountCB), pd
	    );
	    GUISetWidgetTip(w, "Unmount");
	    GTK_WIDGET_SET_SENSITIVE(w, !EDV_DEVICE_IS_NO_UNMOUNT(dev));
	    if(standard_rcstyle != NULL)
		gtk_widget_modify_style_recursive(w, standard_rcstyle);
	    gtk_widget_show(w);

	    /* Eject button */
	    pd->dev_eject_btn = w = GUIButtonPixmap(
		(guint8 **)icon_eject_20x20_xpm
	    );
	    gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	    gtk_signal_connect(
		GTK_OBJECT(w), "clicked",
		GTK_SIGNAL_FUNC(EDVPropDlgEjectCB), pd
	    );
	    GUISetWidgetTip(w, "Eject");
	    GTK_WIDGET_SET_SENSITIVE(
		w,
		!STRISEMPTY(dev->command_eject) ? TRUE : FALSE
	    );
	    if(standard_rcstyle != NULL)
		gtk_widget_modify_style_recursive(w, standard_rcstyle);
	    gtk_widget_show(w);
	}
	else
	{
	    GtkRcStyle *rcstyle;

	    w = gtk_hbox_new(TRUE, 0);
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent2 = w;

	    /* Device not mounted label */
	    w = gtk_label_new("(Device Not Mounted)");
	    gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
	    rcstyle = gtk_rc_style_new();
	    rcstyle->font_name = STRDUP(
"-adobe-helvetica-bold-r-normal-*-14-*-*-*-*-*-iso8859-1"   
	    );
	    gtk_widget_modify_style(w, rcstyle);
	    gtk_widget_show(w);
	    GTK_RC_STYLE_UNREF(rcstyle);

	    w = gtk_hbox_new(TRUE, 0);
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	    parent2 = w;

	    /* Mount button */
	    pd->dev_mount_btn = w = GUIButtonPixmapLabelH(
		(guint8 **)icon_mount_20x20_xpm, "Mount", NULL
	    );
	    gtk_widget_set_usize(
		w,
		GUI_BUTTON_HLABEL_WIDTH, GUI_BUTTON_HLABEL_HEIGHT
	    );
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_signal_connect(
		GTK_OBJECT(w), "clicked",
		GTK_SIGNAL_FUNC(EDVPropDlgMountCB), pd
	    );
	    GUISetWidgetTip(w, "Click to mount the device");
	    GTK_WIDGET_SET_SENSITIVE(w, !EDV_DEVICE_IS_NO_UNMOUNT(dev))
	    if(standard_rcstyle != NULL)
		gtk_widget_modify_style_recursive(w, standard_rcstyle);
	    gtk_widget_show(w);

	    /* Eject button */
	    pd->dev_eject_btn = w = GUIButtonPixmapLabelH(
		(guint8 **)icon_eject_20x20_xpm, "Eject", NULL
	    );
	    gtk_widget_set_usize(
		w,
		GUI_BUTTON_HLABEL_WIDTH, GUI_BUTTON_HLABEL_HEIGHT
	    );
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_signal_connect(
		GTK_OBJECT(w), "clicked",
		GTK_SIGNAL_FUNC(EDVPropDlgEjectCB), pd
	    );
	    GUISetWidgetTip(w, "Click to eject the media from the device");
	    GTK_WIDGET_SET_SENSITIVE(
		w,
		!STRISEMPTY(dev->command_eject) ? TRUE : FALSE
	    );
	    if(standard_rcstyle != NULL)
		gtk_widget_modify_style_recursive(w, standard_rcstyle);
	    gtk_widget_show(w);
	}
}

/*
 *      Creates the device node page parented to the given GtkVBox parent
 *      with respect to the given disk object structure values.
 */
static void EDVPropDlgCreateDeviceNodePage(
	edv_propdlg_struct *pd, GtkWidget *parent,
	edv_core_struct *core, edv_object_struct *obj
)
{
	const gint	border_major = 5,
			border_minor = 2;
	gint major, minor;
	GtkWidget *w, *parent2, *parent3;
	gchar num_str[80];


	/* Get device node's major and minor numbers */
	EDVGetDeviceNumbers(
	    (dev_t)obj->device_type, &major, &minor
	);

	/* Device numbers frame */
	w = gtk_frame_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Artefacto Numeros"
#elif defined(PROG_LANGUAGE_FRENCH)
"Numéro de composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Vorrichtung Zählt"
#elif defined(PROG_LANGUAGE_ITALIAN)
"I Numeri Di Congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Apparaat Nummert"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Artifício Numera"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Innretning Numbers"
#else
"Device Numbers"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_widget_show(w);
	parent2 = w;

	w = gtk_hbox_new(FALSE, border_major);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_widget_show(w);
	parent2 = w;

	/* Major number hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Label */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Mayor:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Majeur:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Major:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Maggiore:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Majoor:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Importante:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Major:"
#else
"Major:"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	/* Entry */
	pd->dev_node_major_entry = w = gtk_entry_new();
	g_snprintf(
	    num_str, sizeof(num_str),
	    "%i", major
	);
	gtk_entry_set_text(GTK_ENTRY(w), num_str);
	gtk_widget_set_usize(w, 80, -1);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	gtk_widget_show(w);

	/* Minor number hbox */
	w = gtk_hbox_new(FALSE, border_minor);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Label */
	w = gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Menor:"
#elif defined(PROG_LANGUAGE_FRENCH)
"Mineur:"
#elif defined(PROG_LANGUAGE_GERMAN)
"Minderjähriger:"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Minore:"
#elif defined(PROG_LANGUAGE_DUTCH)
"Minderjarige:"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Menor:"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Mindreårig:"
#else
"Minor:"
#endif
	);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	/* Entry */
	pd->dev_node_minor_entry = w = gtk_entry_new();
	g_snprintf(
	    num_str, sizeof(num_str),
	    "%i", minor
	);
	gtk_entry_set_text(GTK_ENTRY(w), num_str);
	gtk_widget_set_usize(w, 80, -1);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	EDVPropDlgSetWidgetChangedSignal(pd, w);
	gtk_widget_show(w);


}


/*
 *	Object added callback.
 */
void EDVPropDlgObjectAddedNotifyCB(
	edv_propdlg_struct *pd, const gchar *path,
	const struct stat *lstat_buf      
)
{
	edv_core_struct *core;

	if((pd == NULL) || STRISEMPTY(path))
	    return;

	core = pd->core;
	if(STRISEMPTY(pd->path) || (core == NULL))
	    return;

	/* Update device usage */
	if(pd->dev_usage_frame != NULL)
	{
	    gint dev_num = pd->dev_num;
	    edv_device_struct *dev = ((dev_num >= 0) &&
		(dev_num < core->total_devices)) ?
		core->device[dev_num] : NULL;
	    if((dev != NULL) ? !STRISEMPTY(dev->mount_path) : FALSE)
	    {
		if(strpfx(path, dev->mount_path))
		{
		    EDVPropDlgCreateDeviceUsage(pd, dev);
		}
	    }
	}

	/* Is the added object the object that we are displaying? */
	if(!strcmp(path, pd->path))
	{
	    /* Update details labels */
	    EDVPropDlgCreateDetailsLabels(pd, lstat_buf);

	    EDVPropDlgUpdateMenus(pd);
	}
}

/*
 *	Object modified callback.
 */
void EDVPropDlgObjectModifiedNotifyCB(
	edv_propdlg_struct *pd,
	const gchar *path, const gchar *new_path,
	const struct stat *lstat_buf
)
{
	edv_core_struct *core;

	if((pd == NULL) || STRISEMPTY(path))
	    return;

	if(new_path == NULL)
	    new_path = path;

	core = pd->core;
	if(STRISEMPTY(pd->path) || (core == NULL))
	    return;

	/* Update device usage */
	if(pd->dev_usage_frame != NULL)
	{
	    gint dev_num = pd->dev_num;
	    edv_device_struct *dev = ((dev_num >= 0) &&
		(dev_num < core->total_devices)) ?
		core->device[dev_num] : NULL;
	    if((dev != NULL) ? !STRISEMPTY(dev->mount_path) : FALSE)
	    {
		if(strpfx(path, dev->mount_path) ||
		   strpfx(new_path, dev->mount_path)
		)
		{
		    EDVPropDlgCreateDeviceUsage(pd, dev);
		}
	    }
	}

	/* Is the modified object the object that we are displaying? */
	if(!strcmp(path, pd->path))
	{
	    /* Update details labels */
	    EDVPropDlgCreateDetailsLabels(pd, lstat_buf);

	    EDVPropDlgUpdateMenus(pd);
	}
}

/*
 *	Object removed callback.
 */
void EDVPropDlgObjectRemovedNotifyCB(
	edv_propdlg_struct *pd, const gchar *path
)
{
	edv_core_struct *core;

	if((pd == NULL) || STRISEMPTY(path))
	    return;

	core = pd->core;
	if(STRISEMPTY(pd->path) || (core == NULL))
	    return;

	/* Update device usage */
	if(pd->dev_usage_frame != NULL)
	{
	    gint dev_num = pd->dev_num;
	    edv_device_struct *dev = ((dev_num >= 0) &&
		(dev_num < core->total_devices)) ?
		core->device[dev_num] : NULL;
	    if((dev != NULL) ? !STRISEMPTY(dev->mount_path) : FALSE)
	    {
		if(strpfx(path, dev->mount_path))
		{
		    EDVPropDlgCreateDeviceUsage(pd, dev);
		}
	    }
	}

	/* Is the removed object the object that we are displaying? */
	if(!strcmp(path, pd->path))
	{
	    /* Unmap the dialog since the object no longer exists */
	    EDVPropDlgUnmap(pd);
	}
}

/*
 *      Mount/unmount notify callback.
 */
void EDVPropDlgMountNotifyCB(
	edv_propdlg_struct *pd, 
	gint dev_num, edv_device_struct *dev,
	gboolean is_mounted
)
{
	if(pd == NULL)
	    return;

	/* Update device usage */
	if((pd->dev_usage_frame != NULL) && (dev_num == pd->dev_num))
	{
	    if(dev != NULL)
		EDVPropDlgCreateDeviceUsage(pd, dev);
	}
}

/*
 *	Write protect changed callback.
 */
void EDVPropDlgWriteProtectChangedCB(edv_propdlg_struct *pd, gboolean state)
{
	if(pd == NULL)
	    return;

	EDVPropDlgUpdateMenus(pd);
}

/*
 *	Reconfigured notify callback.
 */
void EDVPropDlgReconfiguredNotifyCB(edv_propdlg_struct *pd)
{
	gint lstat_status;
	const gchar *path;
	struct stat lstat_buf;
	GtkRcStyle *standard_rcstyle, *lists_rcstyle;
	GtkWidget *w;
	edv_core_struct *core;

	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	standard_rcstyle = core->standard_rcstyle;
	lists_rcstyle = core->lists_rcstyle;

	/* Get new stats of object */
	path = pd->path;
	lstat_status = (!STRISEMPTY(path)) ?
	    lstat((const char *)path, &lstat_buf) : -1;

	/* Recreate details labels */
	if(!lstat_status)
	    EDVPropDlgCreateDetailsLabels(pd, &lstat_buf);

	/* Update RC styles */
	w = pd->toplevel;
	if((w != NULL) && (standard_rcstyle != NULL))
	    gtk_widget_modify_style_recursive(
		w, standard_rcstyle
	    );
	w = MenuButtonGetMenu(pd->gen_date_touch_btn);
	if((w != NULL) && (standard_rcstyle != NULL))
	    gtk_widget_modify_style_recursive(
		w, standard_rcstyle
	    );

	EDVPropDlgUpdateMenus(pd);
}


/*
 *	Creates a new Properties Dialog.
 */
edv_propdlg_struct *EDVPropDlgNew(
	edv_core_struct *core, edv_object_struct *obj
)
{
	const gint border_major = 5;
	gint dev_num;
	edv_device_struct *dev;
	GdkWindow *window;
	GtkAccelGroup *accelgrp;
	GtkStyle *style;
	GtkRcStyle	*standard_rcstyle,
			*lists_rcstyle;
	GtkWidget *w, *parent, *parent2;
	const cfg_item_struct *cfg_list;
	edv_object_type type;
	edv_propdlg_struct *pd = EDV_PROPDLG(
	    g_malloc0(sizeof(edv_propdlg_struct))
	);
	if(pd == NULL)
	    return(NULL);

	if(core == NULL)
	{
	    g_free(pd);
	    return(NULL);
	}

	cfg_list = core->cfg_list;

	standard_rcstyle = core->standard_rcstyle;
	lists_rcstyle = core->lists_rcstyle;

	pd->accelgrp = accelgrp = gtk_accel_group_new();
	pd->processing = FALSE;
	pd->busy_count = 0;
	pd->freeze_count = 0;
	pd->core = core;

	pd->path = NULL;
	pd->type = type = EDV_OBJECT_TYPE_UNKNOWN;
	pd->title = STRDUP(PROPDLG_TITLE);
	pd->has_changes = FALSE;
	pd->obj_op_dlg = NULL;

	/* Get the object's path and set the dialog's title */
	if(obj != NULL)
	{
	    g_free(pd->path);
	    pd->path = STRDUP(obj->full_path);

	    pd->type = type = obj->type;

	    if(!STRISEMPTY(obj->name))
	    {
		g_free(pd->title);
		pd->title = g_strdup_printf(
		    PROPDLG_TITLE ": %s",
		    obj->name
		);
	    }
	}

	/* Refresh all device mount states and device stats, then get
	 * device path or mount path that matches the given disk
	 * object's path
	 */
	EDVDevicesListUpdateMountStates(
	    core->device, core->total_devices
	);
	EDVDevicesListUpdateStats(
	    core->device, core->total_devices
	);
	dev = EDVDevicesListMatchMountPath(
	   core->device, core->total_devices,
	   &dev_num, pd->path
	);
	if(dev == NULL)
	   dev = EDVDevicesListMatchDevicePath(
		core->device, core->total_devices,
		&dev_num, pd->path
	   );


	/* Begin creating widgets */

	/* Toplevel */
	pd->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
	gtk_widget_set_usize(w, PROPDLG_WIDTH, PROPDLG_HEIGHT);
	gtk_window_set_wmclass(
	    GTK_WINDOW(w), "propertiesdialog", PROG_NAME
	);
	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
	    );
	    GUISetWMIcon(window, (guint8 **)icon_properties2_48x48_xpm);
	}
	gtk_widget_add_events( 
	    w,
	    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "delete_event",
	    GTK_SIGNAL_FUNC(EDVPropDlgDeleteEventCB), pd
	);
	gtk_window_add_accel_group(GTK_WINDOW(w), accelgrp);
	style = gtk_widget_get_style(w);
	parent = w;


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


	/* Vbox for main notebook */
	w = gtk_vbox_new(FALSE, 0);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Main notebook */
	pd->notebook = w = gtk_notebook_new();
	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(w), GTK_POS_TOP);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_notebook_set_scrollable(GTK_NOTEBOOK(w), TRUE);
	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(w), TRUE);
	gtk_notebook_set_show_border(GTK_NOTEBOOK(w), TRUE);
/*      gtk_notebook_set_page(GTK_NOTEBOOK(w), 0); */
	gtk_signal_connect(
	    GTK_OBJECT(w), "switch_page",
	    GTK_SIGNAL_FUNC(EDVPropDlgSwitchPageCB), pd
	);
	gtk_widget_show(w);
	parent2 = w;


	/* Begin creating pages on notebook */

	/* Create General Page (always the first page) */
	w = gtk_vbox_new(FALSE, border_major);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_notebook_append_page(
	    GTK_NOTEBOOK(parent2), w, gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"General"
#elif defined(PROG_LANGUAGE_FRENCH)
"Général"
#elif defined(PROG_LANGUAGE_GERMAN)
"General"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Generale"
#elif defined(PROG_LANGUAGE_DUTCH)
"Generaal"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O General"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"General"
#else
"General"
#endif
	    )
	);
	gtk_widget_show(w);
	EDVPropDlgCreateGeneralPage(
	    pd, w, core, obj
	);


	/* Is the object a link? */
	if(type == EDV_OBJECT_TYPE_LINK)
	{
	    /* Create Link Page */
	    w = gtk_vbox_new(FALSE, border_major);
	    gtk_container_border_width(GTK_CONTAINER(w), border_major);
	    gtk_notebook_append_page(
		GTK_NOTEBOOK(parent2), w, gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Enlace"
#elif defined(PROG_LANGUAGE_FRENCH)
"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
		)
	    );
	    gtk_widget_show(w);
	    EDVPropDlgCreateLinkPage(
		pd, w, core, obj
	    );
	}


	/* Check if a device structure for this object was matched
	 * (if this object is a mount point for a device)
	 */
	if(dev != NULL)
	{
	    /* Create Device Page */
	    w = gtk_vbox_new(FALSE, border_major);
	    gtk_container_border_width(GTK_CONTAINER(w), border_major);
	    gtk_notebook_append_page(
		GTK_NOTEBOOK(parent2), w, gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Artefacto"
#elif defined(PROG_LANGUAGE_FRENCH)
"Composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Vorrichtung"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Apparaat"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"O Artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Innretning"
#else
"Device"
#endif
		)
	    );
	    gtk_widget_show(w);
	    EDVPropDlgCreateDevicePage(
		pd, w, core, obj, dev_num, dev
	    );
	}


	/* Check if object is a device node */
	if((type == EDV_OBJECT_TYPE_DEVICE_BLOCK) ||
	   (type == EDV_OBJECT_TYPE_DEVICE_CHARACTER)
	)
	{
	    /* Create Device Node Page */
	    w = gtk_vbox_new(FALSE, border_major);
	    gtk_container_border_width(GTK_CONTAINER(w), border_major);
	    gtk_notebook_append_page(
		GTK_NOTEBOOK(parent2), w, gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"El Artefacto Puerto"
#elif defined(PROG_LANGUAGE_FRENCH)
"Port du composant"
#elif defined(PROG_LANGUAGE_GERMAN)
"Geräteknoten"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Il Nodo Di Congegno"
#elif defined(PROG_LANGUAGE_DUTCH)
"Apparaat Knoest"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Node De Artifício"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Innretning Node"
#else
"Device Node"
#endif
		)
	    );
	    gtk_widget_show(w);
	    EDVPropDlgCreateDeviceNodePage(
		pd, w, core, obj
	    );
	}

	/* Create Details Page */
	w = gtk_vbox_new(FALSE, border_major);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_notebook_append_page(
	    GTK_NOTEBOOK(parent2), w, gtk_label_new(
#if defined(PROG_LANGUAGE_SPANISH)
"Los Detalles"
#elif defined(PROG_LANGUAGE_FRENCH)
"Détails"
#elif defined(PROG_LANGUAGE_GERMAN)
"Statistik"
#elif defined(PROG_LANGUAGE_ITALIAN)
"I Dettagli"
#elif defined(PROG_LANGUAGE_DUTCH)
"Statistieken"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Os Detalhes"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Detaljer"
#else
"Details"
#endif
	    )
	);
	gtk_widget_show(w);
	EDVPropDlgCreateDetailsPage(
	    pd, w, core, obj
	);


	/* 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;

	/* OK button */
	pd->ok_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_ok_20x20_xpm, "OK", 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(EDVPropDlgOKCB), pd
	);
	gtk_accel_group_add(
	    accelgrp, GDK_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_o);
	gtk_widget_show(w);

	/* Apply button */
	pd->apply_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_select_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Aplique"
#elif defined(PROG_LANGUAGE_FRENCH)
"Appliquer"
#elif defined(PROG_LANGUAGE_GERMAN)
"Verwenden"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Applicare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Toepas"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Aplique"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Gjeld"
#else
"Apply"
#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(EDVPropDlgApplyCB), pd
	);
	gtk_accel_group_add(
	    accelgrp, GDK_a, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE,
	    GTK_OBJECT(w), "clicked"
	);
	GUIButtonLabelUnderline(w, GDK_a);
	gtk_widget_show(w);

	/* Cancel button */
	pd->cancel_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_cancel_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Cancele"
#elif defined(PROG_LANGUAGE_FRENCH)
"Annuler"
#elif defined(PROG_LANGUAGE_GERMAN)
"Heben"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Annullare"
#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(EDVPropDlgCancelCB), pd
	);
	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);

	/* Close button */
	pd->close_btn = w = GUIButtonPixmapLabelH(
	    (guint8 **)icon_close_20x20_xpm,
#if defined(PROG_LANGUAGE_SPANISH)
"Cierre"
#elif defined(PROG_LANGUAGE_FRENCH)
"Quitter"
#elif defined(PROG_LANGUAGE_GERMAN)
"Nah"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Vicino"
#elif defined(PROG_LANGUAGE_DUTCH)
"Einde"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Próximo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Nær"
#else
"Close"
#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(EDVPropDlgCancelCB), pd
	);
	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);


	/* Set initial RC styles */
	if(standard_rcstyle != NULL)
	    gtk_widget_modify_style_recursive(
		pd->toplevel, standard_rcstyle
	    );
	w = MenuButtonGetMenu(pd->gen_date_touch_btn);
	if((w != NULL) && (standard_rcstyle != NULL))
	    gtk_widget_modify_style_recursive(
		w, standard_rcstyle
	    );


	EDVPropDlgUpdateMenus(pd);


	return(pd);
}


/*
 *	Sets the Properties Dialog has changes marker.
 */
void EDVPropDlgResetHasChanges(
	edv_propdlg_struct *pd, gboolean has_changes
)
{
	if(pd == NULL)
	    return;

	if(pd->has_changes == has_changes)
	    return;

	pd->has_changes = has_changes;
	EDVPropDlgUpdateMenus(pd);
}

/*
 *	Updates the Properties Dialog's widgets to reflect current
 *	values.
 */
void EDVPropDlgUpdateMenus(edv_propdlg_struct *pd)
{
	gboolean	sensitive,
			write_protect,
			has_changes;
	edv_date_relativity date_relativity;
	const gchar *date_format, *path;
	gint lstat_status;
	struct stat lstat_buf;
	const cfg_item_struct *cfg_list;
	edv_core_struct *core;

	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

	cfg_list = core->cfg_list;

	/* Get configuration */
	write_protect = EDV_GET_B(EDV_CFG_PARM_WRITE_PROTECT);
	date_relativity = (edv_date_relativity)EDV_GET_I(
	    EDV_CFG_PARM_DATE_RELATIVITY
	);
	date_format = EDV_GET_S(EDV_CFG_PARM_DATE_FORMAT);

	/* Get Properties Dialog values */
	path = pd->path;
	has_changes = pd->has_changes;

	/* Get object stats */
	lstat_status = (!STRISEMPTY(path)) ?
	    lstat((const char *)path, &lstat_buf) : -1;

#define MAP(w)			\
{ if((w) != NULL) { gtk_widget_show(w); } }
#define UNMAP(w)		\
{ if((w) != NULL) { gtk_widget_hide(w); } }

	/* Title */
	if(!STRISEMPTY(pd->title))
	{
	    GtkWidget *w = pd->toplevel;
	    gchar *title = g_strdup_printf(
		"%s%s",
		pd->title,
		(has_changes) ? " (*)" : ""
	    );
	    gtk_window_set_title(GTK_WINDOW(w), title);
	    g_free(title);
	}


	/* Size */
	if(!lstat_status)
	{
	    GtkWidget *w = pd->gen_size_label;
	    if(w != NULL)
		gtk_label_set_text(
		    GTK_LABEL(w),
		    EDVGetObjectSizeStr(core, (gulong)lstat_buf.st_size)
		);
	}



	/* Touch Button */
	sensitive = !write_protect;
	GTK_WIDGET_SET_SENSITIVE(pd->gen_date_touch_btn, sensitive)

	/* Time Stamp Labels */
	if(!lstat_status)
	{
	    GtkWidget *w = pd->gen_date_access_label;
	    if(w != NULL)
		gtk_label_set_text(
		    GTK_LABEL(w),
		    EDVDateFormatString(
			(gulong)lstat_buf.st_atime,
			date_format, date_relativity
		    )
		);
	    w = pd->gen_date_modify_label;
	    if(w != NULL)
		gtk_label_set_text(
		    GTK_LABEL(w),
		    EDVDateFormatString(
			(gulong)lstat_buf.st_mtime,
			date_format, date_relativity
		    )
		);
	    w = pd->gen_date_change_label;
	    if(w != NULL)
		gtk_label_set_text(
		    GTK_LABEL(w),
		    EDVDateFormatString(
			(gulong)lstat_buf.st_ctime,
			date_format, date_relativity
		    )
		);
	}

	/* OK, Apply, Cancel, Close Buttons */
	sensitive = (write_protect) ? FALSE : has_changes;
	GTK_WIDGET_SET_SENSITIVE(pd->ok_btn, sensitive)
	GTK_WIDGET_SET_SENSITIVE(pd->apply_btn, sensitive)

	if(has_changes)
	{
	    MAP(pd->cancel_btn);
	    UNMAP(pd->close_btn);
	}
	else
	{
	    UNMAP(pd->cancel_btn);
	    MAP(pd->close_btn);
	}

#undef UNMAP
#undef MAP
}

/*
 *	Sets the Properties Dialog as busy or ready.
 */
void EDVPropDlgSetBusy(edv_propdlg_struct *pd, gboolean is_busy)
{
	GdkCursor *cursor;
	GtkWidget *w;
	edv_core_struct *core;


	if(pd == NULL)
	    return;

	core = pd->core;
	if(core == NULL)
	    return;

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

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

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

		/* If still busy do not change anything */
		if(pd->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 Properties Dialog is mapped.
 */
gboolean EDVPropDlgIsMapped(edv_propdlg_struct *pd)
{
	GtkWidget *w = (pd != NULL) ? pd->toplevel : NULL;
	return((w != NULL) ? GTK_WIDGET_MAPPED(w) : FALSE);
}

/*
 *	Maps the Properties Dialog.
 */
void EDVPropDlgMap(edv_propdlg_struct *pd)
{
	GtkWidget *w = (pd != NULL) ? pd->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_show_raise(w);

	w = pd->ok_btn;
	if(w != NULL)
	{
	    gtk_widget_grab_focus(w);
	    gtk_widget_grab_default(w);
	}
}

/*
 *	Unmaps the Properties Dialog.
 */
void EDVPropDlgUnmap(edv_propdlg_struct *pd)
{
	GtkWidget *w = (pd != NULL) ? pd->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Properties Dialog.
 */
void EDVPropDlgDelete(edv_propdlg_struct *pd)
{
	if(pd == NULL)
	    return;

	EDVObjOpDlgDelete(pd->obj_op_dlg);

	GTK_WIDGET_DESTROY(pd->gen_icon_pm);
	GTK_WIDGET_DESTROY(pd->gen_name_label);
	GTK_WIDGET_DESTROY(pd->gen_location_label);
	GTK_WIDGET_DESTROY(pd->gen_size_label);

	GTK_WIDGET_DESTROY(pd->gen_date_access_label);
	GTK_WIDGET_DESTROY(pd->gen_date_modify_label);
	GTK_WIDGET_DESTROY(pd->gen_date_change_label);
	GTK_WIDGET_DESTROY(pd->gen_date_touch_btn);
	GTK_WIDGET_DESTROY(pd->gen_timestamps_frame);

	GTK_WIDGET_DESTROY(pd->gen_owner_entry);
	GTK_WIDGET_DESTROY(pd->gen_owner_btn);
	GTK_WIDGET_DESTROY(pd->gen_group_entry);
	GTK_WIDGET_DESTROY(pd->gen_group_btn);
	GTK_WIDGET_DESTROY(pd->gen_ownership_frame);

	GTK_WIDGET_DESTROY(pd->gen_ur_check);
	GTK_WIDGET_DESTROY(pd->gen_uw_check);
	GTK_WIDGET_DESTROY(pd->gen_ux_check);
	GTK_WIDGET_DESTROY(pd->gen_gr_check);
	GTK_WIDGET_DESTROY(pd->gen_gw_check);
	GTK_WIDGET_DESTROY(pd->gen_gx_check);
	GTK_WIDGET_DESTROY(pd->gen_or_check);
	GTK_WIDGET_DESTROY(pd->gen_ow_check);
	GTK_WIDGET_DESTROY(pd->gen_ox_check);
	GTK_WIDGET_DESTROY(pd->gen_suid_check);
	GTK_WIDGET_DESTROY(pd->gen_sgid_check);
	GTK_WIDGET_DESTROY(pd->gen_sticky_check);
	GTK_WIDGET_DESTROY(pd->gen_permissions_frame);

	GTK_WIDGET_DESTROY(pd->det_verbose_radio);
	GTK_WIDGET_DESTROY(pd->det_raw_radio);
	GTK_WIDGET_DESTROY(pd->det_table);
	GTK_WIDGET_DESTROY(pd->det_vbox);

	GTK_WIDGET_DESTROY(pd->link_connected_icon);
	GTK_WIDGET_DESTROY(pd->link_broken_icon);
	GTK_WIDGET_DESTROY(pd->link_dest_entry);
	GTK_WIDGET_DESTROY(pd->link_dest_properties_btn);

	GTK_WIDGET_DESTROY(pd->dev_icon_pm);
	GTK_WIDGET_DESTROY(pd->dev_device_path_label);
	GTK_WIDGET_DESTROY(pd->dev_mount_path_label);
	GTK_WIDGET_DESTROY(pd->dev_fs_type_label);
	PieChartDelete(pd->dev_usage_pc);
	GTK_WIDGET_DESTROY(pd->dev_mount_btn);
	GTK_WIDGET_DESTROY(pd->dev_eject_btn);
	GTK_WIDGET_DESTROY(pd->dev_usage_vbox);
	GTK_WIDGET_DESTROY(pd->dev_usage_frame);

	GTK_WIDGET_DESTROY(pd->dev_check_btn);
	GTK_WIDGET_DESTROY(pd->dev_tools_btn);
	GTK_WIDGET_DESTROY(pd->dev_format_btn);

	GTK_WIDGET_DESTROY(pd->dev_node_major_entry);
	GTK_WIDGET_DESTROY(pd->dev_node_minor_entry);

	GTK_WIDGET_DESTROY(pd->notebook);
	GTK_WIDGET_DESTROY(pd->ok_btn);
	GTK_WIDGET_DESTROY(pd->apply_btn);
	GTK_WIDGET_DESTROY(pd->cancel_btn);
	GTK_WIDGET_DESTROY(pd->close_btn);
	GTK_WIDGET_DESTROY(pd->main_vbox);
	GTK_WIDGET_DESTROY(pd->toplevel);

	GTK_ACCEL_GROUP_UNREF(pd->accelgrp);

	g_free(pd->path);

	g_free(pd->title);

	g_free(pd);
}
