#include <gtk/gtk.h>

#include "guiutils.h"

#include "edvtypes.h"
#include "cfg.h"
#include "edvstatusbar.h"
#include "endeavour.h"
#include "edvcb.h"
#include "edvcfglist.h"
#include "edvutilsgtk.h"
#include "config.h"

#include "images/icon_secure_16x16.xpm"
#include "images/icon_insecure_16x16.xpm"
#include "images/icon_trash_16x16.xpm"
#include "images/icon_purge_16x16.xpm"


static gint EDVStatusBarButtonEventCB(
	GtkWidget *widget, GdkEventButton *button, gpointer data
);
static gint EDVStatusBarCrossingEventCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
);

edv_status_bar_struct *EDVStatusBarNew(
	gpointer core_ptr, GtkWidget *parent
);
void EDVStatusBarUpdate(edv_status_bar_struct *sb);
void EDVStatusBarSetBusy(
	edv_status_bar_struct *sb, gboolean busy  
);
void EDVStatusBarMap(edv_status_bar_struct *sb);
void EDVStatusBarUnmap(edv_status_bar_struct *sb);
void EDVStatusBarDelete(edv_status_bar_struct *sb);

void EDVStatusBarMessage(
	edv_status_bar_struct *sb, const gchar *message,
	gboolean allow_gtk_iteration
);
void EDVStatusBarProgress(
	edv_status_bar_struct *sb, gfloat percent,
	gboolean allow_gtk_iteration
);


#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 EDV_STATUS_BAR_HEIGHT	26


/*
 *	Status Bar "button_press_event" or "button_release_event"
 *	signal callback.
 */
static gint EDVStatusBarButtonEventCB(
	GtkWidget *widget, GdkEventButton *button, gpointer data
)
{
	gint status = FALSE;
	cfg_item_struct *cfg_list;
	edv_core_struct *core_ptr;
	edv_status_bar_struct *sb = EDV_STATUS_BAR(data);
	if((widget == NULL) || (sb == NULL))
	    return(status);

	core_ptr = EDV_CORE(sb->core_ptr);
	if(core_ptr == NULL)
	    return(status);

	cfg_list = core_ptr->cfg_list;

	EDVStatusBarSetBusy(sb, TRUE);

	/* Check which widget this event is for */
	if(widget == sb->write_protect_enabled_eb)
	{
	    gboolean write_protect = FALSE;
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_WRITE_PROTECT,
		write_protect, FALSE
	    );
	    EDVWriteProtectChangedEmit(core_ptr, write_protect);
	    status = TRUE;
	}
	else if(widget == sb->write_protect_disabled_eb)
	{
	    gboolean write_protect = TRUE;
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_WRITE_PROTECT,
		write_protect, FALSE
	    );
	    EDVWriteProtectChangedEmit(core_ptr, write_protect);
	    status = TRUE;
	}
	else if(widget == sb->delete_method_recycle_eb)
	{
	    edv_delete_method delete_method = EDV_DELETE_METHOD_PURGE;
	    CFGItemListSetValueI(
		cfg_list, EDV_CFG_PARM_DELETE_METHOD,
		delete_method, FALSE
	    );
	    EDVReconfiguredEmit(core_ptr);
	    status = TRUE;
	}
	else if(widget == sb->delete_method_purge_eb)
	{
	    edv_delete_method delete_method = EDV_DELETE_METHOD_MOVE_TO_RECBIN;
	    CFGItemListSetValueI(                    
		cfg_list, EDV_CFG_PARM_DELETE_METHOD,
		delete_method, FALSE                
	    );
	    EDVReconfiguredEmit(core_ptr);
	    status = TRUE;
	}

	EDVStatusBarSetBusy(sb, FALSE);

	return(status);
}

/*
 *      Status Bar "enter_notify_event" or "leave_notify_event"
 *	signal callback.
 */
static gint EDVStatusBarCrossingEventCB(
	GtkWidget *widget, GdkEventCrossing *crossing, gpointer data
)
{
	gint status = FALSE;
	gint etype;
	edv_status_bar_struct *sb = EDV_STATUS_BAR(data);
	if((widget == NULL) || (crossing == NULL) || (sb == NULL))
	    return(status);

	etype = (gint)crossing->type;


	/* Check which widget this event is for */

	/* Write protect enabled */
	if(widget == sb->write_protect_enabled_eb)
	{
	    const gchar *mesg = NULL;

	    switch(etype)
	    {
	      case GDK_ENTER_NOTIFY:
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Escriba proteja es permitido, el clic a incapacitarlo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Protége en écriture est rendu capable, le déclic pour le rendre infirme"
#elif defined(PROG_LANGUAGE_GERMAN)
"Schreibgeschützt ist, klicken ermöglicht, unwirksam es zu machen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scrivere proteggere č permesso, lo scatto esserlo incapace"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrijf beschermt, is gegeven de gelegenheid, klik onbruikbaar het te maken"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Escreva protege é capacitado, estalido incapacitaá-lo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Skrivebeskyttet muliggjřrer, klikk udyktiggjřre det"
#else
"Write protect is enabled, click to disable it"
#endif
		;
		break;
	      case GDK_LEAVE_NOTIFY:
		mesg = NULL;
		break;
	    }
	    EDVStatusBarMessage(sb, mesg, FALSE);
	    status = TRUE;
	}
	/* Write protect disabled */
	else if(widget == sb->write_protect_disabled_eb)
	{
	    const gchar *mesg = NULL;

	    switch(etype)
	    {
	      case GDK_ENTER_NOTIFY:
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Escriba proteja es incapacitado, el clic para permitirlo"
#elif defined(PROG_LANGUAGE_FRENCH)
"Protége en écriture est rendu infirme, le déclic pour le rendre capable"
#elif defined(PROG_LANGUAGE_GERMAN)
"Schreibgeschützt ist unwirksam, klicken gemacht, es zu ermöglichen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scrivere proteggere č stato incapace, lo scatto permetterlo"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrijf beschermt, is gemaakt onbruikbaar, klik aan de gelegenheid het te geven"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Escreva protege é incapacitado, estalido capacitaá-lo"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Skrivebeskyttet udyktiggjřr, klikk muliggjřre det"
#else
"Write protect is disabled, click to enable it"
#endif
		;
		break;

	      case GDK_LEAVE_NOTIFY:
		mesg = "";
		break;
	    }
	    EDVStatusBarMessage(sb, mesg, FALSE);
	    status = TRUE;
	}
	/* Delete method recycle */
	else if(widget == sb->delete_method_recycle_eb)
	{
	    const gchar *mesg = NULL;

	    switch(etype)
	    {
	      case GDK_ENTER_NOTIFY:
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Borra el método se pone a reciclar, hacer clic para ponerlo purgar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer la méthode est réglée pour recycler, cliqueter pour régler\
 le purger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Löschen Sie Methode ist gesetzt wiederzuverwerten, zu klicken, es\
 zu setzen, zu reinigen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cancellare il metodo č regolato per riciclare, lo scatto regolarlo\
 per prosciogliere"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrap methode is gezet te recyclen, klik het te zetten te\
 reinigen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Anule método é posto reciclar, clicar por purgar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Stryk metode setter resirkulere, klikk sette det rense"
#else
"Delete method is set to recycle, click to set it to purge"
#endif
		;
		break;

	      case GDK_LEAVE_NOTIFY: 
		mesg = "";
		break;
	    }
	    EDVStatusBarMessage(sb, mesg, FALSE);
	    status = TRUE;
	}
	/* Delete method purge */
	else if(widget == sb->delete_method_purge_eb)
	{
	    const gchar *mesg = NULL;

	    switch(etype)
	    {
	      case GDK_ENTER_NOTIFY:
		mesg =
#if defined(PROG_LANGUAGE_SPANISH)
"Borre el método se pone a purgar, hacer clic para ponerlo reciclar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer la méthode est réglée pour purger, cliqueter pour régler\
 le recycler"
#elif defined(PROG_LANGUAGE_GERMAN)
"Löschen Sie Methode ist gesetzt zu reinigen, zu klicken, es zu\
 setzen, wiederzuverwerten"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cancellare il metodo č regolato per prosciogliere, lo scatto\
 regolarlo per riciclare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrap methode is gezet te reinigen, klik het te zetten te recyclen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Anule método é posto purgar, clicar por reciclar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Stryk metode setter rense, klikk sette det resirkulere"
#else
"Delete method is set to purge, click to set it to recycle"
#endif
		;
		break;

	      case GDK_LEAVE_NOTIFY:
		mesg = "";
		break;
	    }
	    EDVStatusBarMessage(sb, mesg, FALSE);
	    status = TRUE;
	}

	return(status);
}


/*
 *	Creates a new Status Bar.
 */
edv_status_bar_struct *EDVStatusBarNew(
	gpointer core_ptr, GtkWidget *parent
)
{
	GtkStyle *style;
	GtkWidget *w, *parent2, *parent3;
	GtkAdjustment *adj;
	edv_status_bar_struct *sb = EDV_STATUS_BAR(
	    g_malloc0(sizeof(edv_status_bar_struct))
	);
	if(sb == NULL)
	    return(NULL);

	/* Reset values */
	sb->busy_count = 0;
	sb->freeze_count = 0;
	sb->core_ptr = core_ptr;


	/* Begin creating widgets */

	/* Toplevel frame */
	sb->toplevel = w = gtk_frame_new(NULL);
	gtk_widget_set_usize(w, -1, EDV_STATUS_BAR_HEIGHT);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_OUT);
	gtk_container_border_width(GTK_CONTAINER(w), 0);
	if(GTK_IS_BOX(parent))
	    gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	else if(GTK_IS_CONTAINER(parent))
	    gtk_container_add(GTK_CONTAINER(parent), w);
	else
	    g_printerr(
"EDVStatusBarNew(): Warning:\
 parent 0x%.8x is not a GtkContainer.\n",
		(guint)parent
	    );
	style = gtk_widget_get_style(w);
	parent2 = w;

	/* Table in main frame */
	w = gtk_table_new(1, 4, FALSE);
	gtk_container_add(GTK_CONTAINER(parent2), w);
	gtk_widget_show(w);
	parent2 = w;


	/* Write protect enabled/disabled */
	/* Write protect enabled */
	sb->write_protect_enabled_eb = w = gtk_event_box_new();
	gtk_widget_add_events(
	    w,
	    GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
	    GDK_LEAVE_NOTIFY_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarButtonEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    0, 1, 0, 1,
	    0, 0,
	    2, 0
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Escriba proteja es permitido"
#elif defined(PROG_LANGUAGE_FRENCH)
"Protége en écriture est rendu capable"
#elif defined(PROG_LANGUAGE_GERMAN)
"Schreibgeschützt ist ermöglicht"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scrivere proteggere č permesso"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrijf beschermt, is gegeven de gelegenheid"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Escreva protege é capacitado"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Skrivebeskyttet muliggjřrer"
#else
"Write protect is enabled"
#endif
	);
	parent3 = w;
	/* Icon */
	w = EDVNewPixmapWidget(
	    core_ptr,
	    (guint8 **)icon_secure_16x16_xpm,
	    "icon_secure_16x16_xpm"
	);
	gtk_widget_set_usize(w, 16, 16);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);


	/* Write protect disabled */
	sb->write_protect_disabled_eb = w = gtk_event_box_new();
	gtk_widget_add_events(
	    w,
	    GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
	    GDK_LEAVE_NOTIFY_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarButtonEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    0, 1, 0, 1,
	    0, 0,
	    2, 0
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Escriba proteja es incapacitado"
#elif defined(PROG_LANGUAGE_FRENCH)
"Protége en écriture est rendu infirme"
#elif defined(PROG_LANGUAGE_GERMAN)
"Schreibgeschützt ist unwirksam gemacht"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scrivere proteggere č stato incapace"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrijf beschermt, is gemaakt onbruikbaar"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Escreva protege é incapacitado"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Skrivebeskyttet udyktiggjřr"
#else
"Write protect is disabled"
#endif
	);
	gtk_widget_show(w);
	parent3 = w;
	/* Icon */
	w = EDVNewPixmapWidget(
	    core_ptr,
	    (guint8 **)icon_insecure_16x16_xpm,
	    "icon_insecure_16x16_xpm"
	);
	gtk_widget_set_usize(w, 16, 16);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);


	/* Delete method */
	/* Delete method recycle */         
	sb->delete_method_recycle_eb = w = gtk_event_box_new();
	gtk_widget_add_events(
	    w,
	    GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
	    GDK_LEAVE_NOTIFY_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarButtonEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    1, 2, 0, 1,
	    0, 0,
	    2, 0
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Borre el método se pone a reciclar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer la méthode est réglée pour recycler"
#elif defined(PROG_LANGUAGE_GERMAN)
"Löschen sie methode ist gesetzt wiederzuverwerten"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cancellare il metodo č regolato per riciclare"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrap methode is gezet te recyclen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Anule método é posto reciclar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Stryk metode setter resirkulere"
#else
"Delete method is set to recycle"
#endif
	);
	gtk_widget_show(w);
	parent3 = w;  
	/* Icon */
	w = EDVNewPixmapWidget(
	    core_ptr,
	    (guint8 **)icon_trash_16x16_xpm,
	    "icon_trash_16x16_xpm"
	);
	gtk_widget_set_usize(w, 16, 16);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);

	/* Delete method purge */
	sb->delete_method_purge_eb = w = gtk_event_box_new();
	gtk_widget_add_events(
	    w,
	    GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK |
	    GDK_LEAVE_NOTIFY_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarButtonEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "enter_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "leave_notify_event",
	    GTK_SIGNAL_FUNC(EDVStatusBarCrossingEventCB), sb
	);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    1, 2, 0, 1,
	    0, 0,
	    2, 0 
	);      
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"Borre el método se pone a purgar"
#elif defined(PROG_LANGUAGE_FRENCH)
"Effacer la méthode est réglée pour purger"
#elif defined(PROG_LANGUAGE_GERMAN)
"Löschen sie methode ist gesetzt zu reinigen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Cancellare il metodo č regolato per prosciogliere"
#elif defined(PROG_LANGUAGE_DUTCH)
"Schrap methode is gezet te reinigen"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Anule método é posto purgar"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Stryk metode setter rense"
#else
"Delete method is set to purge"
#endif
	);
	parent3 = w;
	/* Icon */
	w = EDVNewPixmapWidget(
	    core_ptr,
	    (guint8 **)icon_purge_16x16_xpm,
	    "icon_purge_16x16_xpm"
	);
	gtk_widget_set_usize(w, 16, 16);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);


	/* Progress bar */
	adj = (GtkAdjustment *)gtk_adjustment_new(
	    0.0f, 1.0f, 100.0f,
	    0.0f, 0.0f, 0.0f
	);
	sb->progress_bar = w = gtk_progress_bar_new_with_adjustment(adj);
	gtk_widget_set_usize(w, 100, 20);
	gtk_progress_bar_set_orientation(
	    GTK_PROGRESS_BAR(w), GTK_PROGRESS_LEFT_TO_RIGHT
	);
	gtk_progress_bar_set_bar_style(
	    GTK_PROGRESS_BAR(w), GTK_PROGRESS_CONTINUOUS
	);
	gtk_progress_set_activity_mode(
	    GTK_PROGRESS(w), FALSE
	);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    2, 3, 0, 1,
	    0,
	    GTK_SHRINK,
	    0, 0
	);
	gtk_widget_show(w);

	/* Label */
	w = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
	gtk_container_border_width(GTK_CONTAINER(w), 1);
	gtk_table_attach(
	    GTK_TABLE(parent2), w,
	    3, 4, 0, 1,
	    GTK_SHRINK | GTK_EXPAND | GTK_FILL,
	    GTK_FILL,
	    0, 0
	);
	gtk_widget_show(w);
	parent3 = w;

	w = gtk_hbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);
	parent3 = w;

	sb->label = w = gtk_label_new("");
	gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 2);
	gtk_widget_show(w);

	return(sb);
}

/*
 *	Updates the Status Bar widgets to reflect current values.
 */
void EDVStatusBarUpdate(edv_status_bar_struct *sb)
{
	gboolean write_protect;
	edv_delete_method delete_method;
	GtkWidget *w;
	const cfg_item_struct *cfg_list;
	edv_core_struct *core_ptr;


	if(sb == NULL)
	    return;

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

	cfg_list = core_ptr->cfg_list;

	/* Get configuration */
	write_protect = CFGItemListGetValueI(
	    cfg_list, EDV_CFG_PARM_WRITE_PROTECT
	);
	delete_method = CFGItemListGetValueI(          
	    cfg_list, EDV_CFG_PARM_DELETE_METHOD
	);


	/* Begin updating */

	/* Write protect */
	w = sb->write_protect_enabled_eb;
	if(w != NULL)
	{
	    if(write_protect)
		gtk_widget_show(w);
	    else
		gtk_widget_hide(w);
	}
	w = sb->write_protect_disabled_eb;
	if(w != NULL)
	{
	    if(write_protect)
		gtk_widget_hide(w);
	    else
		gtk_widget_show(w);
	}

	/* Delete method */
	w = sb->delete_method_recycle_eb;
	if(w != NULL)
	{
	    if(delete_method == EDV_DELETE_METHOD_MOVE_TO_RECBIN)
		gtk_widget_show(w);
	    else   
		gtk_widget_hide(w);
	}
	w = sb->delete_method_purge_eb;
	if(w != NULL)
	{
	    if(delete_method == EDV_DELETE_METHOD_PURGE)
		gtk_widget_show(w);                              
	    else   
		gtk_widget_hide(w);
	}
}

/*
 *	Sets the Status Bar as busy or ready.
 */
void EDVStatusBarSetBusy(
	edv_status_bar_struct *sb, gboolean busy  
)
{
	GdkCursor *cur;
	GtkWidget *w = (sb != NULL) ? sb->toplevel : NULL;
	edv_core_struct *core_ptr;
	if(w == NULL)
	    return;

	w = gtk_widget_get_toplevel(w);
	core_ptr = EDV_CORE(sb->core_ptr);
	if((w == NULL) || (core_ptr == NULL))
	    return;

	if(busy)
	{
	    /* Increase busy count */
	    sb->busy_count++;

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

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

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

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

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

/*
 *	Maps the Status Bar.
 */
void EDVStatusBarMap(edv_status_bar_struct *sb)
{
	GtkWidget *w = (sb != NULL) ? sb->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_show(w);
}

/*
 *	Unmaps the Status Bar.
 */
void EDVStatusBarUnmap(edv_status_bar_struct *sb)
{
	GtkWidget *w = (sb != NULL) ? sb->toplevel : NULL;
	if(w == NULL)
	    return;

	gtk_widget_hide(w);
}

/*
 *	Deletes the Status Bar.
 */
void EDVStatusBarDelete(edv_status_bar_struct *sb)
{
	if(sb == NULL)
	    return;

	GTK_WIDGET_DESTROY(sb->progress_bar);
	GTK_WIDGET_DESTROY(sb->label);
	GTK_WIDGET_DESTROY(sb->write_protect_enabled_eb);
	GTK_WIDGET_DESTROY(sb->write_protect_disabled_eb);
	GTK_WIDGET_DESTROY(sb->delete_method_recycle_eb);
	GTK_WIDGET_DESTROY(sb->delete_method_purge_eb);
	GTK_WIDGET_DESTROY(sb->toplevel);

	g_free(sb);
}


/*
 *	Sets the Status Bar's message.
 */
void EDVStatusBarMessage(
	edv_status_bar_struct *sb, const gchar *message,
	gboolean allow_gtk_iteration
)
{
	GtkWidget *w = (sb != NULL) ? sb->label : NULL;
	if(w == NULL)
	    return;

	gtk_label_set_text(
	    GTK_LABEL(w),
	    (message != NULL) ? message : ""
	);

	/* Flush events? */
	while((gtk_events_pending() > 0) && allow_gtk_iteration)
	    gtk_main_iteration();
}

/*
 *	Sets the Status Bar's progress.
 *
 *	If value is between 0.0 to 1.0 then normal finite progress
 *	is performed, otherwise if value is negative then unknown time
 *	progress is performed.
 */
void EDVStatusBarProgress(
	edv_status_bar_struct *sb, gfloat value,
	gboolean allow_gtk_iteration
)
{
	GtkProgress *progress;
	GtkWidget *w = (sb != NULL) ? sb->progress_bar : NULL;
	if(w == NULL)
	    return;

	progress = GTK_PROGRESS(w);

	/* Do activity? */
	if(value < 0.0f)
	{
	    GtkAdjustment *adj = progress->adjustment;

	    /* Get new value based on unknown position */
	    value = gtk_progress_get_value(progress) + 1.0f;
	    if(value > adj->upper)
		value = adj->lower;

	    /* Update progress bar for `activity mode' (unknown limit)
	     * and set new value
	     */
	    gtk_progress_set_activity_mode(progress, TRUE);
	    gtk_progress_set_show_text(progress, FALSE);
	    gtk_progress_set_value(progress, value);

	    /* Reset last progress position to -1.0, indicating that
	     * there is no known last position since we are doing
	     * activity mode
	     */
	    sb->progress_pos_last = -1.0f;
	}
	else
	{
	    /* Clip value to 0.0, 1.0 */
	    if(value > 1.0f)
		value = 1.0f;

	    /* Reset last progress position if it is greater than the
	     * given value, implying the progress has warped back to
	     * the beginning
	     */
	    if(sb->progress_pos_last > value)
		sb->progress_pos_last = -1.0f;

	    /* Has value not sufficiently changed? (less than 0.01
	     * change in value)
	     */
	    if((sb->progress_pos_last > 0.0f) &&
	       ((value - sb->progress_pos_last) < 0.01f)
	    )
		return;

	    /* Update progress */
	    gtk_progress_set_activity_mode(progress, FALSE);
	    gtk_progress_set_format_string(
		progress, "%p%%"
	    );
	    /* Display text only if value is positive */
	    gtk_progress_set_show_text(
		progress, (value > 0.0f) ? TRUE : FALSE
	    );
	    gtk_progress_bar_update(GTK_PROGRESS_BAR(w), value);

	    /* Record last position */
	    sb->progress_pos_last = value;
	}

	/* Flush events? */
	while((gtk_events_pending() > 0) && allow_gtk_iteration)
	    gtk_main_iteration();
}
