// -*- C++ -*-

/* 
 * GChemPaint library
 * preferences.cc 
 *
 * Copyright (C) 2006-2007 Jean Bréfort <jean.brefort@normalesup.org>
 *
 * 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 of the
 * License, 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "gchempaint-config.h"
#include "preferences.h"
#include "application.h"
#include "document.h"
#include "fontsel.h"
#include "settings.h"
#include "theme.h"
#include <glib/gi18n-lib.h>
#include <sys/stat.h>
#include <cstring>

static int get_fontstyle (PangoStyle val)
{
	switch (val) {
		case PANGO_STYLE_NORMAL: return 0;
		case PANGO_STYLE_OBLIQUE: return 1;
		case PANGO_STYLE_ITALIC: return 2;
		default: return 0;
	}
}

static int get_fontweight (PangoWeight val)
{
	switch (val) {
		case PANGO_WEIGHT_ULTRALIGHT: return 2;
		case PANGO_WEIGHT_LIGHT: return 3;
		case PANGO_WEIGHT_NORMAL: return 4;
		case PANGO_WEIGHT_SEMIBOLD: return 6;
		case PANGO_WEIGHT_BOLD: return 7;
		case PANGO_WEIGHT_ULTRABOLD: return 8;
		case PANGO_WEIGHT_HEAVY: return 9;
		default: return 4;
	}
}

static int get_fontvariant (PangoVariant val)
{
	switch (val) {
		case PANGO_VARIANT_NORMAL: return 0;
		case PANGO_VARIANT_SMALL_CAPS: return 1;
		default: return 0;
	}
}

static int get_fontstretch (PangoStretch val)
{
	switch (val) {
		case PANGO_STRETCH_ULTRA_CONDENSED: return 0;
		case PANGO_STRETCH_EXTRA_CONDENSED: return 1;
		case PANGO_STRETCH_CONDENSED: return 2;
		case PANGO_STRETCH_SEMI_CONDENSED: return 3;
		case PANGO_STRETCH_NORMAL: return 4;
		case PANGO_STRETCH_SEMI_EXPANDED: return 5;
		case PANGO_STRETCH_EXPANDED: return 6;
		case PANGO_STRETCH_EXTRA_EXPANDED: return 7;
		case PANGO_STRETCH_ULTRA_EXPANDED: return 8;
		default: return 4;
	}
}

static double get_fontsize (double val) {return (double) val / (double) PANGO_SCALE;}

static void on_compression_changed (GtkSpinButton *btn)
{
	CompressionLevel = gtk_spin_button_get_value_as_int (btn);
	GConfClient *conf_client = gconf_client_get_default ();
	GError *error = NULL;
	gconf_client_set_int (conf_client, ROOTDIR"compression", CompressionLevel, &error);
	if (error) {
		g_message("GConf failed: %s", error->message);
		g_error_free (error);
	}
	g_object_unref (conf_client);
}

static void on_tearable_mendeleiev_changed (GtkToggleButton *btn)
{
	TearableMendeleiev = gtk_toggle_button_get_active (btn);
	GConfClient *conf_client = gconf_client_get_default ();
	GError *error = NULL;
	gconf_client_set_bool (conf_client, ROOTDIR"tearable-mendeleiev", TearableMendeleiev, &error);
	if (error) {
		g_message("GConf failed: %s", error->message);
		g_error_free (error);
	}
	g_object_unref (conf_client);
}

static void on_new_theme (gcpPrefsDlg *dlg)
{
	dlg->OnNewTheme ();
}

static void on_select_theme (GtkTreeSelection *selection, gcpPrefsDlg *dlg)
{
	dlg->OnSelectTheme (selection);
}

static void on_bond_length_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnBondLength (gtk_spin_button_get_value (btn));
}

static void on_bond_angle_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnBondAngle (gtk_spin_button_get_value (btn));
}

static void on_bond_width_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnBondWidth (gtk_spin_button_get_value (btn));
}

static void on_bond_dist_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnBondDist (gtk_spin_button_get_value (btn));
}

static void on_stereo_bond_width_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnStereoBondWidth (gtk_spin_button_get_value (btn));
}

static void on_hash_width_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnHashWidth (gtk_spin_button_get_value (btn));
}

static void on_hash_dist_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnHashDist (gtk_spin_button_get_value (btn));
}

static void on_text_font_changed (GcpFontSel *fc, gcpPrefsDlg *dlg)
{
	dlg->OnTextFont (fc);
}

static void on_font_changed (GcpFontSel *fc, gcpPrefsDlg *dlg)
{
	dlg->OnFont (fc);
}

static void on_arrow_length_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowLength (gtk_spin_button_get_value (btn));
}

static void on_arrow_width_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowWidth (gtk_spin_button_get_value (btn));
}

static void on_arrow_dist_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowDist (gtk_spin_button_get_value (btn));
}

static void on_arrow_padding_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowPadding (gtk_spin_button_get_value (btn));
}

static void on_arrow_headA_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowHeadA (gtk_spin_button_get_value (btn));
}

static void on_arrow_headB_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowHeadB (gtk_spin_button_get_value (btn));
}

static void on_arrow_headC_changed (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnArrowHeadC (gtk_spin_button_get_value (btn));
}

static void on_scale (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnScale (gtk_spin_button_get_value (btn));
}

static void on_padding (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnPadding (gtk_spin_button_get_value (btn));
}

static void on_object_padding (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnObjectPadding (gtk_spin_button_get_value (btn));
}

static void on_stoich_padding(GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnStoichPadding (gtk_spin_button_get_value (btn));
}

static void on_sign_padding (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnSignPadding (gtk_spin_button_get_value (btn));
}

static void on_charge_size (GtkSpinButton *btn, gcpPrefsDlg *dlg)
{
	dlg->OnChargeSize (gtk_spin_button_get_value (btn));
}

static void on_name_changed (GtkEntry *entry, gcpPrefsDlg *dlg)
{
	dlg->OnThemeNameChanged (gtk_entry_get_text (entry));
}

static bool on_name_focused_out (GtkEntry *entry, GdkEventFocus *event, gcpPrefsDlg *dlg)
{
	dlg->OnThemeNameChanged (gtk_entry_get_text (entry));
	return false;
}

static bool on_delete_event (GtkWidget* widget, GdkEvent *event, gcpPrefsDlg* dlg)
{
	bool res = dlg->CheckError ();
	if (res) {
		GtkWidget* box = gtk_message_dialog_new (GTK_WINDOW (widget), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Invalid name");
		g_signal_connect (G_OBJECT (box), "response", G_CALLBACK (gtk_widget_destroy), NULL);
		gtk_widget_show_all (box);
	}
	return res;
}

static void on_default_theme_changed (GtkComboBox *box, gcpPrefsDlg* dlg)
{
	dlg->SetDefaultTheme (gtk_combo_box_get_active_text (box));
}

gcpPrefsDlg::gcpPrefsDlg (gcpApplication *pApp):
	Dialog (pApp, GLADEDIR"/preferences.glade", "preferences", pApp),
	Object (),
	m_CurTheme (NULL),
	m_Path (NULL)
{
	if (!xml) {
		delete this;
		return;
	}
	g_signal_connect (G_OBJECT (dialog), "delete-event", G_CALLBACK (on_delete_event), this);
	// compression level
	GtkWidget *w = glade_xml_get_widget (xml, "compression");
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), CompressionLevel);
	g_signal_connect (G_OBJECT (w), "value-changed", G_CALLBACK (on_compression_changed), NULL);
	// tearable table of the elements
	w = glade_xml_get_widget (xml, "tearable-mendeleiev-btn");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TearableMendeleiev);
	g_signal_connect (G_OBJECT (w), "toggled", G_CALLBACK (on_tearable_mendeleiev_changed), NULL);
	// retrieve theme widgets and set signals
	m_BondLengthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-length-btn"));
	g_signal_connect (G_OBJECT (m_BondLengthBtn), "value-changed", G_CALLBACK (on_bond_length_changed), this);
	m_BondAngleBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-angle-btn"));
	g_signal_connect (G_OBJECT (m_BondAngleBtn), "value-changed", G_CALLBACK (on_bond_angle_changed), this);
	m_BondWidthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-width-btn"));
	g_signal_connect (G_OBJECT (m_BondWidthBtn), "value-changed", G_CALLBACK (on_bond_width_changed), this);
	m_BondDistBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "bond-dist-btn"));
	g_signal_connect (G_OBJECT (m_BondDistBtn), "value-changed", G_CALLBACK (on_bond_dist_changed), this);
	m_StereoBondWidthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "stereo-width-btn"));
	g_signal_connect (G_OBJECT (m_StereoBondWidthBtn), "value-changed", G_CALLBACK (on_stereo_bond_width_changed), this);
	m_HashWidthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "hash-width-btn"));
	g_signal_connect (G_OBJECT (m_HashWidthBtn), "value-changed", G_CALLBACK (on_hash_width_changed), this);
	m_HashDistBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "hash-dist-btn"));
	g_signal_connect (G_OBJECT (m_HashDistBtn), "value-changed", G_CALLBACK (on_hash_dist_changed), this);
	// add font selector
	m_FontSel = GCP_FONT_SEL (g_object_new (GCP_FONT_SEL_TYPE, NULL));
	w = glade_xml_get_widget (xml, "atom-font-box");
	gtk_box_pack_start_defaults (GTK_BOX (w), GTK_WIDGET (m_FontSel));
	m_FontChanged = g_signal_connect (G_OBJECT (m_FontSel), "changed", G_CALLBACK (on_font_changed), this);
	// add text font selector
	m_TextFontSel = GCP_FONT_SEL (g_object_new (GCP_FONT_SEL_TYPE, NULL));
	w = glade_xml_get_widget (xml, "text-box");
	gtk_box_pack_start_defaults (GTK_BOX (w), GTK_WIDGET (m_TextFontSel));
	m_TextFontChanged = g_signal_connect (G_OBJECT (m_TextFontSel), "changed", G_CALLBACK (on_text_font_changed), this);
	// arrow spin buttons
	m_ArrowLengthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-length-btn"));
	g_signal_connect (G_OBJECT (m_ArrowLengthBtn), "value-changed", G_CALLBACK (on_arrow_length_changed), this);
	m_ArrowWidthBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-width-btn"));
	g_signal_connect (G_OBJECT (m_ArrowWidthBtn), "value-changed", G_CALLBACK (on_arrow_width_changed), this);
	m_ArrowDistBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-dist-btn"));
	g_signal_connect (G_OBJECT (m_ArrowDistBtn), "value-changed", G_CALLBACK (on_arrow_dist_changed), this);
	m_ArrowPaddingBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-padding-btn"));
	g_signal_connect (G_OBJECT (m_ArrowPaddingBtn), "value-changed", G_CALLBACK (on_arrow_padding_changed), this);
	m_ArrowHeadABtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-headA-btn"));
	g_signal_connect (G_OBJECT (m_ArrowHeadABtn), "value-changed", G_CALLBACK (on_arrow_headA_changed), this);
	m_ArrowHeadBBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-headB-btn"));
	g_signal_connect (G_OBJECT (m_ArrowHeadBBtn), "value-changed", G_CALLBACK (on_arrow_headB_changed), this);
	m_ArrowHeadCBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "arrow-headC-btn"));
	g_signal_connect (G_OBJECT (m_ArrowHeadCBtn), "value-changed", G_CALLBACK (on_arrow_headC_changed), this);
	m_ScaleBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "scale-btn"));
	g_signal_connect (G_OBJECT (m_ScaleBtn), "value-changed", G_CALLBACK (on_scale), this);
	m_PaddingBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "padding-btn"));
	g_signal_connect (G_OBJECT (m_PaddingBtn), "value-changed", G_CALLBACK (on_padding), this);
	m_ObjectPaddingBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "object-padding-btn"));
	g_signal_connect (G_OBJECT (m_ObjectPaddingBtn), "value-changed", G_CALLBACK (on_object_padding), this);
	m_StoichPaddingBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "stoich-padding-btn"));
	g_signal_connect (G_OBJECT (m_StoichPaddingBtn), "value-changed", G_CALLBACK (on_stoich_padding), this);
	m_SignPaddingBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "sign-padding-btn"));
	g_signal_connect (G_OBJECT (m_SignPaddingBtn), "value-changed", G_CALLBACK (on_sign_padding), this);
	m_ChargeSizeBtn = GTK_SPIN_BUTTON (glade_xml_get_widget (xml, "charge-size-btn"));
	g_signal_connect (G_OBJECT (m_ChargeSizeBtn), "value-changed", G_CALLBACK (on_charge_size), this);
	m_NameEntry = GTK_ENTRY (glade_xml_get_widget (xml, "name"));
	gtk_entry_set_text (m_NameEntry, _("Default"));
	m_NameActivate = g_signal_connect (G_OBJECT (m_NameEntry), "activate", G_CALLBACK (on_name_changed), this);
	m_NameFocusOut = g_signal_connect (G_OBJECT (m_NameEntry), "focus-out-event", G_CALLBACK (on_name_focused_out), this);
	// get notebook
	m_Book = GTK_NOTEBOOK (glade_xml_get_widget (xml, "theme-book"));
	// create themes list and select active document theme
	m_ThemesView = GTK_TREE_VIEW (glade_xml_get_widget (xml, "themes"));
	themes = gtk_tree_store_new (1, G_TYPE_STRING);
	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (themes), 0, GTK_SORT_ASCENDING);
	gtk_tree_view_set_model (m_ThemesView, GTK_TREE_MODEL (themes));
	GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
	GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "text", 0, NULL);
	gtk_tree_view_append_column (m_ThemesView, column);
	m_ThemesSelection = gtk_tree_view_get_selection (m_ThemesView);
	list<string> theme_names = ThemeManager.GetThemesNames ();
	list<string>::iterator i, iend = theme_names.end ();
	GtkTreeIter iter, selected, child, grand_child;
	string default_name = pApp->GetActiveDocument ()->GetTheme ()->GetName ();
	if (default_name == "Default")
			default_name = _("Default");
	gcpTheme *theme, *default_theme = ThemeManager.GetDefaultTheme ();
	m_DefaultThemeBox = GTK_COMBO_BOX (gtk_combo_box_new_text ());
	gtk_table_attach (GTK_TABLE (glade_xml_get_widget (xml, "table1")), GTK_WIDGET (m_DefaultThemeBox), 1, 3, 2, 3,
													   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
													   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
	int n = 0;
	for (i = theme_names.begin (); i != iend; i++) {
		theme = ThemeManager.GetTheme (*i);
		gtk_combo_box_append_text (m_DefaultThemeBox, (*i).c_str ());
		if (theme == default_theme)
			gtk_combo_box_set_active (m_DefaultThemeBox, n);
		n++;
		if (theme)
			theme->AddClient (this);
		gtk_tree_store_append (themes, &iter, NULL);
		gtk_tree_store_set (themes, &iter,
				  0, (*i).c_str (),
				  -1);
		gtk_tree_store_append (themes, &child, &iter);
		gtk_tree_store_set (themes, &child,
				  0, _("General"),
				  -1);
		if (*i == default_name)
			selected = child;
		gtk_tree_store_append (themes, &child, &iter);
		gtk_tree_store_set (themes, &child,
				  0, _("Atoms"),
				  -1);
		gtk_tree_store_append (themes, &grand_child, &child);
		gtk_tree_store_set (themes, &grand_child,
				  0, _("Font"),
				  -1);
		gtk_tree_store_append (themes, &grand_child, &child);
		gtk_tree_store_set (themes, &grand_child,
				  0, _("Other"),
				  -1);
		gtk_tree_store_append (themes, &child, &iter);
		gtk_tree_store_set (themes, &child,
				  0, _("Bonds"),
				  -1);
		gtk_tree_store_append (themes, &child, &iter);
		gtk_tree_store_set (themes, &child,
				  0, _("Arrows"),
				  -1);
		gtk_tree_store_append (themes, &child, &iter);
		gtk_tree_store_set (themes, &child,
				  0, _("Text"),
				  -1);
	}
	g_signal_connect (m_DefaultThemeBox,"changed", G_CALLBACK (on_default_theme_changed), this);
	m_Path = gtk_tree_model_get_path (GTK_TREE_MODEL (themes), &selected);
	gtk_tree_selection_set_mode (m_ThemesSelection, GTK_SELECTION_BROWSE);
	g_signal_connect (m_ThemesSelection, "changed", G_CALLBACK (on_select_theme), this);
	if (m_Path) {
		gtk_tree_view_expand_to_path (m_ThemesView, m_Path);
		gtk_tree_selection_select_path (m_ThemesSelection, m_Path);
		gtk_tree_view_scroll_to_cell (m_ThemesView, m_Path, column, FALSE, 0., 0.);
	}
	
	// add event handler to new theme button
	g_signal_connect_swapped (G_OBJECT (glade_xml_get_widget (xml, "new-theme")), "clicked", G_CALLBACK (on_new_theme), this);
	gtk_widget_show_all (GTK_WIDGET (dialog));
}

gcpPrefsDlg::~gcpPrefsDlg ()
{
	list <string> names = ThemeManager.GetThemesNames ();
	list <string>::iterator i, end = names.end ();
	gcpTheme *theme;
	for (i = names.begin (); i != end; i++) {
		theme = ThemeManager.GetTheme (*i);
		if (theme)
			theme->RemoveClient (this);
	}
	if (m_Path)
		gtk_tree_path_free (m_Path);
}

void gcpPrefsDlg::OnNewTheme ()
{
	gcpTheme *pTheme = ThemeManager.CreateNewTheme (m_CurTheme);
	string &name = pTheme->GetName ();
	GtkTreeIter iter, child, grand_child;
	gtk_tree_store_append (themes, &iter, NULL);
	gtk_tree_store_set (themes, &iter,
			  0, name.c_str (),
			  -1);
	gtk_tree_store_append (themes, &child, &iter);
	gtk_tree_store_set (themes, &child,
			  0, _("General"),
			  -1);
	GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (themes), &child);
	if (path) {
		gtk_tree_view_expand_to_path (m_ThemesView, path);
		gtk_tree_selection_select_path (m_ThemesSelection, path);
		gtk_tree_view_scroll_to_cell (m_ThemesView, path, 0, FALSE, 0., 0.);
		gtk_tree_path_free (path);
	}
	gtk_tree_store_append (themes, &child, &iter);
	gtk_tree_store_set (themes, &child,
			  0, _("Atoms"),
			  -1);
	gtk_tree_store_append (themes, &grand_child, &child);
	gtk_tree_store_set (themes, &grand_child,
			  0, _("Font"),
			  -1);
	gtk_tree_store_append (themes, &grand_child, &child);
	gtk_tree_store_set (themes, &grand_child,
			  0, _("Other"),
			  -1);
	gtk_tree_store_append (themes, &child, &iter);
	gtk_tree_store_set (themes, &child,
			  0, _("Bonds"),
			  -1);
	gtk_tree_store_append (themes, &child, &iter);
	gtk_tree_store_set (themes, &child,
			  0, _("Arrows"),
			  -1);
	gtk_tree_store_append (themes, &child, &iter);
	gtk_tree_store_set (themes, &child,
			  0, _("Text"),
			  -1);
	dynamic_cast <gcpApplication*> (m_App)->OnThemeNamesChanged ();
}

void gcpPrefsDlg::OnSelectTheme (GtkTreeSelection *selection)
{
	char const *Name = gtk_entry_get_text (m_NameEntry);
	if (!strcmp (Name, _("Default")))
		Name = "Default";
	if (m_CurTheme && Name != m_CurTheme->m_Name)
		OnThemeNameChanged (Name);
	if (!*Name) {
		gtk_tree_selection_select_path (selection, m_Path);
		return;
	}
	// we must fill the theme widgets with the corresponding data
	GtkTreeIter iter, parent;
	char *name;
	char *page;
	GtkTreeModel *model;
	if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
		gtk_notebook_set_current_page (m_Book, 0);
		return;
	}
	if (m_Path)
		gtk_tree_path_free (m_Path);
	m_Path = gtk_tree_model_get_path (GTK_TREE_MODEL (themes), &iter);
	if (gtk_tree_model_iter_parent (model, &parent, &iter)) {
		gtk_tree_model_get (model, &parent, 0, &name, -1);
		if (!strcmp (name, _("Atoms"))) {
			GtkTreeIter grand_parent;
			gtk_tree_model_iter_parent (model, &grand_parent, &parent);
			gtk_tree_model_get (model, &grand_parent, 0, &name, -1);
		}
		gtk_tree_model_get (model, &iter, 0, &page, -1);
		if (!strcmp (page, _("General")))
			gtk_notebook_set_current_page (m_Book, 1);
		else if (!strcmp (page, _("Font")))
			gtk_notebook_set_current_page (m_Book, 2);
		else if (!strcmp (page, _("Other")))
			gtk_notebook_set_current_page (m_Book, 6);
		else if (!strcmp (page, _("Bonds")))
			gtk_notebook_set_current_page (m_Book, 3);
		else if (!strcmp (page, _("Arrows")))
			gtk_notebook_set_current_page (m_Book, 4);
		else if (!strcmp (page, _("Text")))
			gtk_notebook_set_current_page (m_Book, 5);
		else
			gtk_notebook_set_current_page (m_Book, 0);
	} else {
		gtk_tree_model_get (model, &iter, 0, &name, -1);
		gtk_notebook_set_current_page (m_Book, 0);
	}
	m_CurTheme = ThemeManager.GetTheme (name);
	bool rw = m_CurTheme->m_ThemeType != GLOBAL_THEME_TYPE;
	gtk_spin_button_set_value (m_BondLengthBtn, m_CurTheme->m_BondLength);
	gtk_widget_set_sensitive (GTK_WIDGET (m_BondLengthBtn), rw);
	gtk_spin_button_set_value (m_BondAngleBtn, m_CurTheme->m_BondAngle);
	gtk_widget_set_sensitive (GTK_WIDGET (m_BondAngleBtn), rw);
	gtk_spin_button_set_value (m_BondWidthBtn, m_CurTheme->m_BondWidth);
	gtk_widget_set_sensitive (GTK_WIDGET (m_BondWidthBtn), rw);
	gtk_spin_button_set_value (m_BondDistBtn, m_CurTheme->m_BondDist);
	gtk_widget_set_sensitive (GTK_WIDGET (m_BondDistBtn), rw);
	gtk_spin_button_set_value (m_StereoBondWidthBtn, m_CurTheme->m_StereoBondWidth);
	gtk_widget_set_sensitive (GTK_WIDGET (m_StereoBondWidthBtn), rw);
	gtk_spin_button_set_value (m_HashWidthBtn, m_CurTheme->m_HashWidth);
	gtk_widget_set_sensitive (GTK_WIDGET (m_HashWidthBtn), rw);
	gtk_spin_button_set_value (m_HashDistBtn, m_CurTheme->m_HashDist);
	gtk_widget_set_sensitive (GTK_WIDGET (m_HashDistBtn), rw);
	g_signal_handler_block (G_OBJECT (m_TextFontSel), m_TextFontChanged);
	g_object_set (G_OBJECT (m_TextFontSel),
					"family", m_CurTheme->m_TextFontFamily,
					"style", m_CurTheme->m_TextFontStyle,
					"weight", m_CurTheme->m_TextFontWeight,
					"variant", m_CurTheme->m_TextFontVariant,
					"stretch", m_CurTheme->m_TextFontStretch,
					"size", m_CurTheme->m_TextFontSize,
					NULL);
	g_signal_handler_unblock (G_OBJECT (m_TextFontSel), m_TextFontChanged);
	gtk_widget_set_sensitive (GTK_WIDGET (m_TextFontSel), rw);
	g_signal_handler_block (G_OBJECT (m_FontSel), m_FontChanged);
	g_object_set (G_OBJECT (m_FontSel),
					"family", m_CurTheme->m_FontFamily,
					"style", m_CurTheme->m_FontStyle,
					"weight", m_CurTheme->m_FontWeight,
					"variant", m_CurTheme->m_FontVariant,
					"stretch", m_CurTheme->m_FontStretch,
					"size", m_CurTheme->m_FontSize,
					NULL);
	g_signal_handler_unblock (G_OBJECT (m_FontSel), m_FontChanged);
	gtk_widget_set_sensitive (GTK_WIDGET (m_FontSel), rw);
	gtk_spin_button_set_value (m_ArrowLengthBtn, m_CurTheme->m_ArrowLength);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowLengthBtn), rw);
	gtk_spin_button_set_value (m_ArrowWidthBtn, m_CurTheme->m_ArrowWidth);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowWidthBtn), rw);
	gtk_spin_button_set_value (m_ArrowDistBtn, m_CurTheme->m_ArrowDist);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowDistBtn), rw);
	gtk_spin_button_set_value (m_ArrowPaddingBtn, m_CurTheme->m_ArrowPadding);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowPaddingBtn), rw);
	gtk_spin_button_set_value (m_ArrowHeadABtn, m_CurTheme->m_ArrowHeadA);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowHeadABtn), rw);
	gtk_spin_button_set_value (m_ArrowHeadBBtn, m_CurTheme->m_ArrowHeadB);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowHeadBBtn), rw);
	gtk_spin_button_set_value (m_ArrowHeadCBtn, m_CurTheme->m_ArrowHeadC);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ArrowHeadCBtn), rw);
	gtk_spin_button_set_value (m_ScaleBtn, 1. / m_CurTheme->m_ZoomFactor);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ScaleBtn), rw);
	gtk_spin_button_set_value (m_PaddingBtn, m_CurTheme->m_Padding);
	gtk_widget_set_sensitive (GTK_WIDGET (m_PaddingBtn), rw);
	gtk_spin_button_set_value (m_ObjectPaddingBtn, m_CurTheme->m_ObjectPadding);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ObjectPaddingBtn), rw);
	gtk_spin_button_set_value (m_StoichPaddingBtn, m_CurTheme->m_StoichiometryPadding);
	gtk_widget_set_sensitive (GTK_WIDGET (m_StoichPaddingBtn), rw);
	gtk_spin_button_set_value (m_SignPaddingBtn, m_CurTheme->m_SignPadding);
	gtk_widget_set_sensitive (GTK_WIDGET (m_SignPaddingBtn), rw);
	gtk_spin_button_set_value (m_ChargeSizeBtn, m_CurTheme->m_ChargeSignSize);
	gtk_widget_set_sensitive (GTK_WIDGET (m_ChargeSizeBtn), rw);
	g_signal_handler_block (m_NameEntry, m_NameActivate);
	g_signal_handler_block (m_NameEntry, m_NameFocusOut);
	gtk_entry_set_text (m_NameEntry, _(m_CurTheme->m_Name.c_str ()));
	g_signal_handler_unblock (m_NameEntry, m_NameFocusOut);
	g_signal_handler_unblock (m_NameEntry, m_NameActivate);
	gtk_widget_set_sensitive (GTK_WIDGET (m_NameEntry), rw && m_CurTheme->m_ThemeType != DEFAULT_THEME_TYPE);
}

void gcpPrefsDlg::OnBondLength (double length)
{
	if (length != m_CurTheme->m_BondLength) {
		m_CurTheme->m_BondLength = length;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"bond-length", length, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnBondAngle (double angle)
{
	if (angle != m_CurTheme->m_BondAngle) {
		m_CurTheme->m_BondAngle = angle;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"bond-angle", angle, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnBondWidth (double width)
{
	if (width != m_CurTheme->m_BondWidth) {
		m_CurTheme->m_BondWidth = width;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"bond-width", width, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnBondDist (double dist)
{
	if (dist != m_CurTheme->m_BondDist) {
		m_CurTheme->m_BondDist = dist;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"bond-dist", dist, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnStereoBondWidth (double width)
{
	if (width != m_CurTheme->m_StereoBondWidth) {
		m_CurTheme->m_StereoBondWidth = width;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"stereo-width", width, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnHashWidth (double width)
{
	if (width != m_CurTheme->m_HashWidth) {
		m_CurTheme->m_HashWidth = width;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"hash-width", width, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnHashDist (double dist)
{
	if (dist != m_CurTheme->m_HashDist) {
		m_CurTheme->m_HashDist = dist;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"hash-dist", dist, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnFont (GcpFontSel *fs)
{
	char *Name;
	PangoStyle Style;
	PangoWeight Weight;
	PangoStretch Stretch;
	PangoVariant Variant;
	int Size;
	bool changed = false;
	g_object_get (G_OBJECT (fs), "family", &Name, "style", &Style, "weight", &Weight, "stretch", &Stretch, "variant", &Variant, "size", &Size, NULL);

	if (strcmp (m_CurTheme->m_FontFamily, Name)) {
		g_free (m_CurTheme->m_FontFamily);
		m_CurTheme->m_FontFamily = Name;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
				gconf_client_set_string (conf_client, ROOTDIR"font-family", Name, &error);
				if (error) {
					g_message("GConf failed: %s", error->message);
					g_error_free (error);
				}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_FontStyle != Style) {
		m_CurTheme->m_FontStyle = Style;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"font-style", get_fontstyle (Style), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_FontWeight != Weight) {
		m_CurTheme->m_FontWeight = Weight;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"font-weight", get_fontweight (Weight), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_FontStretch != Stretch) {
		m_CurTheme->m_FontStretch = Stretch;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"font-stretch", get_fontstretch (Stretch), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_FontVariant != Variant) {
		m_CurTheme->m_FontVariant = Variant;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"font-variant", get_fontvariant (Variant), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_FontSize != Size) {
		m_CurTheme->m_FontSize = Size;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"font-size", get_fontsize (Size), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (changed)
		m_CurTheme->NotifyChanged ();
}

void gcpPrefsDlg::OnTextFont (GcpFontSel *fs)
{
	char *Name;
	PangoStyle Style;
	PangoWeight Weight;
	PangoStretch Stretch;
	PangoVariant Variant;
	int Size;
	bool changed = false;
	g_object_get (G_OBJECT (fs), "family", &Name, "style", &Style, "weight", &Weight, "stretch", &Stretch, "variant", &Variant, "size", &Size, NULL);

	if (strcmp (m_CurTheme->m_TextFontFamily, Name)) {
		g_free (m_CurTheme->m_TextFontFamily);
		m_CurTheme->m_TextFontFamily = Name;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_string (conf_client, ROOTDIR"text-font-family", Name, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_TextFontStyle != Style) {
		m_CurTheme->m_TextFontStyle = Style;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"text-font-style", get_fontstyle (Style), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_TextFontWeight != Weight) {
		m_CurTheme->m_TextFontWeight = Weight;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"text-font-weight", get_fontweight (Weight), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_TextFontStretch != Stretch) {
		m_CurTheme->m_TextFontStretch = Stretch;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"text-font-stretch", get_fontstretch (Stretch), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_TextFontVariant != Variant) {
		m_CurTheme->m_TextFontVariant = Variant;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_int (conf_client, ROOTDIR"text-font-variant", get_fontvariant (Variant), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (m_CurTheme->m_TextFontSize != Size) {
		m_CurTheme->m_TextFontSize = Size;
		changed = true;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"text-font-size", get_fontsize (Size), &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
	if (changed)
		m_CurTheme->NotifyChanged ();
}

// arrows

void gcpPrefsDlg::OnArrowLength (double length)
{
	if (length != m_CurTheme->m_ArrowLength) {
		m_CurTheme->m_ArrowLength = length;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-length", length, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnArrowWidth (double width)
{
	if (width != m_CurTheme->m_ArrowWidth) {
		m_CurTheme->m_ArrowWidth = width;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-width", width, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnArrowDist (double dist)
{
	if (dist != m_CurTheme->m_ArrowDist) {
		m_CurTheme->m_ArrowDist = dist;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-dist", dist, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnArrowPadding (double padding)
{
	if (padding != m_CurTheme->m_ArrowPadding) {
		m_CurTheme->m_ArrowPadding = padding;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-padding", padding, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnArrowHeadA (double headA)
{
	if (headA != m_CurTheme->m_ArrowHeadA) {
		m_CurTheme->m_ArrowHeadA = headA;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-headA", headA, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnArrowHeadB (double headB)
{
	if (headB != m_CurTheme->m_ArrowHeadB) {
		m_CurTheme->m_ArrowHeadB = headB;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-headB", headB, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnArrowHeadC (double headC)
{
	if (headC != m_CurTheme->m_ArrowHeadC) {
		m_CurTheme->m_ArrowHeadC = headC;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"arrow-headC", headC, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnScale (double scale)
{
	double zoom = 1. / scale;
	if (zoom != m_CurTheme->m_ZoomFactor) {
		m_CurTheme->m_ZoomFactor = zoom;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"scale", scale, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnPadding (double padding)
{
	if (padding != m_CurTheme->m_Padding) {
		m_CurTheme->m_Padding = padding;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"padding", padding, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnObjectPadding (double padding)
{
	if (padding != m_CurTheme->m_ObjectPadding) {
		m_CurTheme->m_ObjectPadding = padding;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"object-padding", padding, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnStoichPadding (double padding)
{
	if (padding != m_CurTheme->m_StoichiometryPadding) {
		m_CurTheme->m_StoichiometryPadding = padding;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"stoichiometry-padding", padding, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnSignPadding (double padding)
{
	if (padding != m_CurTheme->m_SignPadding) {
		m_CurTheme->m_SignPadding = padding;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"sign-padding", padding, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
	}
}

void gcpPrefsDlg::OnChargeSize(double size)
{
	if (size != m_CurTheme->m_ChargeSignSize) {
		m_CurTheme->m_ChargeSignSize = size;
		switch (m_CurTheme->m_ThemeType) {
		case DEFAULT_THEME_TYPE: {
			GConfClient *conf_client = gconf_client_get_default ();
			GError *error = NULL;
			gconf_client_set_float (conf_client, ROOTDIR"charge-sign-size", size, &error);
			if (error) {
				g_message("GConf failed: %s", error->message);
				g_error_free (error);
			}
			g_object_unref (conf_client);
			break;
		}
		case LOCAL_THEME_TYPE:
			m_CurTheme->modified = true;
			break;
		default:
			break;
		}
		m_CurTheme->NotifyChanged ();
	}
}

void gcpPrefsDlg::OnThemeNameChanged (char const *name)
{
	if (!name || !*name) {
		// No valid name found
		if (!gtk_window_has_toplevel_focus (GTK_WINDOW (dialog)))
			return;
		GtkWidget* box = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Invalid name");
		g_signal_handler_block (m_NameEntry, m_NameFocusOut);
		g_signal_connect (G_OBJECT (box), "response", G_CALLBACK (gtk_widget_destroy), NULL);
		gtk_widget_show_all (box);
		g_signal_handler_unblock (m_NameEntry, m_NameFocusOut);
		gtk_window_set_focus (GTK_WINDOW (dialog), GTK_WIDGET (m_NameEntry));
		return;
	}
	GtkTreeIter iter, parent;
	gtk_tree_model_get_iter (GTK_TREE_MODEL (themes), &iter, m_Path);
	gtk_tree_model_iter_parent  (GTK_TREE_MODEL (themes), &parent, &iter);
	gtk_tree_store_set (themes, &parent, 0, name, -1);
	// delete old file
	if (m_CurTheme->m_ThemeType == LOCAL_THEME_TYPE) {
		xmlDocPtr doc = xmlNewDoc((xmlChar*)"1.0");
		xmlDocSetRootElement (doc,  xmlNewDocNode (doc, NULL, (xmlChar*) "chemistry", NULL));
		char *szhome = getenv ("HOME");
		string home, path;
		if (szhome)
			home = szhome;
		path = home + "/.gchempaint/themes";
		GDir *dir = g_dir_open (path.c_str (), 0, NULL);
		if (!dir) {
			string gcppath;
			gcppath = home + "/.gchempaint";
			dir = g_dir_open (gcppath.c_str (), 0, NULL);
			if (dir)
				g_dir_close (dir);
			else
				mkdir (gcppath.c_str (), 0x1ed);
			mkdir (path.c_str (), 0x1ed);
		} else {
			path += string ("/") + m_CurTheme->GetName ();
			remove (path.c_str ());
			g_dir_close (dir);
		}
		ThemeManager.ChangeThemeName (m_CurTheme, name); // just set the name
		if (m_CurTheme->Save (doc)) {
			path = home + "/.gchempaint/themes/" + name;
			xmlSaveFormatFile (path.c_str (), doc, true);
			m_CurTheme->modified = false;
		}
	} else
		m_CurTheme->m_Name = name; // just set the name
	dynamic_cast <gcpApplication*> (m_App)->OnThemeNamesChanged ();
}

bool gcpPrefsDlg::CheckError ()
{
	return (!*gtk_entry_get_text (m_NameEntry));
}

void gcpPrefsDlg::SetDefaultTheme (char const *name)
{
	ThemeManager.SetDefaultTheme (name);
	GConfClient *conf_client = gconf_client_get_default ();
	GError *error = NULL;
	gconf_client_set_string (conf_client, ROOTDIR"default-theme", name, &error);
	if (error) {
		g_message("GConf failed: %s", error->message);
		g_error_free (error);
	}
	g_object_unref (conf_client);
}


syntax highlighted by Code2HTML, v. 0.9.1