/*
 *  Copyright (C) 2002 Jorn Baayen
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "pdm-dialog.h"
#include "galeon-shell.h"
#include "galeon-embed-shell.h"
#include "gul-gui.h"
#include "gul-state.h"

#include <gtk/gtktreemodelfilter.h>
#include <gtk/gtktreeview.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtktreemodelsort.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtksizegroup.h>
#include <gtk/gtkdialog.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkentry.h>
#include <gtk/gtklabel.h>
#include <glib/gi18n.h>

#define get_filter_from_treeview(treeview) \
	GTK_TREE_MODEL_FILTER(gtk_tree_model_sort_get_model( \
	GTK_TREE_MODEL_SORT(gtk_tree_view_get_model( \
	GTK_TREE_VIEW(treeview)))))

#define get_model_from_treeview(treeview) \
	gtk_tree_model_filter_get_model(get_filter_from_treeview(treeview))

GList *get_model_selection_refs(GtkTreeView *treeview);
gint tree_row_reference_compare(GtkTreeRowReference *ref1,
				GtkTreeRowReference *ref2);

typedef struct PdmActionInfo PdmActionInfo;

typedef void (* PDM_add) (PdmActionInfo *info, gpointer data);
typedef void (* PDM_remove) (PdmActionInfo *info, GList *data);
typedef void (* PDM_free) (PdmActionInfo *info, GList *data);

static void pdm_dialog_class_init (PdmDialogClass *klass);
static void pdm_dialog_init (PdmDialog *dialog);
static void pdm_dialog_finalize (GObject *object);

/* Filter callbacks */
static gboolean
visibility_filter_func(GtkTreeModel *model,
		       GtkTreeIter *iter,
		       gpointer data);

/* Glade callbacks */
void
pdm_dialog_close_button_clicked_cb (GtkWidget *button,
			            PdmDialog *dialog);
void
pdm_dialog_cookies_properties_button_clicked_cb (GtkWidget *button,
						 PdmDialog *dialog);
void
pdm_dialog_cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
                                          	  PdmDialog *dialog);
void
pdm_dialog_passwords_treeview_selection_changed_cb (GtkTreeSelection *selection,
                                          	    PdmDialog *dialog);

/* Non-Glade callbacks */
static void
pdm_dialog_cookie_remove_block_button_clicked_cb (GtkWidget *button,
						  PdmActionInfo *action);

static GObjectClass *parent_class = NULL;

struct PdmActionInfo
{
	PDM_add add;
	PDM_remove remove;
	PDM_free free;
	GtkWidget *treeview;
	GList *list;
	int remove_id;
	int data_col;
	const gchar *filter_string;
	gboolean lock_selection;
	PdmDialog *dialog;
};

struct PdmDialogPrivate
{
	GtkWidget     *notebook;
	PdmActionInfo *cookies;
	PdmActionInfo *passwords;
	PdmActionInfo *password_sites;
	PdmActionInfo *cookie_sites;
	PdmActionInfo *image_sites;
	PdmActionInfo *popup_sites;
};

enum
{
	PROP_DIALOG,
	PROP_NOTEBOOK,

	PROP_COOKIES_TREEVIEW,
	PROP_COOKIES_REMOVE,
	PROP_COOKIES_FIND_ENTRY,
	PROP_COOKIES_CLEAR,
	PROP_COOKIES_REMOVE_BLOCK,
	PROP_COOKIES_VALUE_ENTRY,
	PROP_COOKIES_URL_ENTRY,
	PROP_COOKIES_EXPIRES_LABEL,

	PROP_PASSWORDS_TREEVIEW,
	PROP_PASSWORDS_REMOVE,
	PROP_PASSWORDS_FIND_ENTRY,
	PROP_PASSWORDS_CLEAR,

	PROP_COOKIE_SITES_TREEVIEW,
	PROP_COOKIE_SITES_REMOVE,
	PROP_COOKIE_SITES_FIND_ENTRY,
	PROP_COOKIE_SITES_CLEAR,

	PROP_IMAGE_SITES_TREEVIEW,
	PROP_IMAGE_SITES_REMOVE,
	PROP_IMAGE_SITES_FIND_ENTRY,
	PROP_IMAGE_SITES_CLEAR,

	PROP_PASSWORD_SITES_TREEVIEW,
	PROP_PASSWORD_SITES_REMOVE,
	PROP_PASSWORD_SITES_FIND_ENTRY,
	PROP_PASSWORD_SITES_CLEAR,

	PROP_POPUP_SITES_TREEVIEW,
	PROP_POPUP_SITES_REMOVE,
	PROP_POPUP_SITES_FIND_ENTRY,
	PROP_POPUP_SITES_CLEAR
};

enum
{
	COL_COOKIES_HOST,
	COL_COOKIES_NAME,
	COL_COOKIES_DATA
};

enum
{
	COL_PASSWORDS_HOST,
	COL_PASSWORDS_USER,
	COL_PASSWORDS_DATA
};

enum
{
	COL_COOKIE_SITES_DOMAIN,
	COL_COOKIE_SITES_STATUS,
	COL_COOKIE_SITES_DATA
};

enum
{
	COL_IMAGE_SITES_DOMAIN,
	COL_IMAGE_SITES_STATUS,
	COL_IMAGE_SITES_DATA
};

enum
{
	COL_PASSWORD_SITES_HOST,
	COL_PASSWORD_SITES_STATUS,
	COL_PASSWORD_SITES_DATA
};

enum
{
	COL_POPUP_SITES_DOMAIN,
	COL_POPUP_SITES_STATUS,
	COL_POPUP_SITES_DATA
};

static const
GaleonDialogProperty properties [] =
{
	{ PROP_DIALOG, "pdm_dialog", NULL, PT_NORMAL, NULL },
	{ PROP_NOTEBOOK, "pdm_notebook", NULL, PT_NORMAL, NULL },

	{ PROP_COOKIES_TREEVIEW, "cookies_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_REMOVE, "cookies_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_FIND_ENTRY, "cookies_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_CLEAR, "cookies_clear_button", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_REMOVE_BLOCK, "cookies_remove_block_button", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_VALUE_ENTRY, "cookies_value_entry", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_URL_ENTRY, "cookies_url_entry", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIES_EXPIRES_LABEL, "cookies_expires_label", NULL, PT_NORMAL, NULL },

	{ PROP_PASSWORDS_TREEVIEW, "passwords_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORDS_REMOVE, "passwords_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORDS_FIND_ENTRY, "passwords_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORDS_CLEAR, "passwords_clear_button", NULL, PT_NORMAL, NULL },

	{ PROP_COOKIE_SITES_TREEVIEW, "cookie_sites_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIE_SITES_REMOVE, "cookie_sites_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIE_SITES_FIND_ENTRY, "cookie_sites_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_COOKIE_SITES_CLEAR, "cookie_sites_clear_button", NULL, PT_NORMAL, NULL },

	{ PROP_IMAGE_SITES_TREEVIEW, "image_sites_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_IMAGE_SITES_REMOVE, "image_sites_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_IMAGE_SITES_FIND_ENTRY, "image_sites_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_IMAGE_SITES_CLEAR, "image_sites_clear_button", NULL, PT_NORMAL, NULL },

	{ PROP_PASSWORD_SITES_TREEVIEW, "password_sites_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORD_SITES_REMOVE, "password_sites_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORD_SITES_FIND_ENTRY, "password_sites_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_PASSWORD_SITES_CLEAR, "password_sites_clear_button", NULL, PT_NORMAL, NULL },

	{ PROP_POPUP_SITES_TREEVIEW, "popup_sites_treeview", NULL, PT_NORMAL, NULL },
	{ PROP_POPUP_SITES_REMOVE, "popup_sites_remove_button", NULL, PT_NORMAL, NULL },
	{ PROP_POPUP_SITES_FIND_ENTRY, "popup_sites_find_entry", NULL, PT_NORMAL, NULL },
	{ PROP_POPUP_SITES_CLEAR, "popup_sites_clear_button", NULL, PT_NORMAL, NULL },

	{ -1, NULL, NULL }
};

GType 
pdm_dialog_get_type (void)
{
        static GType pdm_dialog_type = 0;

        if (pdm_dialog_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (PdmDialogClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) pdm_dialog_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (PdmDialog),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) pdm_dialog_init
                };

                pdm_dialog_type = g_type_register_static (GALEON_DIALOG_TYPE,
						              "PdmDialog",
						              &our_info, 0);
        }

        return pdm_dialog_type;

}

static void
pdm_dialog_class_init (PdmDialogClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);

        parent_class = g_type_class_peek_parent (klass);

        object_class->finalize = pdm_dialog_finalize;
}

GList *get_model_selection_refs(GtkTreeView *treeview)
{
	GList *i, *sort_refs, *ret_refs = NULL;
	GtkTreeModel *model, *sorter, *filter;

	sorter = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
	filter = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(sorter));
	model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter));

	sort_refs = gul_gui_treeview_get_selection_refs(treeview);

	for(i = sort_refs ; i ; i = i->next)
	{
		GtkTreePath *sort_path, *filter_path, *path;
		GtkTreeRowReference *node;

		sort_path = gtk_tree_row_reference_get_path 
				((GtkTreeRowReference *)i->data);
		filter_path = gtk_tree_model_sort_convert_path_to_child_path
				(GTK_TREE_MODEL_SORT(sorter), sort_path);
		path = gtk_tree_model_filter_convert_path_to_child_path
				(GTK_TREE_MODEL_FILTER(filter), filter_path);

		node = gtk_tree_row_reference_new(model, path);
	        ret_refs = g_list_append(ret_refs, node);

		gtk_tree_path_free(path);
		gtk_tree_path_free(filter_path);
		gtk_tree_path_free(sort_path);
	}

	gul_gui_treeview_free_selection_refs(sort_refs);

	return ret_refs;
}

gint tree_row_reference_compare(GtkTreeRowReference *ref1,
				GtkTreeRowReference *ref2)
{
	gint retval;
	GtkTreePath *path1 = gtk_tree_row_reference_get_path(ref1);
	GtkTreePath *path2 = gtk_tree_row_reference_get_path(ref2);

	retval = gtk_tree_path_compare(path1, path2);

	gtk_tree_path_free(path1);
	gtk_tree_path_free(path2);

	return retval;
}

static void
cookies_treeview_selection_changed_cb (GtkTreeSelection *selection,
                                       PdmDialog *dialog)
{
	GaleonDialog *d = GALEON_DIALOG(dialog);
	GtkTreeModel *model;
	GValue val = {0, };
	GtkTreeIter iter;
	GtkTreePath *path;
	CookieInfo *info;
	GList *l;
	GtkEntry *value_entry, *url_entry;
	GtkLabel *expires_label;
	GtkWidget *treeview = dialog->priv->cookies->treeview;
	gchar *url, *scheme;

	if (dialog->priv->cookies->lock_selection) return;

	value_entry = GTK_ENTRY(galeon_dialog_get_control(d, PROP_COOKIES_VALUE_ENTRY));
	url_entry = GTK_ENTRY(galeon_dialog_get_control(d, PROP_COOKIES_URL_ENTRY));
	expires_label = GTK_LABEL(galeon_dialog_get_control(d, PROP_COOKIES_EXPIRES_LABEL));

	model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));

	l = gul_gui_treeview_get_selection_refs(GTK_TREE_VIEW(treeview));

	if (l == NULL || l->next != NULL)
	{
		gtk_entry_set_text(value_entry, "");
		gtk_entry_set_text(url_entry, "");
		gtk_label_set_text(expires_label, "");

		gul_gui_treeview_free_selection_refs(l);
		return;
	}

	path = gtk_tree_row_reference_get_path((GtkTreeRowReference *)l->data);

	gul_gui_treeview_free_selection_refs(l);

	gtk_tree_model_get_iter(model, &iter, path);
	gtk_tree_path_free(path);

	gtk_tree_model_get_value 
		(model, &iter, COL_COOKIES_DATA, &val);
	info = (CookieInfo *)g_value_get_pointer (&val);

	if (!g_ascii_strcasecmp(info->secure, "Yes"))
		scheme = "https://";
	else
		scheme = "http://";

	if (info->domain[0] == '.')
		url = g_strconcat(scheme, "*", info->domain, info->path, NULL);
	else
		url = g_strconcat(scheme, info->domain, info->path, NULL);

	gtk_entry_set_text(value_entry, info->value);
	gtk_label_set_text(expires_label, info->expire);
	gtk_entry_set_text(url_entry, url);
	g_free(url);
}

static void
action_treeview_selection_changed_cb (GtkTreeSelection *selection,
                                      PdmActionInfo *action)
{
	GtkWidget *widget;
	GList *l;
	GaleonDialog *d = GALEON_DIALOG(action->dialog);
	gboolean has_selection;

	if (action->lock_selection) return;

	l = gul_gui_treeview_get_selection_refs 
		(GTK_TREE_VIEW(action->treeview));

	has_selection = l != NULL;
	gul_gui_treeview_free_selection_refs (l);

	widget = galeon_dialog_get_control (d, action->remove_id);
	gtk_widget_set_sensitive (widget, has_selection);

	/* Cookies page needs special handling for block button  */
	if (action->remove_id == PROP_COOKIES_REMOVE)
	{
		widget = galeon_dialog_get_control(d,
						   PROP_COOKIES_REMOVE_BLOCK);
		gtk_widget_set_sensitive(widget, has_selection);
	}
}

static gboolean
visibility_filter_func(GtkTreeModel *model,
		       GtkTreeIter *iter,
		       gpointer data)
{
	GValue val = {0, };
	CookieInfo *info;
	PdmActionInfo *action = (PdmActionInfo *)data;

	if (action->filter_string == NULL) return TRUE;

	gtk_tree_model_get_value(model, iter, action->data_col, &val);

	/* Bit of a sneaky hack. Cookies/passwords/permissions have
	 * different structs, but all have domain/hostname as the first
	 * field. So we can get away with this fudge
	 */
	info = (CookieInfo *)g_value_get_pointer(&val);

	if (g_strrstr(info->domain, action->filter_string) != NULL)
		return TRUE;
	else
		return FALSE;
}

static void
action_find_entry_changed_cb(GtkEntry *entry,
			     PdmActionInfo *action)
{
	GtkWidget *find_entry;
	GtkTreeModelFilter *filter = get_filter_from_treeview(action->treeview);

	find_entry = galeon_dialog_get_control(GALEON_DIALOG(action->dialog),
					       (action->remove_id)+1);

	action->filter_string = gtk_entry_get_text(GTK_ENTRY(find_entry));
	gtk_tree_model_filter_refilter(filter);
}

static void
action_clear_button_clicked_cb(GtkButton *button,
			       PdmActionInfo *action)
{
	GtkWidget *find_entry;
	GtkTreeModelFilter *filter = get_filter_from_treeview(action->treeview);

	find_entry = galeon_dialog_get_control(GALEON_DIALOG(action->dialog),
					       (action->remove_id)+1);

	gtk_entry_set_text(GTK_ENTRY(find_entry), "");

	action->filter_string = NULL;
	gtk_tree_model_filter_refilter(filter);
}

static GtkWidget *
setup_passwords_treeview (PdmDialog *dialog)
{

	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;

	treeview = GTK_TREE_VIEW(galeon_dialog_get_control 
				 (GALEON_DIALOG(dialog),
				 PROP_PASSWORDS_TREEVIEW));
	
        /* set tree model */
        liststore = gtk_list_store_new (3,
                                        G_TYPE_STRING,
                                        G_TYPE_STRING,
                                        G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible (treeview, TRUE);
	selection = gtk_tree_view_get_selection (treeview);
	gtk_tree_selection_set_mode (selection,
				     GTK_SELECTION_MULTIPLE);
	
        renderer = gtk_cell_renderer_text_new ();

        gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_PASSWORDS_HOST, 
						     _("Host"),
                                                     renderer,
                                                     "text", COL_PASSWORDS_HOST,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_HOST);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_HOST);

        gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_PASSWORDS_USER, 
						     _("User Name"),
                                                     renderer,
                                                     "text", COL_PASSWORDS_USER,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_PASSWORDS_USER);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_PASSWORDS_USER);

	return GTK_WIDGET (treeview);
}

static GtkWidget *
setup_password_sites_treeview (PdmDialog *dialog)
{

	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;

	treeview = GTK_TREE_VIEW(galeon_dialog_get_control 
				 (GALEON_DIALOG(dialog),
				 PROP_PASSWORD_SITES_TREEVIEW));
	
        /* set tree model */
        liststore = gtk_list_store_new(3,
                                       G_TYPE_STRING,
                                       G_TYPE_STRING,
                                       G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible(treeview, TRUE);
	selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_set_mode(selection,
				    GTK_SELECTION_MULTIPLE);
	
        renderer = gtk_cell_renderer_text_new();

        gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_PASSWORD_SITES_HOST, 
						     _("Host"),
                                                     renderer,
                                                     "text", COL_PASSWORD_SITES_HOST,
                                                     NULL);
        column = gtk_tree_view_get_column(treeview, COL_PASSWORD_SITES_HOST);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_PASSWORD_SITES_HOST);

	gtk_tree_view_insert_column_with_attributes(treeview,
                                                    COL_PASSWORD_SITES_STATUS, 
						    _("Status"),
                                                    renderer,
                                                    "text", COL_PASSWORD_SITES_STATUS,
                                                    NULL);
        column = gtk_tree_view_get_column(treeview, COL_PASSWORD_SITES_STATUS);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_PASSWORD_SITES_STATUS);

	return GTK_WIDGET(treeview);
}

static GtkWidget *
setup_cookies_treeview (PdmDialog *dialog)
{
	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;
	
	treeview = GTK_TREE_VIEW (galeon_dialog_get_control 
				  (GALEON_DIALOG(dialog),
				  PROP_COOKIES_TREEVIEW));

        /* set tree model */
        liststore = gtk_list_store_new (3,
                                        G_TYPE_STRING,
                                        G_TYPE_STRING,
                                        G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible (treeview, TRUE);
	selection = gtk_tree_view_get_selection (treeview);
	gtk_tree_selection_set_mode (selection,
				     GTK_SELECTION_MULTIPLE);

	g_signal_connect (selection, "changed",
			  G_CALLBACK(cookies_treeview_selection_changed_cb),
			  dialog);
	
	renderer = gtk_cell_renderer_text_new ();

	gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_COOKIES_HOST, 
						     _("Domain"),
                                                     renderer,
                                                     "text", COL_COOKIES_HOST,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_COOKIES_HOST);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_HOST);
	
        gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_COOKIES_NAME, 
						     _("Name"),
                                                     renderer,
                                                     "text", COL_COOKIES_NAME,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_COOKIES_NAME);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_COOKIES_NAME);

	return GTK_WIDGET(treeview);
}

static GtkWidget *
setup_cookie_sites_treeview (PdmDialog *dialog)
{
	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;
	
	treeview = GTK_TREE_VIEW (galeon_dialog_get_control 
				  (GALEON_DIALOG(dialog),
				  PROP_COOKIE_SITES_TREEVIEW));

	
	
        /* set tree model */
        liststore = gtk_list_store_new (3,
                                        G_TYPE_STRING,
                                        G_TYPE_STRING,
                                        G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible (treeview, TRUE);
	selection = gtk_tree_view_get_selection (treeview);
	gtk_tree_selection_set_mode (selection,
				     GTK_SELECTION_MULTIPLE);

	renderer = gtk_cell_renderer_text_new ();

	gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_COOKIE_SITES_DOMAIN, 
						     _("Domain"),
                                                     renderer,
                                                     "text", COL_COOKIE_SITES_DOMAIN,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_COOKIE_SITES_DOMAIN);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_COOKIE_SITES_DOMAIN);
	
        gtk_tree_view_insert_column_with_attributes (treeview,
                                                     COL_COOKIE_SITES_STATUS, 
						     _("Status"),
                                                     renderer,
                                                     "text", COL_COOKIE_SITES_STATUS,
                                                     NULL);
        column = gtk_tree_view_get_column (treeview, COL_COOKIE_SITES_STATUS);
        gtk_tree_view_column_set_resizable (column, TRUE);
        gtk_tree_view_column_set_reorderable (column, TRUE);
        gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id (column, COL_COOKIE_SITES_STATUS);

	return GTK_WIDGET(treeview);
}

static GtkWidget *
setup_image_sites_treeview (PdmDialog *dialog)
{
	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;
	
	treeview = GTK_TREE_VIEW(galeon_dialog_get_control 
				 (GALEON_DIALOG(dialog),
				 PROP_IMAGE_SITES_TREEVIEW));

	
	
        /* set tree model */
        liststore = gtk_list_store_new(3,
                                       G_TYPE_STRING,
                                       G_TYPE_STRING,
                                       G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible(treeview, TRUE);
	selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_set_mode(selection,
				    GTK_SELECTION_MULTIPLE);

	renderer = gtk_cell_renderer_text_new();

	gtk_tree_view_insert_column_with_attributes(treeview,
                                                    COL_IMAGE_SITES_DOMAIN, 
						    _("Domain"),
                                                    renderer,
                                                    "text", COL_IMAGE_SITES_DOMAIN,
                                                    NULL);
        column = gtk_tree_view_get_column(treeview, COL_IMAGE_SITES_DOMAIN);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_IMAGE_SITES_DOMAIN);
	
        gtk_tree_view_insert_column_with_attributes(treeview,
                                                    COL_IMAGE_SITES_STATUS, 
						    _("Status"),
                                                    renderer,
                                                    "text", COL_IMAGE_SITES_STATUS,
                                                    NULL);
        column = gtk_tree_view_get_column(treeview, COL_IMAGE_SITES_STATUS);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_IMAGE_SITES_STATUS);

	return GTK_WIDGET(treeview);
}

static GtkWidget *
setup_popup_sites_treeview (PdmDialog *dialog)
{
	GtkTreeView *treeview;
        GtkListStore *liststore;
        GtkCellRenderer *renderer;
        GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeModel *sorter, *filter;
	
	treeview = GTK_TREE_VIEW(galeon_dialog_get_control 
				 (GALEON_DIALOG(dialog),
				 PROP_POPUP_SITES_TREEVIEW));

	
	
        /* set tree model */
        liststore = gtk_list_store_new(3,
                                       G_TYPE_STRING,
                                       G_TYPE_STRING,
                                       G_TYPE_POINTER);

	filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(liststore), NULL);
	sorter = gtk_tree_model_sort_new_with_model(filter);

        gtk_tree_view_set_model (treeview, GTK_TREE_MODEL(sorter));
        gtk_tree_view_set_headers_visible(treeview, TRUE);
	selection = gtk_tree_view_get_selection(treeview);
	gtk_tree_selection_set_mode(selection,
				    GTK_SELECTION_MULTIPLE);

	renderer = gtk_cell_renderer_text_new();

	gtk_tree_view_insert_column_with_attributes(treeview,
                                                    COL_POPUP_SITES_DOMAIN, 
						    _("Domain"),
                                                    renderer,
                                                    "text", COL_POPUP_SITES_DOMAIN,
                                                    NULL);
        column = gtk_tree_view_get_column(treeview, COL_POPUP_SITES_DOMAIN);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_POPUP_SITES_DOMAIN);
	
        gtk_tree_view_insert_column_with_attributes(treeview,
                                                    COL_POPUP_SITES_STATUS, 
						    _("Status"),
                                                    renderer,
                                                    "text", COL_POPUP_SITES_STATUS,
                                                    NULL);
        column = gtk_tree_view_get_column(treeview, COL_POPUP_SITES_STATUS);
        gtk_tree_view_column_set_resizable(column, TRUE);
        gtk_tree_view_column_set_reorderable(column, TRUE);
        gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
        gtk_tree_view_column_set_sort_column_id(column, COL_POPUP_SITES_STATUS);

	return GTK_WIDGET(treeview);
}

static GList *
get_remove_list(PdmActionInfo *action)
{
	GList *refs, *l;
	GList *remove_list = NULL;
	GtkTreeModel *model, *sorter, *filter;

	sorter = gtk_tree_view_get_model(GTK_TREE_VIEW(action->treeview));
	filter = gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(sorter));
	model = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter));

	action->lock_selection = TRUE;

	refs = get_model_selection_refs(GTK_TREE_VIEW(action->treeview));
	refs = g_list_sort(refs, (GCompareFunc)tree_row_reference_compare);
	refs = g_list_reverse(refs);

	for (l = refs; l != NULL; l = l->next)
	{
		GtkTreeIter iter;
		gpointer data;
		GtkTreePath *path;
		GValue val = {0, };

		if (!gtk_tree_row_reference_valid((GtkTreeRowReference *)l->data))
		{
			continue;
		}

		path = gtk_tree_row_reference_get_path 
				((GtkTreeRowReference *)l->data);

		gtk_tree_model_get_iter(model, &iter, path);

		gtk_tree_model_get_value 
			(model, &iter, action->data_col, &val);
		data = g_value_get_pointer (&val);

		gtk_list_store_remove (GTK_LIST_STORE(model),
				       &iter);

		gtk_tree_model_row_deleted(model, path);
		gtk_tree_path_free(path);

		action->list = g_list_remove (action->list, data);
		remove_list = g_list_append (remove_list, data);
	}

	gul_gui_treeview_free_selection_refs(refs);

	gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(filter));

	action->lock_selection = FALSE;

	/* Callback will clear the cookie info fields */
	cookies_treeview_selection_changed_cb(NULL, action->dialog);

	return remove_list;
}

static void
pdm_dialog_remove_button_clicked_cb (GtkWidget *button,
				     PdmActionInfo *action)
{
	GList *remove_list = get_remove_list(action);
	if (remove_list)
	{
		action->remove (action, remove_list);
		action->free (action, remove_list);
	}
}

static void
setup_action (PdmActionInfo *action)
{
	GList *l;
	GtkWidget *remove_button, *clear_button, *find_entry;
	GtkTreeSelection *selection;
	GtkTreeModelFilter *filter;
	
	for (l = action->list; l != NULL; l = l->next)
	{
		action->add (action, l->data);
	}

	remove_button = galeon_dialog_get_control(GALEON_DIALOG(action->dialog), 
						  action->remove_id);
	g_signal_connect (remove_button, "clicked",
			  G_CALLBACK(pdm_dialog_remove_button_clicked_cb),
			  action);
	
	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(action->treeview));
	g_signal_connect (selection, "changed",
			  G_CALLBACK(action_treeview_selection_changed_cb),
			  action);

	filter = get_filter_from_treeview(action->treeview);
	gtk_tree_model_filter_set_visible_func(filter, visibility_filter_func,
					       action, NULL);

	find_entry = galeon_dialog_get_control(GALEON_DIALOG(action->dialog),
					       (action->remove_id)+1);
	g_signal_connect(find_entry, "changed",
			 G_CALLBACK(action_find_entry_changed_cb),
			 action);

	clear_button = galeon_dialog_get_control(GALEON_DIALOG(action->dialog),
						 (action->remove_id)+2);
	g_signal_connect(clear_button, "clicked",
			 G_CALLBACK(action_clear_button_clicked_cb),
			 action);
}

static void
pdm_dialog_cookie_add (PdmActionInfo *action, 
		       gpointer cookie)
{
	GtkListStore *store;
	GtkTreeIter iter;
	CookieInfo *cinfo = (CookieInfo *)cookie;

	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append (store, &iter);
        gtk_list_store_set (store,
                            &iter,
			    COL_COOKIES_HOST, cinfo->domain,
                            COL_COOKIES_NAME, cinfo->name,
			    COL_COOKIES_DATA, cinfo,
                            -1);
}

static void
pdm_dialog_password_add (PdmActionInfo *action, 
			 gpointer password)
{
	GtkListStore *store;
	GtkTreeIter iter;
	PasswordInfo *pinfo = (PasswordInfo *)password;

	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append (store, &iter);
        gtk_list_store_set (store,
                            &iter,
                            COL_PASSWORDS_HOST, pinfo->host,
                            COL_PASSWORDS_USER, pinfo->username,
			    COL_PASSWORDS_DATA, pinfo,
                            -1);
}

static void
pdm_dialog_password_site_add(PdmActionInfo *action, 
			     gpointer password_site)
{
	GtkListStore *store;
	GtkTreeIter iter;
	PasswordInfo *pinfo = (PasswordInfo *)password_site;

	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append(store, &iter);
        gtk_list_store_set(store,
                           &iter,
                           COL_PASSWORD_SITES_HOST, pinfo->host,
                           COL_PASSWORD_SITES_STATUS, _("Cannot save passwords"),
			   COL_PASSWORD_SITES_DATA, pinfo,
                           -1);
}

static void
pdm_dialog_cookie_sites_reload_cb(GtkWidget *button,
				  PdmActionInfo *action)
{
	GList *l;
	GaleonEmbedShell *shell;
	GtkListStore *store;

	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));
	gtk_list_store_clear(store);

	action->free(action, action->list);

	shell = galeon_shell_get_embed_shell(galeon_shell);

	galeon_embed_shell_list_permissions(shell, COOKIES_PERMISSION,
					    &action->list);

	for (l = action->list; l != NULL; l = l->next)
	{
		action->add(action, l->data);
	}
}

static void
pdm_dialog_cookie_site_add (PdmActionInfo *action, 
		            gpointer cookie_site)
{
	GtkListStore *store;
	GtkTreeIter iter;
	PermissionInfo *pinfo = (PermissionInfo *)cookie_site;
	
	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append (store, &iter);
        gtk_list_store_set (store,
                            &iter,
			    COL_COOKIE_SITES_DOMAIN, pinfo->domain,
                            COL_COOKIE_SITES_STATUS, pinfo->status 
			                             ? _("Can set cookies") 
						     : _("Cannot set cookies"),
			    COL_COOKIE_SITES_DATA,   pinfo,
                            -1);
}

static void
pdm_dialog_image_site_add (PdmActionInfo *action, 
		            gpointer image_site)
{
	GtkListStore *store;
	GtkTreeIter iter;
	PermissionInfo *pinfo = (PermissionInfo *)image_site;
	
	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append(store, &iter);
        gtk_list_store_set(store,
                           &iter,
			   COL_IMAGE_SITES_DOMAIN, pinfo->domain,
                           COL_IMAGE_SITES_STATUS, pinfo->status 
			                           ? _("Can show images") 
						   : _("Cannot show images"),
			   COL_IMAGE_SITES_DATA,   pinfo,
                           -1);
}

static void
pdm_dialog_popup_site_add(PdmActionInfo *action, 
			  gpointer popup_site)
{
	GtkListStore *store;
	GtkTreeIter iter;
	PermissionInfo *pinfo = (PermissionInfo *)popup_site;

	store = GTK_LIST_STORE(get_model_from_treeview(action->treeview));

	gtk_list_store_append(store, &iter);
        gtk_list_store_set(store,
                           &iter,
                           COL_POPUP_SITES_DOMAIN, pinfo->domain,
                           COL_POPUP_SITES_STATUS, _("Can show popups"),
			   COL_POPUP_SITES_DATA, pinfo,
                           -1);
}

static void
real_cookie_remove (PdmActionInfo *info,
		    GList *data,
		    gboolean block)
{	
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell (galeon_shell);
	galeon_embed_shell_remove_cookies (shell, data, block);
}

void
pdm_dialog_cookie_remove_block_button_clicked_cb (GtkWidget *button,
						  PdmActionInfo *action)
{
	GList *remove_list = get_remove_list(action);
	if (remove_list)
	{
		real_cookie_remove (action, remove_list, TRUE);
		action->free (action, remove_list);
	}
}

static void
pdm_dialog_cookie_remove (PdmActionInfo *info,
			  GList *data)
{	
	real_cookie_remove(info, data, FALSE);
}

static void
pdm_dialog_password_remove (PdmActionInfo *info,
			    GList *data)
{
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell (galeon_shell);
	galeon_embed_shell_remove_passwords (shell, data, PASSWORD_PASSWORD);
}

static void
pdm_dialog_password_site_remove(PdmActionInfo *info,
				GList *data)
{
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell(galeon_shell);
	galeon_embed_shell_remove_passwords(shell, data, PASSWORD_REJECT);
}

static void
pdm_dialog_cookie_site_remove (PdmActionInfo *info,
			       GList *data)
{
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell (galeon_shell);
	galeon_embed_shell_remove_permissions (shell, COOKIES_PERMISSION, data);
}

static void
pdm_dialog_image_site_remove(PdmActionInfo *info,
			     GList *data)
{
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell(galeon_shell);
	galeon_embed_shell_remove_permissions(shell, IMAGES_PERMISSION, data);
}

static void
pdm_dialog_popup_site_remove(PdmActionInfo *info,
			     GList *data)
{
	GaleonEmbedShell *shell;
	shell = galeon_shell_get_embed_shell(galeon_shell);
	galeon_embed_shell_remove_permissions(shell, POPUPS_PERMISSION, data);
}

static void
pdm_dialog_cookies_free (PdmActionInfo *info,
			 GList *data)
{	
	GaleonEmbedShell *shell;
	GList *l;
		
	shell = galeon_shell_get_embed_shell (galeon_shell);
	l = data ? data : info->list;
	galeon_embed_shell_free_cookies (shell, l);
}

static void
pdm_dialog_passwords_free (PdmActionInfo *info,
			   GList *data)
{
	GaleonEmbedShell *shell;
	GList *l;
	
	shell = galeon_shell_get_embed_shell (galeon_shell);
	l = data ? data : info->list;
	galeon_embed_shell_free_passwords (shell, l);
}

static void
pdm_dialog_site_permissions_free(PdmActionInfo *info,
				 GList *data)
{
	GaleonEmbedShell *shell;
	GList *l;
	
	shell = galeon_shell_get_embed_shell (galeon_shell);
	l = data ? data : info->list;
	galeon_embed_shell_free_permissions (shell, l);
}

/* Group all Properties and Remove buttons in the same size group to avoid the
 * little jerk you get otherwise when switching pages because one set of
 * buttons is wider than another. */
static void
group_button_allocations (GaleonDialog *dialog)
{
	const gint props[] =
	{
		PROP_COOKIES_REMOVE,
		PROP_COOKIES_REMOVE_BLOCK,
		PROP_PASSWORDS_REMOVE,
		PROP_COOKIE_SITES_REMOVE,
		PROP_IMAGE_SITES_REMOVE,
		PROP_PASSWORD_SITES_REMOVE,
		PROP_POPUP_SITES_REMOVE
	};
	GtkSizeGroup *size_group;
	guint i;

	size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);

	for (i = 0; i < G_N_ELEMENTS (props); ++i)
	{
		GtkWidget *w;
		w = galeon_dialog_get_control (dialog, props[i]);
		gtk_size_group_add_widget (size_group,  w);
	}

	g_object_unref(size_group);
}

static void
pdm_dialog_init (PdmDialog *dialog)
{	
	GaleonEmbedShell *shell;
	PdmActionInfo *cookies;
	PdmActionInfo *passwords;
	PdmActionInfo *cookie_sites;
	PdmActionInfo *image_sites;
	PdmActionInfo *password_sites;
	PdmActionInfo *popup_sites;
	GtkWidget *cookies_tv;
	GtkWidget *passwords_tv;
	GtkWidget *cookie_sites_tv;
	GtkWidget *image_sites_tv;
	GtkWidget *password_sites_tv;
	GtkWidget *popup_sites_tv;
	GtkWidget *remove_block_button;
	
	shell = galeon_shell_get_embed_shell (galeon_shell);
	
	dialog->priv = g_new0 (PdmDialogPrivate, 1);
	dialog->priv->cookies = NULL;
	dialog->priv->passwords = NULL;
	
	galeon_dialog_construct (GALEON_DIALOG(dialog),
                                 properties,
                                 "galeon.glade",
                                 "pdm_dialog");

	gul_state_monitor_window 
		(galeon_dialog_get_control (GALEON_DIALOG(dialog), PROP_DIALOG),
		 "PDM", -1, -1);

	dialog->priv->notebook = 
		galeon_dialog_get_control (GALEON_DIALOG(dialog),
				           PROP_NOTEBOOK);

	group_button_allocations (GALEON_DIALOG (dialog));

	cookies_tv = setup_cookies_treeview (dialog);
	passwords_tv = setup_passwords_treeview (dialog);
	cookie_sites_tv = setup_cookie_sites_treeview (dialog);
	image_sites_tv = setup_image_sites_treeview(dialog);
	password_sites_tv = setup_password_sites_treeview(dialog);
	popup_sites_tv = setup_popup_sites_treeview(dialog);

	cookies = g_new0 (PdmActionInfo, 1);
	galeon_embed_shell_list_cookies (shell, &cookies->list);
	cookies->dialog = dialog;
	cookies->remove_id = PROP_COOKIES_REMOVE;
	cookies->add = pdm_dialog_cookie_add;
	cookies->remove = pdm_dialog_cookie_remove;
	cookies->free = pdm_dialog_cookies_free;
	cookies->treeview = cookies_tv;
	cookies->data_col = COL_COOKIES_DATA;
	setup_action (cookies);

	remove_block_button =
		galeon_dialog_get_control(GALEON_DIALOG(cookies->dialog),
					  PROP_COOKIES_REMOVE_BLOCK);
		 
	g_signal_connect(remove_block_button, "clicked",
			 G_CALLBACK(pdm_dialog_cookie_remove_block_button_clicked_cb),
			 cookies);

	passwords = g_new0 (PdmActionInfo, 1);
	galeon_embed_shell_list_passwords (shell, PASSWORD_PASSWORD,
					   &passwords->list);
	passwords->dialog = dialog;
	passwords->remove_id = PROP_PASSWORDS_REMOVE;
	passwords->add = pdm_dialog_password_add;
	passwords->remove = pdm_dialog_password_remove;
	passwords->free = pdm_dialog_passwords_free;
	passwords->treeview = passwords_tv;
	passwords->data_col = COL_PASSWORDS_DATA;
	setup_action (passwords);

	password_sites = g_new0(PdmActionInfo, 1);
	galeon_embed_shell_list_passwords(shell, PASSWORD_REJECT,
					  &password_sites->list);
	password_sites->dialog = dialog;
	password_sites->remove_id = PROP_PASSWORD_SITES_REMOVE;
	password_sites->add = pdm_dialog_password_site_add;
	password_sites->remove = pdm_dialog_password_site_remove;
	password_sites->free = pdm_dialog_passwords_free;
	password_sites->treeview = password_sites_tv;
	password_sites->data_col = COL_PASSWORD_SITES_DATA;
	setup_action(password_sites);

	cookie_sites = g_new0 (PdmActionInfo, 1);
	galeon_embed_shell_list_permissions (shell, COOKIES_PERMISSION,
					     &cookie_sites->list);
	cookie_sites->dialog	= dialog;
	cookie_sites->remove_id = PROP_COOKIE_SITES_REMOVE;
	cookie_sites->add	= pdm_dialog_cookie_site_add;
	cookie_sites->remove	= pdm_dialog_cookie_site_remove;
	cookie_sites->free	= pdm_dialog_site_permissions_free;
	cookie_sites->treeview	= cookie_sites_tv;
	cookie_sites->data_col	= COL_COOKIE_SITES_DATA;
	setup_action (cookie_sites);

	/* 
	 * Must be attached after the callback that actually blocks the cookie
	 * site, otherwise it won't reload the updated list
	 */
	g_signal_connect(remove_block_button, "clicked",
			 G_CALLBACK(pdm_dialog_cookie_sites_reload_cb),
			 cookie_sites);

	image_sites = g_new0(PdmActionInfo, 1);
	galeon_embed_shell_list_permissions(shell, IMAGES_PERMISSION,
					    &image_sites->list);
	image_sites->dialog	= dialog;
	image_sites->remove_id	= PROP_IMAGE_SITES_REMOVE;
	image_sites->add	= pdm_dialog_image_site_add;
	image_sites->remove	= pdm_dialog_image_site_remove;
	image_sites->free	= pdm_dialog_site_permissions_free;
	image_sites->treeview	= image_sites_tv;
	image_sites->data_col	= COL_IMAGE_SITES_DATA;
	setup_action(image_sites);

	popup_sites = g_new0(PdmActionInfo, 1);
	galeon_embed_shell_list_permissions(shell, POPUPS_PERMISSION,
					    &popup_sites->list);
	popup_sites->dialog	= dialog;
	popup_sites->remove_id	= PROP_POPUP_SITES_REMOVE;
	popup_sites->add	= pdm_dialog_popup_site_add;
	popup_sites->remove	= pdm_dialog_popup_site_remove;
	popup_sites->free	= pdm_dialog_site_permissions_free;
	popup_sites->treeview	= popup_sites_tv;
	popup_sites->data_col	= COL_POPUP_SITES_DATA;
	setup_action(popup_sites);

	dialog->priv->cookies = cookies;
	dialog->priv->passwords = passwords;
	dialog->priv->password_sites = password_sites;
	dialog->priv->cookie_sites = cookie_sites;
	dialog->priv->image_sites = image_sites;
	dialog->priv->popup_sites = popup_sites;

	/* Sort by host/domain name.  Setting it here, after the treeview has
	 * been filled, is noticeably faster than setting it in
	 * setup_*_treeview and adding the items in sorted liststores.
	 */

#define set_sort_column(treeview, column) \
	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE( \
		gtk_tree_view_get_model(GTK_TREE_VIEW(treeview))), \
					     column, GTK_SORT_ASCENDING)

	set_sort_column (cookies_tv,        COL_COOKIES_HOST);
	set_sort_column (cookie_sites_tv,   COL_COOKIE_SITES_DOMAIN);
	set_sort_column (image_sites_tv,    COL_IMAGE_SITES_DOMAIN);
	set_sort_column (passwords_tv,      COL_PASSWORDS_HOST);
	set_sort_column (password_sites_tv, COL_PASSWORD_SITES_HOST);
	set_sort_column (popup_sites_tv,    COL_POPUP_SITES_DOMAIN);

#undef set_sort_column
}

static void
pdm_dialog_finalize (GObject *object)
{
	PdmDialog *dialog;

        g_return_if_fail (object != NULL);
        g_return_if_fail (IS_PDM_DIALOG (object));

	dialog = PDM_DIALOG (object);

        g_return_if_fail (dialog->priv != NULL);

	pdm_dialog_site_permissions_free (dialog->priv->popup_sites, NULL);
	pdm_dialog_site_permissions_free (dialog->priv->cookie_sites, NULL);
	pdm_dialog_site_permissions_free (dialog->priv->image_sites, NULL);
	pdm_dialog_passwords_free (dialog->priv->passwords, NULL);
	pdm_dialog_passwords_free (dialog->priv->password_sites, NULL);
	pdm_dialog_cookies_free (dialog->priv->cookies, NULL);
	
        g_free (dialog->priv);

        G_OBJECT_CLASS (parent_class)->finalize (object);
}

GaleonDialog *
pdm_dialog_new (GtkWidget *window)
{
	PdmDialog *dialog;
	
	dialog = PDM_DIALOG (g_object_new (PDM_DIALOG_TYPE,
				     	   "ParentWindow", window,
				           NULL));

	return GALEON_DIALOG(dialog);
}

void
pdm_dialog_set_current_page (PdmDialog *dialog, PdmDialogPage page)
{
	GtkNotebook *notebook;
	guint        n_pages;
	
	notebook = GTK_NOTEBOOK(dialog->priv->notebook);
	n_pages  = gtk_notebook_get_n_pages (notebook);

	if (page < n_pages)
	{
		gtk_notebook_set_current_page (notebook, page);
	}
	else
	{
		g_warning ("%s: invalid page `%d'", G_STRLOC, page);
	}
}

void
pdm_dialog_close_button_clicked_cb (GtkWidget *button,
			            PdmDialog *dialog)
{
	g_object_unref (dialog);
}
