 /*
 *  Copyright (C) 200-2003 Marco Pesenti Gritti
 *  Copyright (C) 2003, 2004 Christian Persch
 *
 *  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.
 *
 *  $Id$
 */

#include "config.h"

#include "prefs-dialog.h"
#include "ephy-dialog.h"
#include "ephy-prefs.h"
#include "ephy-embed-shell.h"
#include "ephy-shell.h"
#include "ephy-session.h"
#include "ephy-embed-prefs.h"
#include "ephy-embed-single.h"
#include "ephy-shell.h"
#include "ephy-gui.h"
#include "eel-gconf-extensions.h"
#include "ephy-langs.h"
#include "ephy-encodings.h"
#include "ephy-debug.h"
#include "ephy-file-chooser.h"
#include "ephy-file-helpers.h"
#include "ephy-tree-model-node.h"
#include "ephy-tree-model-sort.h"

#include <glib/gi18n.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkcellrenderertext.h>
#include <gtk/gtkcelllayout.h>
#include <gtk/gtktreeselection.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkradiobutton.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkcombobox.h>
#include <gtk/gtktreemodel.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtkimage.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkstock.h>
#include <gtk/gtknotebook.h>
#include <string.h>

#define CONF_FONTS_FOR_LANGUAGE	"/apps/epiphany/dialogs/preferences_font_language"

static void prefs_dialog_class_init	(PrefsDialogClass *klass);
static void prefs_dialog_init		(PrefsDialog *pd);

/* Glade callbacks */
void prefs_clear_cache_button_clicked_cb	(GtkWidget *button,
						 gpointer data);
void prefs_dialog_response_cb			(GtkDialog *widget,
						 gint response_id,
						 EphyDialog *dialog);
void prefs_homepage_current_button_clicked_cb	(GtkWidget *button,
						 EphyDialog *dialog);
void prefs_homepage_blank_button_clicked_cb	(GtkWidget *button,
						 EphyDialog *dialog);
void prefs_language_more_button_clicked_cb	(GtkWidget *button,
						 EphyDialog *dialog);
void prefs_download_path_button_clicked_cb	(GtkWidget *button,
						 PrefsDialog *dialog);
void language_editor_add_button_clicked_cb	(GtkWidget *button,
						 PrefsDialog *pd);
void language_editor_remove_button_clicked_cb	(GtkWidget *button,
						 PrefsDialog *pd);
void language_editor_up_button_clicked_cb	(GtkWidget *button,
						 PrefsDialog *pd);
void language_editor_down_button_clicked_cb	(GtkWidget *button,
						 PrefsDialog *pd);

#ifdef HAVE_ISO_CODES
static const char *languages[] =
{
	/* If you're missing your language/locale combination, file a bug at
	 * http://bugzilla.gnome.org/enter_bug.cgi?product=epiphany
	 */
	"af",
	"am",
	"an",
	"ar",
	"ar-ae",
	"ar-bh",
	"ar-dz",
	"ar-eg",
	"ar-iq",
	"ar-jo",
	"ar-kw",
	"ar-lb",
	"ar-ly",
	"ar-ma",
	"ar-om",
	"ar-qa",
	"ar-sa",
	"ar-sy",
	"ar-tn",
	"ar-ye",
	"ast",
	"az",
	"be",
	"bg",
	"bn",
	"br",
	"bs",
	"ca",
	"ce",
	"ch",
	"co",
	"cs",
	"cv",
	"cy",
	"da",
	"de",
	"de-at",
	"de-ch",
	"de-de",
	"de-li",
	"de-lu",
	"el",
	"en",
	"en-au",
	"en-bz",
	"en-ca",
	"en-gb",
	"en-ie",
	"en-jm",
	"en-nz",
	"en-ph",
	"en-tt",
	"en-us",
	"en-za",
	"en-zw",
	"eo",
	"es",
	"es-ar",
	"es-bo",
	"es-cl",
	"es-co",
	"es-cr",
	"es-do",
	"es-ec",
	"es-es",
	"es-gt",
	"es-hn",
	"es-mx",
	"es-ni",
	"es-pa",
	"es-pe",
	"es-pr",
	"es-py",
	"es-sv",
	"es-uy",
	"es-ve",
	"et",
	"eu",
	"fa",
	"fi",
	"fj",
	"fo",
	"fr",
	"fr-be",
	"fr-ca",
	"fr-ch",
	"fr-fr",
	"fr-lu",
	"fr-mc",
	"fy",
	"ga",
	"gd",
	"gl",
	"gu",
	"he",
	"hsb",
	"hi",
	"hr",
	"ht",
	"hu",
	"hy",
	"ia",
	"id",
	"ie",
	"is",
	"it",
	"it-ch",
	"it-it",
	"iu",
	"ja",
	"ka",
	"kk",
	"ko",
	"ko-kp",
	"ko-kr",
	"ky",
	"la",
	"lb",
	"li",
	"lt",
	"lv",
	"mi",
	"mk-mk",
	"ml",
	"mn",
	"mo",
	"mr",
	"ms",
	"nb",
	"ne",
	"ng",
	"nl",
	"nl-be",
	"nn",
	"no",
	"nv",
	"oc",
	"om",
	"pa",
	"pl",
	"pt",
	"pt-br",
	"qu",
	"rm",
	"ro",
	"ru",
	"sa",
	"sc",
	"sd",
	"sg",
	"sk",
	"sl",
	"so",
	"sq",
	"sr",
	"sv",
	"sv-fi",
	"sw",
	"ta",
	"th",
	"tk",
	"tr",
	"uk",
	"ve",
	"vi",
	"vo",
	"wa",
	"xh",
	"yi",
	"zh",
	"zh-cn",
	"zh-hk",
	"zh-sg",
	"zh-tw",
	"zu"
};
#else
static const
struct
{
	char *code;
	char *name;
}
languages [] =
{
	{ "af",		N_("Afrikaans") },
	{ "ar",		N_("Arabic") },
	{ "az",		N_("Azerbaijani") },
	{ "be",		N_("Byelorussian") },
	{ "bg",		N_("Bulgarian") },
	{ "br",		N_("Breton") },
	{ "ca",		N_("Catalan") },
	{ "cs",		N_("Czech") },
	{ "da",		N_("Danish") },
	{ "de",		N_("German") },
	{ "en",		N_("English") },
	{ "el",		N_("Greek") },
	{ "eo",		N_("Esperanto") },
	{ "es",		N_("Spanish") },
	{ "et",		N_("Estonian") },
	{ "eu",		N_("Basque") },
	{ "fi",		N_("Finnish") },
	{ "fo",		N_("Faeroese") },
	{ "fr",		N_("French") },
	{ "ga",		N_("Irish") },
	{ "gd",		N_("Scots Gaelic") },
	{ "gl",		N_("Galician") },
	{ "he",		N_("Hebrew") },
	{ "hr",		N_("Croatian") },
	{ "hu",		N_("Hungarian") },
	{ "id",		N_("Indonesian") },
	{ "is",		N_("Icelandic") },
	{ "it",		N_("Italian") },
	{ "ja",		N_("Japanese") },
	{ "ko",		N_("Korean") },
	{ "lt",		N_("Lithuanian") },
	{ "lv",		N_("Latvian") },
	{ "mk",		N_("Macedonian") },
	{ "ms",		N_("Malay") },
	{ "nl",		N_("Dutch") },
	{ "nb",		N_("Norwegian/Bokmal") },
	{ "nn",		N_("Norwegian/Nynorsk") },
	{ "no",		N_("Norwegian") },
	{ "pl",		N_("Polish") },
	{ "pt",		N_("Portuguese") },
	{ "pt-br",	N_("Portuguese of Brazil") },
	{ "ro",		N_("Romanian") },
	{ "ru",		N_("Russian") },
	{ "sk",		N_("Slovak") },
	{ "sl",		N_("Slovenian") },
	{ "sq",		N_("Albanian") },
	{ "sr",		N_("Serbian") },
	{ "sv",		N_("Swedish") },
	{ "ta",		N_("Tamil") },
	{ "tr",		N_("Turkish") },
	{ "uk",		N_("Ukrainian") },
	{ "vi",		N_("Vietnamese") },
	{ "wa",		N_("Walloon") },
	{ "zh",		N_("Chinese") },
	{ "zh-cn",	N_("Simplified Chinese") },
	{ "zh-tw",	N_("Traditional Chinese") }
};
#endif /* HAVE_ISO_CODES */

static const
char *cookies_accept_enum [] =
{
	"anywhere", "current site", "nowhere"
};
static guint n_cookies_accept_enum = G_N_ELEMENTS (cookies_accept_enum);

enum
{
	FONT_TYPE_VARIABLE,
	FONT_TYPE_MONOSPACE
};

const
char *fonts_types[] =
{
	"variable",
	"monospace"
};

enum
{
	FONT_SIZE_FIXED,
	FONT_SIZE_VAR,
	FONT_SIZE_MIN
};

const
char *size_prefs [] =
{
	CONF_RENDERING_FONT_FIXED_SIZE,
	CONF_RENDERING_FONT_VAR_SIZE,
	CONF_RENDERING_FONT_MIN_SIZE
};

const
int default_size [] =
{
	10,
	11,
	7
};

enum
{
	WINDOW_PROP,
	NOTEBOOK_PROP,

	/* General */
	HOMEPAGE_ENTRY_PROP,
	HOMEPAGE_CURRENT_PROP,
	HOMEPAGE_BLANK_PROP,
	AUTO_OPEN_PROP,
	DOWNLOAD_PATH_BUTTON_PROP,

	/* Fonts and Colors */
	FONTS_LANGUAGE_PROP,
	VARIABLE_PROP,
	MONOSPACE_PROP,
	FIXED_SIZE_PROP,
	VARIABLE_SIZE_PROP,
	MIN_SIZE_PROP,
	USE_COLORS_PROP,
	USE_FONTS_PROP,

	/* Privacy */
	ALLOW_POPUPS_PROP,
	ALLOW_JAVA_PROP,
	ALLOW_JS_PROP,
	ACCEPT_COOKIES_PROP,
	DISK_CACHE_PROP,

	/* Language */
	AUTO_ENCODING_PROP,
	DEFAULT_ENCODING_PROP,
	DEFAULT_ENCODING_LABEL_PROP,
	AUTO_ENCODING_LABEL_PROP,
	LANGUAGE_ADD_BUTTON_PROP,
	LANGUAGE_REMOVE_BUTTON_PROP,
	LANGUAGE_UP_BUTTON_PROP,
	LANGUAGE_DOWN_BUTTON_PROP,
	LANGUAGE_TREEVIEW_PROP
};

static const
EphyDialogProperty properties [] =
{
	{ "prefs_dialog",	NULL, PT_NORMAL, 0},
	{ "prefs_notebook",	NULL, PT_NORMAL, 0},

	/* General */
	{ "homepage_entry",			CONF_GENERAL_HOMEPAGE,	  PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "homepage_current_button",		NULL,			  PT_NORMAL,	0 },
	{ "homepage_blank_button",		NULL,			  PT_NORMAL,	0 },
	{ "automatic_downloads_checkbutton",	CONF_AUTO_DOWNLOADS,      PT_AUTOAPPLY,	0 },
	{ "download_path_button",		NULL,			  PT_NORMAL,	0 },

	/* Fonts and Colors */
	{ "fonts_language_combo",	CONF_FONTS_FOR_LANGUAGE,	PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "variable_combo",		NULL,				PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "monospace_combo",		NULL,				PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "fixed_size_spinbutton",	NULL,				PT_AUTOAPPLY,	0 },
	{ "variable_size_spinbutton",	NULL,				PT_AUTOAPPLY,	0 },
	{ "min_size_spinbutton",	NULL,				PT_AUTOAPPLY,	0 },
	{ "use_colors_checkbutton",	CONF_RENDERING_USE_OWN_COLORS,	PT_AUTOAPPLY,	0 },
	{ "use_fonts_checkbutton",	CONF_RENDERING_USE_OWN_FONTS,	PT_AUTOAPPLY,	0 },

	/* Privacy */
	{ "popups_allow_checkbutton",		CONF_SECURITY_ALLOW_POPUPS,	  PT_AUTOAPPLY, 0 },
	{ "enable_java_checkbutton",		CONF_SECURITY_JAVA_ENABLED,	  PT_AUTOAPPLY, 0 },
	{ "enable_javascript_checkbutton",	CONF_SECURITY_JAVASCRIPT_ENABLED, PT_AUTOAPPLY, 0 },
	{ "cookies_radiobutton",		CONF_SECURITY_COOKIES_ACCEPT,	  PT_AUTOAPPLY, G_TYPE_STRING },
	{ "disk_cache_spin",			CONF_NETWORK_CACHE_SIZE,	  PT_AUTOAPPLY, 0 },

	/* Languages */
	{ "auto_encoding_combo",	CONF_LANGUAGE_AUTODETECT_ENCODING,	PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "default_encoding_combo",	CONF_LANGUAGE_DEFAULT_ENCODING,		PT_AUTOAPPLY,	G_TYPE_STRING },
	{ "default_encoding_label",	NULL,					PT_NORMAL,	0 },
	{ "auto_encoding_label",	NULL,					PT_NORMAL,	0 },
	{ "lang_add_button",		NULL,					PT_NORMAL,	0 },
	{ "lang_remove_button",		NULL,					PT_NORMAL,	0 },
	{ "lang_up_button",		NULL,					PT_NORMAL,	0 },
	{ "lang_down_button",		NULL,					PT_NORMAL,	0 },
	{ "lang_treeview",		NULL,					PT_NORMAL,	0 },

	{ NULL }
};

enum
{
	LANGUAGE_DIALOG,
	LANGUAGE_PROP,
	LANGUAGE_ACCEPT_BUTTON_PROP
};

static const
EphyDialogProperty add_lang_props [] =
{
	{ "add_language_dialog", NULL,	PT_NORMAL,	0 },
	{ "languages_treeview",	 NULL,	PT_NORMAL,	G_TYPE_STRING },
	{ "add_button",		 NULL,	PT_NORMAL,	0 },

	{ NULL }
};

enum
{
	COL_FONTS_LANG_NAME,
	COL_FONTS_LANG_CODE
};

enum
{
	COL_LANG_NAME,
	COL_LANG_CODE
};

enum
{
	COL_ENC_NAME,
	COL_ENC_CODE
};

#define EPHY_PREFS_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_PREFS_DIALOG, PrefsDialogPrivate))

struct PrefsDialogPrivate
{
	GtkWidget *download_dir_chooser;
	GtkTreeView *lang_treeview;
	GtkTreeModel *lang_model;
	EphyDialog *add_lang_dialog;
	GtkWidget *lang_add_button;
	GtkWidget *lang_remove_button;
	GtkWidget *lang_up_button;
	GtkWidget *lang_down_button;
#ifdef HAVE_ISO_CODES
	GHashTable *iso_639_table;
	GHashTable *iso_3166_table;
#endif
};

/* gtk+' gettext domain */
#define GTK_DOMAIN "gtk20"

static GObjectClass *parent_class = NULL;

GType
prefs_dialog_get_type (void)
{
	static GType type = 0;

	if (G_UNLIKELY (type == 0))
	{
		static const GTypeInfo our_info =
		{
			sizeof (PrefsDialogClass),
			NULL, /* base_init */
			NULL, /* base_finalize */
			(GClassInitFunc) prefs_dialog_class_init,
			NULL,
			NULL, /* class_data */
			sizeof (PrefsDialog),
			0, /* n_preallocs */
			(GInstanceInitFunc) prefs_dialog_init
		};

		type = g_type_register_static (EPHY_TYPE_DIALOG,
					       "PrefsDialog",
					       &our_info, 0);
	}

	return type;
}

static void
prefs_dialog_finalize (GObject *object)
{
	PrefsDialog *dialog = EPHY_PREFS_DIALOG (object);

	if (dialog->priv->add_lang_dialog != NULL)
	{
		g_object_remove_weak_pointer
			(G_OBJECT (dialog->priv->add_lang_dialog),
			(gpointer *) &dialog->priv->add_lang_dialog);
		g_object_unref (dialog->priv->add_lang_dialog);
	}

	if (dialog->priv->download_dir_chooser != NULL)
	{
		g_object_remove_weak_pointer
			(G_OBJECT (dialog->priv->download_dir_chooser),
			 (gpointer *) &dialog->priv->download_dir_chooser);
	}

#ifdef HAVE_ISO_CODES
	g_hash_table_destroy (dialog->priv->iso_639_table);
	g_hash_table_destroy (dialog->priv->iso_3166_table);
#endif

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

static void
prefs_dialog_class_init (PrefsDialogClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);

	parent_class = g_type_class_peek_parent (klass);

	object_class->finalize = prefs_dialog_finalize;

	g_type_class_add_private (object_class, sizeof(PrefsDialogPrivate));
}

static void
prefs_dialog_show_help (EphyDialog *dialog)
{
	GtkWidget *window, *notebook;
	int id;

	char *help_preferences[] = {
		"general-preferences",
		"fonts-and-colors-preferences",
		"privacy-preferences",
		"language-preferences"
	};

	ephy_dialog_get_controls (dialog,
				  properties[WINDOW_PROP].id, &window,
				  properties[NOTEBOOK_PROP].id, &notebook,
				  NULL);

	id = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
	id = CLAMP (id, 0, 3);

	ephy_gui_help (GTK_WINDOW (window), "epiphany", help_preferences[id]);
}

static void
setup_font_combo (EphyDialog *dialog,
		  const char *type,
		  const char *code,
		  int prop)
{
	GtkWidget *combo;
	GtkListStore *store;
	GtkTreeModel *sortmodel;
	GtkTreeIter iter;
	GList *fonts, *l;
	char *name;
	char key[255];
	EphyEmbedSingle *single;

	single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
	fonts = ephy_embed_single_get_font_list (single, code);

	g_snprintf (key, 255, "%s_%s_%s", CONF_RENDERING_FONT, type, code);
	name = eel_gconf_get_string (key);

	/* sanitise the pref */
	if (name == NULL || name[0] == '\0'
	    || g_list_find_custom (fonts, name, (GCompareFunc) strcmp) == NULL)
	{
		if (prop == VARIABLE_PROP)
		{
			eel_gconf_set_string (key, "sans-serif");
		}
		else
		{
			eel_gconf_set_string (key, "monospace");
		}
	}
	g_free (name);

	combo = ephy_dialog_get_control (dialog, properties[prop].id);
	store = gtk_list_store_new (1, G_TYPE_STRING);

	for (l = fonts; l != NULL; l = l->next)
	{
		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter, 0, (char *) l->data, -1);
	}
	g_list_foreach (fonts, (GFunc) g_free, NULL);
	g_list_free (fonts);

	sortmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
	gtk_tree_sortable_set_sort_column_id
		(GTK_TREE_SORTABLE (sortmodel), 0, GTK_SORT_ASCENDING);

	ephy_dialog_set_pref (dialog, properties[prop].id, NULL);

	gtk_combo_box_set_model (GTK_COMBO_BOX (combo), sortmodel);
	gtk_combo_box_set_active (GTK_COMBO_BOX (combo), -1);

	ephy_dialog_set_pref (dialog, properties[prop].id, key);

	g_object_unref (store);
	g_object_unref (sortmodel);
}

static void
fonts_language_changed_cb (EphyDialog *dialog,
			   const GValue *value,
			   gpointer data)
{
	const char *code;
	char key[128];
	int size;

	code = g_value_get_string (value);

	LOG ("fonts language combo changed, new code '%s'", code);

	setup_font_combo (dialog, "variable", code, VARIABLE_PROP);
	setup_font_combo (dialog, "monospace", code, MONOSPACE_PROP);

	g_snprintf (key, sizeof (key), "%s_%s", size_prefs[FONT_SIZE_VAR], code);
	size = eel_gconf_get_integer (key);
	if (size <= 0)
	{
		eel_gconf_set_integer (key, default_size[FONT_SIZE_VAR]);
	}
	ephy_dialog_set_pref (dialog, properties[VARIABLE_SIZE_PROP].id, key);

	g_snprintf (key, sizeof (key), "%s_%s", size_prefs[FONT_SIZE_FIXED], code);
	size = eel_gconf_get_integer (key);
	if (size <= 0)
	{
		eel_gconf_set_integer (key, default_size[FONT_SIZE_FIXED]);
	}
	ephy_dialog_set_pref (dialog, properties[FIXED_SIZE_PROP].id, key);

	g_snprintf (key, sizeof (key), "%s_%s", size_prefs[FONT_SIZE_MIN], code);
	size = eel_gconf_get_integer (key);
	if (size <= 0)
	{
		eel_gconf_set_integer (key, default_size[FONT_SIZE_MIN]);
	}
	ephy_dialog_set_pref (dialog, properties[MIN_SIZE_PROP].id, key);
}

static void
create_fonts_language_menu (EphyDialog *dialog)
{
	GtkWidget *combo;
	GtkCellRenderer *renderer;
	GtkListStore *store;
	GtkTreeModel *sortmodel;
	GtkTreeIter iter;
	guint n_fonts_languages, i;
	const EphyFontsLanguageInfo *fonts_languages;

	combo = ephy_dialog_get_control (dialog, properties[FONTS_LANGUAGE_PROP].id);

	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

	fonts_languages = ephy_font_languages ();
	n_fonts_languages = ephy_font_n_languages ();
	
	for (i = 0; i < n_fonts_languages; i++)
	{
		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COL_FONTS_LANG_NAME, Q_(fonts_languages[i].title),
				    COL_FONTS_LANG_CODE, fonts_languages[i].code,
				    -1);
	}

	sortmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
	gtk_tree_sortable_set_sort_column_id
		(GTK_TREE_SORTABLE (sortmodel), COL_FONTS_LANG_NAME, GTK_SORT_ASCENDING);

	gtk_combo_box_set_model (GTK_COMBO_BOX (combo), sortmodel);

        renderer = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
                                        "text", COL_FONTS_LANG_NAME,
                                        NULL);

	ephy_dialog_set_data_column (dialog, properties[FONTS_LANGUAGE_PROP].id, COL_FONTS_LANG_CODE);

	g_signal_connect (dialog, "changed::fonts_language_combo",
			  G_CALLBACK (fonts_language_changed_cb),
			  NULL);

	g_object_unref (store);
	g_object_unref (sortmodel);
}

static void
create_node_combo (EphyDialog *dialog,
		   int prop,
		   EphyEncodings *encodings,
		   EphyNode *node,
		   const char *key,
		   const char *default_value)
{
	EphyTreeModelNode *nodemodel;
	GtkTreeModel *sortmodel;
	GtkComboBox *combo;
	GtkCellRenderer *renderer;
	char *code;
	int title_col, data_col;

	code = eel_gconf_get_string (key);
	if (code == NULL || ephy_encodings_get_node (encodings, code, FALSE) == NULL)
	{
		/* safe default */
		eel_gconf_set_string (key, default_value);
	}
	g_free (code);

	combo = GTK_COMBO_BOX (ephy_dialog_get_control (dialog, properties[prop].id));

	nodemodel = ephy_tree_model_node_new (node);

	title_col = ephy_tree_model_node_add_prop_column
			(nodemodel, G_TYPE_STRING, EPHY_NODE_ENCODING_PROP_TITLE_ELIDED);
	data_col = ephy_tree_model_node_add_prop_column
			(nodemodel, G_TYPE_STRING, EPHY_NODE_ENCODING_PROP_ENCODING);

	sortmodel = ephy_tree_model_sort_new (GTK_TREE_MODEL (nodemodel));

	gtk_tree_sortable_set_sort_column_id
		(GTK_TREE_SORTABLE (sortmodel), title_col, GTK_SORT_ASCENDING);

	gtk_combo_box_set_model (combo, GTK_TREE_MODEL (sortmodel));

        renderer = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer,
                                        "text", title_col,
                                        NULL);

	ephy_dialog_set_data_column (dialog, properties[prop].id, data_col);

	g_object_unref (nodemodel);
	g_object_unref (sortmodel);
}

static void
language_editor_add (PrefsDialog *pd,
		     const char *code,
		     const char *desc)
{
	GtkTreeIter iter;

	g_return_if_fail (code != NULL && desc != NULL);

	if (gtk_tree_model_get_iter_first (pd->priv->lang_model, &iter))
	{
		do
		{
			char *c;

			gtk_tree_model_get (pd->priv->lang_model, &iter,
					    COL_LANG_CODE, &c,
					    -1);

			if (strcmp (code, c) == 0)
			{
				g_free (c);

				/* already in list, don't allow a duplicate */
				return;
			}
			g_free (c);
		}
		while (gtk_tree_model_iter_next (pd->priv->lang_model, &iter));
	}

	gtk_list_store_append (GTK_LIST_STORE (pd->priv->lang_model), &iter);
	
	gtk_list_store_set (GTK_LIST_STORE (pd->priv->lang_model), &iter,
			    COL_LANG_NAME, desc,
			    COL_LANG_CODE, code,
			    -1);
}

static void
language_editor_update_pref (PrefsDialog *pd)
{
	GtkTreeIter iter;
	GSList *codes = NULL;

	if (gtk_tree_model_get_iter_first (pd->priv->lang_model, &iter))
	{
		do
		{
			char *code;
		
			gtk_tree_model_get (pd->priv->lang_model, &iter,
					    COL_LANG_CODE, &code,
					    -1);

			codes = g_slist_prepend (codes, code);
		}
		while (gtk_tree_model_iter_next (pd->priv->lang_model, &iter));
	}

	codes = g_slist_reverse (codes);
	eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, codes);

	g_slist_foreach (codes, (GFunc) g_free, NULL);
	g_slist_free (codes);
}

static void
language_editor_update_buttons (PrefsDialog *dialog)
{
	GtkTreeSelection *selection;
	GtkTreeModel *model;
	GtkTreePath *path;
	GtkTreeIter iter;
	gboolean can_remove = FALSE, can_move_up = FALSE, can_move_down = FALSE;
	int selected;

	selection = gtk_tree_view_get_selection (dialog->priv->lang_treeview);

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
	{
		path = gtk_tree_model_get_path (model, &iter);
	
		selected = gtk_tree_path_get_indices (path)[0];

		can_remove = TRUE;
		can_move_up = selected > 0;
		can_move_down = 
			selected < gtk_tree_model_iter_n_children (model, NULL) - 1;

		gtk_tree_path_free (path);
	}

	gtk_widget_set_sensitive (dialog->priv->lang_remove_button, can_remove);
	gtk_widget_set_sensitive (dialog->priv->lang_up_button, can_move_up);
	gtk_widget_set_sensitive (dialog->priv->lang_down_button, can_move_down);
}

static void
add_lang_dialog_selection_changed (GtkTreeSelection *selection,
				   EphyDialog *dialog)
{
	GtkWidget *button;
	int n_selected;

	button = ephy_dialog_get_control (dialog, add_lang_props[LANGUAGE_ACCEPT_BUTTON_PROP].id);

	n_selected = gtk_tree_selection_count_selected_rows (selection);
	gtk_widget_set_sensitive (button, n_selected > 0);
}

static void
add_lang_dialog_response_cb (GtkWidget *widget,
			     int response,
			     PrefsDialog *pd)
{
	EphyDialog *dialog = pd->priv->add_lang_dialog;
	GtkTreeView *treeview;
	GtkTreeModel *model;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	GList *rows, *r;

	g_return_if_fail (dialog != NULL);

	if (response == GTK_RESPONSE_ACCEPT)
	{
		treeview = GTK_TREE_VIEW (ephy_dialog_get_control
				(dialog, add_lang_props[LANGUAGE_PROP].id));
		selection = gtk_tree_view_get_selection (treeview);

		rows = gtk_tree_selection_get_selected_rows (selection, &model);

		for (r = rows; r != NULL; r = r->next)
		{
			GtkTreePath *path = (GtkTreePath *) r->data;

			if (gtk_tree_model_get_iter (model, &iter, path))
			{
				char *code, *desc;
				
				gtk_tree_model_get (model, &iter,
						    COL_LANG_NAME, &desc,
						    COL_LANG_CODE, &code,
						    -1);

				language_editor_add (pd, code, desc);
		
				g_free (desc);
				g_free (code);
			}
		}			

		g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
		g_list_free (rows);

		language_editor_update_pref (pd);
		language_editor_update_buttons (pd);
	}

	g_object_unref (dialog);
}

#ifdef HAVE_ISO_CODES
static char *
get_name_for_lang_code (PrefsDialog *pd,
			const char *code)
{
	char **str;
	char *name;
	const char *langname, *localename;
	int len;

	str = g_strsplit (code, "-", -1);
	len = g_strv_length (str);
	g_return_val_if_fail (len != 0, NULL);

	langname = (const char *) g_hash_table_lookup (pd->priv->iso_639_table, str[0]);

	if (len == 1 && langname != NULL)
	{
		name = g_strdup (dgettext (ISO_639_DOMAIN, langname));
	}
	else if (len == 2 && langname != NULL)
	{
		localename = (const char *) g_hash_table_lookup (pd->priv->iso_3166_table, str[1]);

		if (localename != NULL)
		{
			/* Translators: The text before the "|" is context to help you decide on
			 * the correct translation. You MUST OMIT it in the translated string.
			 * Translators: the first %s is the language name, and the
			 * second %s is the locale name. Example:
			 * "French (France)"
			 */
			name = g_strdup_printf (Q_("language|%s (%s)"),
						dgettext (ISO_639_DOMAIN, langname),
						dgettext (ISO_3166_DOMAIN, localename));
		}
		else
		{
			/* Translators: The text before the "|" is context to help you decide on
			 * the correct translation. You MUST OMIT it in the translated string. */
			name = g_strdup_printf (Q_("language|%s (%s)"),
						dgettext (ISO_639_DOMAIN, langname), str[1]);
		}
	}
	else
	{
		/* Translators: The text before the "|" is context to help you decide on
		 * the correct translation. You MUST OMIT it in the translated string.
		 * Translators: this refers to a user-define language code
		 * (one which isn't in our built-in list).
		 */
		name = g_strdup_printf (Q_("language|User defined (%s)"), code);
	}

	g_strfreev (str);

	return name;
}
#endif /* HAVE_ISO_CODES */

static void
add_system_language_entry (GtkListStore *store)
{
	GtkTreeIter iter;
	char **sys_langs;
	char *system, *text;
	int n_sys_langs;

	sys_langs = ephy_langs_get_languages ();
	n_sys_langs = g_strv_length (sys_langs);

	system = g_strjoinv (", ", sys_langs);

	text = g_strdup_printf
		(ngettext ("System language (%s)",
			   "System languages (%s)", n_sys_langs), system);

	gtk_list_store_append (store, &iter);
	gtk_list_store_set (store, &iter,
			    COL_LANG_NAME, text,
			    COL_LANG_CODE, "system",
			    -1);

	g_strfreev (sys_langs);
	g_free (system);
	g_free (text);
}

static EphyDialog *
setup_add_language_dialog (PrefsDialog *pd)
{
	EphyDialog *dialog;
	GtkWidget *window;
	GtkListStore *store;
	GtkTreeModel *sortmodel;
	GtkTreeView *treeview;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GtkTreeIter iter;
	int i;

	window = ephy_dialog_get_control (EPHY_DIALOG (pd), properties[WINDOW_PROP].id);

	dialog =  EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG,
					     "parent-window", window,
					     "default-width", 260,
					     "default-height", 230,
					     NULL));

	ephy_dialog_construct (dialog, 
			       add_lang_props,
			       ephy_file ("prefs-dialog.glade"),
			       "add_language_dialog",
			       NULL);

	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

	for (i = 0; i < G_N_ELEMENTS (languages); i++)
	{
#ifdef HAVE_ISO_CODES
		const char *code = languages[i];
		char *name;

		name = get_name_for_lang_code (pd, code);
		
		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COL_LANG_NAME, name,
				    COL_LANG_CODE, code,
				    -1);
		g_free (name);
#else
		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    COL_LANG_NAME, _(languages[i].name),
				    COL_LANG_CODE, languages[i].code,
				    -1);
#endif /* HAVE_ISO_CODES */
	}

	add_system_language_entry (store);

	sortmodel = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
	gtk_tree_sortable_set_sort_column_id
		(GTK_TREE_SORTABLE (sortmodel), COL_LANG_NAME, GTK_SORT_ASCENDING);

	ephy_dialog_get_controls (dialog,
				  add_lang_props[LANGUAGE_PROP].id, &treeview,
				  add_lang_props[LANGUAGE_DIALOG].id, &window,
				  NULL);

	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), FALSE);

	gtk_tree_view_set_model (treeview, sortmodel);

	gtk_tree_view_set_headers_visible (treeview, FALSE);

	renderer = gtk_cell_renderer_text_new ();

	gtk_tree_view_insert_column_with_attributes (treeview,
						     0, "Language",
						     renderer,
						     "text", 0,
						     NULL);
	column = gtk_tree_view_get_column (treeview, 0);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);

	selection = gtk_tree_view_get_selection (treeview);
	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
	
	add_lang_dialog_selection_changed (GTK_TREE_SELECTION (selection), dialog);
	g_signal_connect (selection, "changed",
			  G_CALLBACK (add_lang_dialog_selection_changed), dialog);

	g_signal_connect (window, "response",
			  G_CALLBACK (add_lang_dialog_response_cb), pd);

	g_object_unref (store);
	g_object_unref (sortmodel);

	return dialog;
}

void
language_editor_add_button_clicked_cb (GtkWidget *button,
				       PrefsDialog *pd)
{
	if (pd->priv->add_lang_dialog == NULL)
	{
		pd->priv->add_lang_dialog = setup_add_language_dialog (pd);

		g_object_add_weak_pointer
			(G_OBJECT (pd->priv->add_lang_dialog),
			(gpointer *) &pd->priv->add_lang_dialog);
	}

	ephy_dialog_show (pd->priv->add_lang_dialog);
}

void
language_editor_remove_button_clicked_cb (GtkWidget *button,
					  PrefsDialog *pd)
{
	GtkTreeSelection *selection;
	GtkTreeModel *model;
	GtkTreeIter iter;

	selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
	{
		gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
	}

	language_editor_update_pref (pd);
	language_editor_update_buttons (pd);
}

void
language_editor_up_button_clicked_cb (GtkWidget *button,
				      PrefsDialog *pd)
{
	GtkTreeSelection *selection;
	GtkTreeModel *model;
	GtkTreeIter iter, iter_prev;
	GtkTreePath *path;

	selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
	{
		path = gtk_tree_model_get_path (model, &iter);

		if (!gtk_tree_path_prev (path))
		{
			gtk_tree_path_free (path);
			return;
		}

		gtk_tree_model_get_iter (model, &iter_prev, path);

		gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter);

		gtk_tree_path_free (path);
	}

	language_editor_update_pref (pd);
	language_editor_update_buttons (pd);
}

void
language_editor_down_button_clicked_cb (GtkWidget *button,
					PrefsDialog *pd)
{
	GtkTreeSelection *selection;
	GtkTreeModel *model;
	GtkTreeIter iter, iter_next;
	GtkTreePath *path;


	selection = gtk_tree_view_get_selection (pd->priv->lang_treeview);

	if (gtk_tree_selection_get_selected (selection, &model, &iter))
	{
		path = gtk_tree_model_get_path (model, &iter);

		gtk_tree_path_next (path);

		gtk_tree_model_get_iter (model, &iter_next, path);

		gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &iter_next);

		gtk_tree_path_free (path);
	}

	language_editor_update_pref (pd);
	language_editor_update_buttons (pd);
}

static void
language_editor_treeview_drag_end_cb (GtkWidget *widget,
				      GdkDragContext *context,
				      PrefsDialog *dialog)
{
	language_editor_update_pref (dialog);
	language_editor_update_buttons (dialog);
}

static void
language_editor_selection_changed_cb (GtkTreeSelection *selection,
				      PrefsDialog *dialog)
{
	language_editor_update_buttons (dialog);
}

static void
create_language_section (EphyDialog *dialog)
{
	PrefsDialog *pd = EPHY_PREFS_DIALOG (dialog);
	GtkListStore *store;
	GtkTreeView *treeview;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeSelection *selection;
	GSList *list, *l, *ulist = NULL;

#ifdef HAVE_ISO_CODES
	pd->priv->iso_639_table = ephy_langs_iso_639_table ();
	pd->priv->iso_3166_table = ephy_langs_iso_3166_table ();
#endif

	ephy_dialog_get_controls
		(dialog,
		 properties[LANGUAGE_TREEVIEW_PROP].id, &treeview,
		 properties[LANGUAGE_ADD_BUTTON_PROP].id, &pd->priv->lang_add_button,
		 properties[LANGUAGE_REMOVE_BUTTON_PROP].id, &pd->priv->lang_remove_button,
		 properties[LANGUAGE_UP_BUTTON_PROP].id, &pd->priv->lang_up_button, 
		 properties[LANGUAGE_DOWN_BUTTON_PROP].id, &pd->priv->lang_down_button,
		 NULL);

	/* setup the languages treeview */
	pd->priv->lang_treeview = treeview;

	gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), TRUE);

	store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);

	pd->priv->lang_model = GTK_TREE_MODEL (store);

	gtk_tree_view_set_model (treeview, pd->priv->lang_model);
	g_object_unref (store);

	gtk_tree_view_set_headers_visible (treeview, FALSE);

	renderer = gtk_cell_renderer_text_new ();

	gtk_tree_view_insert_column_with_attributes (treeview,
						     0, "Language",
						     renderer,
						     "text", 0,
						     NULL);
	column = gtk_tree_view_get_column (treeview, 0);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_column_set_sort_column_id (column, COL_LANG_NAME);

	selection = gtk_tree_view_get_selection (treeview);
	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);

	/* Connect treeview signals */
	g_signal_connect (G_OBJECT (treeview), "drag_end",
			  G_CALLBACK (language_editor_treeview_drag_end_cb), pd);
	g_signal_connect (G_OBJECT (selection), "changed",
			  G_CALLBACK (language_editor_selection_changed_cb), pd);

	list = eel_gconf_get_string_list (CONF_RENDERING_LANGUAGE);

	/* uniquify list */
	for (l = list; l != NULL; l = l->next)
	{
		if (g_slist_find_custom (ulist, l->data, (GCompareFunc) strcmp) == NULL)
		{
			ulist = g_slist_prepend (ulist, g_strdup (l->data));
		}
	}
	ulist = g_slist_reverse (ulist);

	/* if modified, write back */
	if (g_slist_length (ulist) != g_slist_length (list))
	{
		eel_gconf_set_string_list (CONF_RENDERING_LANGUAGE, ulist);
	}

	/* Fill languages editor */
	for (l = ulist; l != NULL; l = l->next)
	{
		const char *code = (const char *) l->data;

#ifdef HAVE_ISO_CODES
		if (strcmp (code, "system") == 0)
		{
			add_system_language_entry (store);
		}
		else if (code[0] != '\0')
		{
			char *text;

			text = get_name_for_lang_code (pd, code);
			language_editor_add (pd, code, text);
			g_free (text);
		}

#else /* !HAVE_ISO_CODES */

		int i, n_languages = G_N_ELEMENTS (languages);

		for (i = 0; i < n_languages; i++)
		{
			if (strcmp (languages[i].code, code) == 0) break;
		}

		/* code isn't in stock list */
		if (i == n_languages)
		{
			if (strcmp (code, "system") != 0)
			{
				char *text;
	
				text = g_strdup_printf (Q_("language|User defined (%s)"), code);
	
				language_editor_add (pd, code, text);
				g_free (text);
			}
			else
			{
				add_system_language_entry (store);
			}
		}
		else
		{
			language_editor_add (pd, code, _(languages[i].name));
		}
#endif /* HAVE_ISO_CODES */
	}

	language_editor_update_buttons (pd);

	/* Lockdown if key is not writable */
	if (eel_gconf_key_is_writable (CONF_RENDERING_LANGUAGE) == FALSE)
	{
		gtk_widget_set_sensitive (pd->priv->lang_add_button, FALSE);
		gtk_widget_set_sensitive (pd->priv->lang_remove_button, FALSE);
		gtk_widget_set_sensitive (pd->priv->lang_up_button, FALSE);
		gtk_widget_set_sensitive (pd->priv->lang_down_button, FALSE);
		gtk_widget_set_sensitive (GTK_WIDGET (pd->priv->lang_treeview), FALSE);
	}

	g_slist_foreach (list, (GFunc) g_free, NULL);
	g_slist_free (list);

	g_slist_foreach (ulist, (GFunc) g_free, NULL);
	g_slist_free (ulist);
}

static char*
get_download_button_label (void)
{
	char *key, *label, *downloads_path, *converted_dp;

	key = eel_gconf_get_string (CONF_STATE_DOWNLOAD_DIR);

	downloads_path = ephy_file_downloads_dir ();
	converted_dp = g_filename_to_utf8 (downloads_path, -1, NULL, NULL, NULL);

	if (key == NULL || g_utf8_collate (key, "~") == 0)
	{
		label = g_strdup (dgettext (GTK_DOMAIN, "Home"));
	}
	else if ((converted_dp != NULL && g_utf8_collate (key, converted_dp) == 0) ||
		 g_utf8_collate (key, "Downloads") == 0)
	{
		label = g_strdup (_("Downloads"));
	}
	else if (g_utf8_collate (key, "~/Desktop") == 0 ||
	         g_utf8_collate (key, "Desktop") == 0)
	{
		label = g_strdup (dgettext (GTK_DOMAIN, "Desktop"));
	}
	else
	{
		label = g_strdup (key);
	}

	g_free (downloads_path);
	g_free (converted_dp);
	g_free (key);

	return label;
}
	
static void
create_download_path_label (EphyDialog *dialog)
{
	GtkWidget *button, *label;
	char *dir;

	button = ephy_dialog_get_control (dialog, properties[DOWNLOAD_PATH_BUTTON_PROP].id);
	
	dir = get_download_button_label ();
	label = gtk_label_new (dir);
	gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_START);
	gtk_container_add (GTK_CONTAINER (button), label);
	g_free (dir);
	gtk_widget_show (label);

	gtk_widget_set_sensitive (button, eel_gconf_key_is_writable (CONF_STATE_DOWNLOAD_DIR));
}
	
static void
prefs_dialog_init (PrefsDialog *pd)
{
	EphyDialog *dialog = EPHY_DIALOG (pd);
	EphyEncodings *encodings;
	GtkWidget *window, *curr_button, *blank_button;
	GtkWidget *variable_combo, *monospace_combo;
	GtkCellRenderer *renderer;
	gboolean sensitive;

	pd->priv = EPHY_PREFS_DIALOG_GET_PRIVATE (pd);

	ephy_dialog_construct (dialog,
			       properties,
			       ephy_file ("prefs-dialog.glade"),
			       "prefs_dialog",
			       NULL);

	ephy_dialog_add_enum (dialog, properties[ACCEPT_COOKIES_PROP].id,
			      n_cookies_accept_enum, cookies_accept_enum);

	ephy_dialog_get_controls
		(dialog,
		 properties[WINDOW_PROP].id, &window,
		 properties[HOMEPAGE_CURRENT_PROP].id, &curr_button,
		 properties[HOMEPAGE_BLANK_PROP].id, &blank_button,
		 properties[VARIABLE_PROP].id, &variable_combo,
		 properties[MONOSPACE_PROP].id, &monospace_combo,
		 NULL);

	gtk_window_set_icon_name (GTK_WINDOW (window), GTK_STOCK_PREFERENCES);

	/* set homepage button sensitivity */
	sensitive = eel_gconf_key_is_writable (CONF_GENERAL_HOMEPAGE);
	gtk_widget_set_sensitive (curr_button, sensitive);
	gtk_widget_set_sensitive (blank_button, sensitive);

        renderer = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (variable_combo), renderer, TRUE);
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (variable_combo), renderer,
                                        "text", 0,
                                        NULL);
	ephy_dialog_set_data_column (dialog, properties[VARIABLE_PROP].id, 0);
        renderer = gtk_cell_renderer_text_new ();
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (monospace_combo), renderer, TRUE);
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (monospace_combo), renderer,
                                        "text", 0,
                                        NULL);
	ephy_dialog_set_data_column (dialog, properties[MONOSPACE_PROP].id, 0);

	create_fonts_language_menu (dialog);

	encodings = EPHY_ENCODINGS (ephy_embed_shell_get_encodings
					(EPHY_EMBED_SHELL (ephy_shell)));

	create_node_combo (dialog, DEFAULT_ENCODING_PROP, encodings,
			   ephy_encodings_get_all (encodings),
			   CONF_LANGUAGE_DEFAULT_ENCODING, "ISO-8859-1");
	create_node_combo (dialog, AUTO_ENCODING_PROP, encodings,
			   ephy_encodings_get_detectors (encodings),
			   CONF_LANGUAGE_AUTODETECT_ENCODING, "");

	create_language_section	(dialog);

	create_download_path_label (dialog);
}

void
prefs_dialog_response_cb (GtkDialog *widget,
			  gint response_id,
			  EphyDialog *dialog)
{
	if (response_id == GTK_RESPONSE_CLOSE)
	{
		g_object_unref (dialog);
	}
	else if (response_id == GTK_RESPONSE_HELP)
	{
		prefs_dialog_show_help (dialog);
	}
}

void
prefs_clear_cache_button_clicked_cb (GtkWidget *button,
				     gpointer data)
{
	EphyEmbedSingle *single;

	single = EPHY_EMBED_SINGLE (ephy_embed_shell_get_embed_single (embed_shell));
	ephy_embed_single_clear_cache (single);
}

static void
set_homepage_entry (EphyDialog *dialog,
		    char *new_location)
{
	GValue value = { 0, };

	g_value_init (&value, G_TYPE_STRING);
	g_value_take_string (&value, new_location);
	ephy_dialog_set_value (dialog, properties[HOMEPAGE_ENTRY_PROP].id, &value);
	g_value_unset (&value);
}

void
prefs_homepage_current_button_clicked_cb (GtkWidget *button,
					  EphyDialog *dialog)
{
	GtkWidget *parent;
	EphyEmbed *embed;
	char *location;

	parent = ephy_dialog_get_parent (dialog);
	g_return_if_fail (parent != NULL);

	embed = ephy_window_get_active_embed (EPHY_WINDOW (parent));
	g_return_if_fail (embed != NULL);

	location = ephy_embed_get_location (embed, TRUE);
	set_homepage_entry (dialog, location);
}

void
prefs_homepage_blank_button_clicked_cb (GtkWidget *button,
					EphyDialog *dialog)
{
	set_homepage_entry (dialog, NULL);
}

static void
download_path_response_cb (GtkDialog *fc, gint response, EphyDialog *dialog)
{
	if (response == GTK_RESPONSE_ACCEPT)
	{
		char *dir;

		dir = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (fc));
		if (dir != NULL)
		{
			GtkWidget *button;
			char *label;

			eel_gconf_set_path (CONF_STATE_DOWNLOAD_DIR, dir);

			button = ephy_dialog_get_control (dialog, properties[DOWNLOAD_PATH_BUTTON_PROP].id);
			label = get_download_button_label ();
			gtk_label_set_text (GTK_LABEL (GTK_BIN (button)->child), label);

			g_free (dir);
			g_free (label);
		}
	}

	gtk_widget_destroy (GTK_WIDGET (fc));
}

void
prefs_download_path_button_clicked_cb (GtkWidget *button,
				       PrefsDialog *dialog)
{
	if (dialog->priv->download_dir_chooser == NULL)
	{
		GtkWidget *parent;
		EphyFileChooser *fc;

		parent = ephy_dialog_get_control
			(EPHY_DIALOG (dialog), properties[WINDOW_PROP].id);
	
		fc = ephy_file_chooser_new (_("Select a directory"),
					    GTK_WIDGET (parent),
					    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
					    NULL, EPHY_FILE_FILTER_NONE);
		gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fc),
						     g_get_home_dir ());

		g_signal_connect (GTK_DIALOG (fc), "response",
				    G_CALLBACK (download_path_response_cb),
				    dialog);
		dialog->priv->download_dir_chooser = GTK_WIDGET (fc);
		g_object_add_weak_pointer
			(G_OBJECT (fc), (gpointer *) &dialog->priv->download_dir_chooser);
	}

	gtk_widget_show (dialog->priv->download_dir_chooser);
}
