diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ephy-dialog.c | 1672 | ||||
-rw-r--r-- | lib/ephy-dialog.h | 113 | ||||
-rw-r--r-- | lib/ephy-file-chooser.c | 5 |
3 files changed, 995 insertions, 795 deletions
diff --git a/lib/ephy-dialog.c b/lib/ephy-dialog.c index 78e72af93..b82b0faef 100644 --- a/lib/ephy-dialog.c +++ b/lib/ephy-dialog.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2000-2003 Marco Pesenti Gritti + * Copyright (C) 2003 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 @@ -18,56 +19,26 @@ * $Id$ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "ephy-dialog.h" #include "ephy-glade.h" #include "ephy-state.h" #include "ephy-gui.h" #include "eel-gconf-extensions.h" +#include "ephy-debug.h" #include <stdlib.h> #include <string.h> #include <gtk/gtktogglebutton.h> - -static void -ephy_dialog_class_init (EphyDialogClass *klass); -static void -ephy_dialog_init (EphyDialog *window); -static void -ephy_dialog_finalize (GObject *object); -static void -ephy_dialog_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void -ephy_dialog_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); - -static void -ephy_dialog_set_parent (EphyDialog *dialog, - GtkWidget *parent); - -static void -impl_construct (EphyDialog *dialog, - const EphyDialogProperty *properties, - const char *file, - const char *name); -static GtkWidget * -impl_get_control (EphyDialog *dialog, - int property_id); -static void -impl_get_value (EphyDialog *dialog, - int property_id, - GValue *value); -static gint -impl_run (EphyDialog *dialog); -static void -impl_show (EphyDialog *dialog); -void -ephy_dialog_destroy_cb (GtkWidget *widget, - EphyDialog *dialog); +#include <gtk/gtkradiobutton.h> +#include <gtk/gtkoptionmenu.h> +#include <gtk/gtkcombobox.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtkeditable.h> +#include <gtk/gtkentry.h> enum { @@ -78,197 +49,300 @@ enum typedef enum { - PT_TOGGLEBUTTON, - PT_RADIOBUTTON, - PT_SPINBUTTON, - PT_OPTIONMENU, - PT_ENTRY, + PT_TOGGLEBUTTON, + PT_RADIOBUTTON, + PT_SPINBUTTON, + PT_OPTIONMENU, + PT_COMBOBOX, + PT_EDITABLE, PT_UNKNOWN -} PrefType; +} WidgetType; typedef struct { - int id; + const char *id; + char *pref; + EphyDialogApplyType apply_type; GtkWidget *widget; - const char *pref; - int *sg; - PropertyType type; + WidgetType widget_type; + GType data_type; GList *string_enum; + int data_col; + gboolean loaded; + gboolean sane_state; } PropertyInfo; #define EPHY_DIALOG_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_DIALOG, EphyDialogPrivate)) struct EphyDialogPrivate { + char *name; + + GHashTable *props; GtkWidget *parent; GtkWidget *dialog; - GtkWidget *container; - PropertyInfo *props; gboolean modal; gboolean has_default_size; gboolean disposing; - char *name; - - int spin_item_id; - GTimer *spin_timer; gboolean initialized; }; #define SPIN_DELAY 0.20 +static void ephy_dialog_class_init (EphyDialogClass *klass); +static void ephy_dialog_init (EphyDialog *window); + static GObjectClass *parent_class = NULL; GType ephy_dialog_get_type (void) { - static GType ephy_dialog_type = 0; - - if (ephy_dialog_type == 0) - { - static const GTypeInfo our_info = - { - sizeof (EphyDialogClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) ephy_dialog_class_init, - NULL, - NULL, /* class_data */ - sizeof (EphyDialog), - 0, /* n_preallocs */ - (GInstanceInitFunc) ephy_dialog_init - }; - - ephy_dialog_type = g_type_register_static (G_TYPE_OBJECT, - "EphyDialog", - &our_info, 0); - } - - return ephy_dialog_type; -} - -static void -ephy_dialog_dispose (GObject *object) -{ - EphyDialog *dialog = EPHY_DIALOG (object); + static GType type = 0; - if (dialog->priv->dialog) + if (type == 0) { - dialog->priv->disposing = TRUE; - gtk_widget_destroy (dialog->priv->dialog); - dialog->priv->dialog = NULL; + static const GTypeInfo our_info = + { + sizeof (EphyDialogClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_dialog_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_dialog_init + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EphyDialog", + &our_info, 0); } + + return type; } -static void -ephy_dialog_class_init (EphyDialogClass *klass) +static PropertyInfo * +lookup_info (EphyDialog *dialog, const char *id) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - object_class->finalize = ephy_dialog_finalize; - object_class->dispose = ephy_dialog_dispose; - object_class->set_property = ephy_dialog_set_property; - object_class->get_property = ephy_dialog_get_property; + return g_hash_table_lookup (dialog->priv->props, id); +} - klass->construct = impl_construct; - klass->get_control = impl_get_control; - klass->get_value = impl_get_value; - klass->run = impl_run; - klass->show = impl_show; +static void +set_sensitivity (PropertyInfo *info, gboolean sensitive) +{ + g_return_if_fail (info->widget != NULL); - g_object_class_install_property (object_class, - PROP_PARENT_WINDOW, - g_param_spec_object ("ParentWindow", - "ParentWindow", - "Parent window", - GTK_TYPE_WIDGET, - G_PARAM_READWRITE)); + if (info->widget_type == PT_RADIOBUTTON) + { + GSList *list, *l; - g_object_class_install_property (object_class, - PROP_MODAL, - g_param_spec_boolean ("Modal", - "Modal", - "Modal dialog", - FALSE, - G_PARAM_READWRITE)); + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (info->widget)); - g_type_class_add_private (object_class, sizeof (EphyDialogPrivate)); + for (l = list; l != NULL; l = l->next) + { + gtk_widget_set_sensitive (GTK_WIDGET (l->data), sensitive); + } + } + else + { + gtk_widget_set_sensitive (info->widget, sensitive); + } } static void -set_config_from_editable (GtkWidget *editable, const char *config_name) +set_value_from_pref (PropertyInfo *info, GValue *value) { - GConfValue *gcvalue = eel_gconf_get_value (config_name); + GConfValue *gcvalue; GConfValueType value_type; - char *value; - gint ivalue; - gfloat fvalue; + char *text; - if (gcvalue == NULL) { + gcvalue = eel_gconf_get_value (info->pref); + if (gcvalue == NULL) + { /* ugly hack around what appears to be a gconf bug * it returns a NULL GConfValue for a valid string pref * which is "" by default */ value_type = GCONF_VALUE_STRING; - } else { + } + else + { value_type = gcvalue->type; gconf_value_free (gcvalue); } - /* get all the text into a new string */ - value = gtk_editable_get_chars (GTK_EDITABLE(editable), 0, -1); - - switch (value_type) { - case GCONF_VALUE_STRING: - eel_gconf_set_string (config_name, - value); - break; - /* FIXME : handle possible errors in the input for int and float */ - case GCONF_VALUE_INT: - ivalue = atoi (value); - eel_gconf_set_integer (config_name, ivalue); - break; - case GCONF_VALUE_FLOAT: - fvalue = strtod (value, (char**)NULL); - eel_gconf_set_float (config_name, fvalue); - break; - default: - break; - } - - /* free the allocated strings */ - g_free (value); + switch (value_type) + { + case GCONF_VALUE_STRING: + g_value_init (value, G_TYPE_STRING); + text = eel_gconf_get_string (info->pref); + g_value_take_string (value, text ? text : g_strdup ("")); + break; + case GCONF_VALUE_INT: + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, eel_gconf_get_integer (info->pref)); + break; + case GCONF_VALUE_FLOAT: + g_value_init (value, G_TYPE_FLOAT); + g_value_set_float (value, eel_gconf_get_float (info->pref)); + break; + case GCONF_VALUE_BOOL: + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, eel_gconf_get_boolean (info->pref)); + break; + default: + g_warning ("Unsupported value read from pref %s\n", info->pref); + break; + } + + if (!G_VALUE_HOLDS (value, info->data_type)) + { + g_warning ("Pref %s has wrong value type for id %s!\n", info->pref, info->id); + } + + LOG ("id[%s], pref[%s]: %s", info->id, info->pref, g_strdup_value_contents (value)) +} + +static void +set_pref_from_value (PropertyInfo *info, GValue *value) +{ + const char *pref = info->pref; + g_return_if_fail (G_VALUE_HOLDS (value, info->data_type)); + + switch (info->data_type) + { + case G_TYPE_STRING: + eel_gconf_set_string (pref, g_value_get_string (value)); + break; + case G_TYPE_INT: + eel_gconf_set_integer (pref, g_value_get_int (value)); + break; + case G_TYPE_FLOAT: + eel_gconf_set_float (pref, g_value_get_float (value)); + break; + case G_TYPE_BOOLEAN: + eel_gconf_set_boolean (pref, g_value_get_boolean (value)); + break; + default: + break; + } +} + +static void +set_value_from_editable (PropertyInfo *info, GValue *value) +{ + char *text; + gboolean free_text = TRUE; + + g_return_if_fail (GTK_IS_EDITABLE (info->widget)); + + text = gtk_editable_get_chars (GTK_EDITABLE (info->widget), 0, -1); + + g_value_init (value, info->data_type); + switch (info->data_type) + { + case G_TYPE_STRING: + g_value_take_string (value, text); + free_text = FALSE; + break; + /* FIXME : handle possible errors in the input for int and float */ + case G_TYPE_INT: + g_value_set_int (value, atoi (text)); + break; + case G_TYPE_FLOAT: + g_value_set_float (value, strtod (text, NULL)); + break; + default: + g_warning ("Unsupported value type for editable %s", info->id); + break; + } + + if (free_text) + { + g_free (text); + } } static void -set_config_from_optionmenu (GtkWidget *optionmenu, const char *config_name, GList *senum) +set_value_from_optionmenu (PropertyInfo *info, GValue *value) { - int index = gtk_option_menu_get_history (GTK_OPTION_MENU (optionmenu)); + int index; + + g_return_if_fail (GTK_IS_OPTION_MENU (info->widget)); + + index = gtk_option_menu_get_history (GTK_OPTION_MENU (info->widget)); + g_return_if_fail (index >= 0); + + g_value_init (value, info->data_type); + + if (info->data_type == G_TYPE_STRING) + { + g_return_if_fail (info->string_enum != NULL); - if (senum) + g_value_set_string (value, g_list_nth_data (info->string_enum, index)); + } + else if (info->data_type == G_TYPE_INT) { - eel_gconf_set_string (config_name, g_list_nth_data (senum, index)); + g_value_set_int (value, index); } else { - eel_gconf_set_integer (config_name, index); + g_warning ("Unsupported data type for optionmenu %s\n", info->id); + } +} + +static void +set_value_from_combobox (PropertyInfo *info, GValue *value) +{ + int index; + + g_return_if_fail (GTK_IS_COMBO_BOX (info->widget)); + + index = gtk_combo_box_get_active (GTK_COMBO_BOX (info->widget)); + g_return_if_fail (index >= 0); + + if (info->data_col != -1) + { + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (info->widget)); + + g_return_if_fail (gtk_tree_model_get_column_type (model, info->data_col) == info->data_type); + + if (gtk_tree_model_iter_nth_child (model, &iter, NULL, index)) + { + gtk_tree_model_get_value (model, &iter, info->data_col, value); + } + else + { + g_warning ("Invalid index in combo model for %s\n", info->id); + } + } + else if (info->data_type == G_TYPE_INT) + { + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, index); + } + else + { + g_warning ("Unsupported data type for combo %s\n", info->id); } } static int get_radio_button_active_index (GtkWidget *radiobutton) { - gint index; GtkToggleButton *toggle_button; - gint i, length; - GSList *list; + GSList *list; + int index, i, length; /* get group list */ - list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton)); - length = g_slist_length (list); + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton)); + length = g_slist_length (list); /* iterate over list to find active button */ - for (i = 0; list != NULL; i++, list = g_slist_next (list)) + for (i = 0; list != NULL; i++, list = list->next) { /* get button and text */ toggle_button = GTK_TOGGLE_BUTTON (list->data); @@ -286,933 +360,1061 @@ get_radio_button_active_index (GtkWidget *radiobutton) } static void -set_config_from_radiobuttongroup (GtkWidget *radiobutton, const char *config_name, GList *senum) +set_value_from_radiobuttongroup (PropertyInfo *info, GValue *value) { int index; - index = get_radio_button_active_index (radiobutton); + g_return_if_fail (GTK_IS_RADIO_BUTTON (info->widget)); + + index = get_radio_button_active_index (info->widget); + g_return_if_fail (index >= 0); - if (senum) + g_value_init (value, info->data_type); + if (info->data_type == G_TYPE_STRING) + { + g_return_if_fail (info->string_enum != NULL); + + g_value_set_string (value, (char*) g_list_nth_data (info->string_enum, index)); + } + else if (info->data_type == G_TYPE_INT) { - eel_gconf_set_string (config_name, g_list_nth_data (senum, index)); + g_value_set_int (value, index); } else { - eel_gconf_set_integer (config_name, index); + g_warning ("unsupported data type for radio button %s\n", info->id); } } static void -set_config_from_spin_button (GtkWidget *spinbutton, const char *config_name) +set_value_from_spin_button (PropertyInfo *info, GValue *value) { - gdouble value; - gboolean use_int; + gdouble f; + gboolean is_int; - /* read the value as an integer */ - value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spinbutton)); + g_return_if_fail (GTK_IS_SPIN_BUTTON (info->widget)); - use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0); + f = gtk_spin_button_get_value (GTK_SPIN_BUTTON (info->widget)); - if (use_int) + is_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(info->widget)) == 0); + + g_value_init (value, info->data_type); + if (info->data_type == G_TYPE_INT && is_int) + { + g_value_set_int (value, (int) f); + } + else if (info->data_type == G_TYPE_FLOAT) { - eel_gconf_set_integer (config_name, value); + g_value_set_float (value, f); } else { - eel_gconf_set_float (config_name, value); + g_warning ("Unsupported data type for spin button %s\n", info->id); } } static void -set_config_from_togglebutton (GtkWidget *togglebutton, const char *config_name) +set_value_from_togglebutton (PropertyInfo *info, GValue *value) { - gboolean value; + gboolean active; - /* read the value */ - value = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(togglebutton)); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (info->widget)); - eel_gconf_set_boolean (config_name, value); + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (info->widget)); + + g_value_init (value, info->data_type); + if (info->data_type == G_TYPE_BOOLEAN) + { + g_value_set_boolean (value, active); + } + else + { + g_warning ("Unsupported data type for toggle button %s\n", info->id); + } } static void -set_editable_from_config (GtkWidget *editable, const char *config_name) +set_value_from_info (PropertyInfo *info, GValue *value) { - GConfValue *gcvalue = eel_gconf_get_value (config_name); - GConfValueType value_type; - gchar *value; - - if (gcvalue == NULL) + if (info->sane_state == FALSE) { - /* ugly hack around what appears to be a gconf bug - * it returns a NULL GConfValue for a valid string pref - * which is "" by default */ - value_type = GCONF_VALUE_STRING; + g_warning ("id[%s] has insane state when trying to get value!\n", info->id); } - else + + switch (info->widget_type) { - value_type = gcvalue->type; - gconf_value_free (gcvalue); + case PT_SPINBUTTON: + set_value_from_spin_button (info, value); + break; + case PT_RADIOBUTTON: + set_value_from_radiobuttongroup (info, value); + break; + case PT_TOGGLEBUTTON: + set_value_from_togglebutton (info, value); + break; + case PT_EDITABLE: + set_value_from_editable (info, value); + break; + case PT_OPTIONMENU: + set_value_from_optionmenu (info, value); + break; + case PT_COMBOBOX: + set_value_from_combobox (info, value); + break; + default: + g_warning ("Unsupported widget type\n"); + break; } +} - switch (value_type) +static void +set_editable_from_value (PropertyInfo *info, const GValue *value) +{ + char *text = NULL; + int pos; + + g_return_if_fail (GTK_IS_EDITABLE (info->widget)); + + switch (info->data_type) { - case GCONF_VALUE_STRING: - value = eel_gconf_get_string (config_name); - break; - case GCONF_VALUE_INT: - value = g_strdup_printf ("%d",eel_gconf_get_integer (config_name)); - break; - case GCONF_VALUE_FLOAT: - value = g_strdup_printf ("%.2f",eel_gconf_get_float (config_name)); - break; - default: - value = NULL; + case G_TYPE_STRING: + text = g_value_dup_string (value); + break; + case G_TYPE_INT: + text = g_strdup_printf ("%d", g_value_get_int (value)); + break; + case G_TYPE_FLOAT: + text = g_strdup_printf ("%.2f", g_value_get_float (value)); + break; + default: + break; } - /* set this string value in the widget */ - if (value) + if (text == NULL) { - gtk_entry_set_text(GTK_ENTRY(editable), value); + text = g_strdup (""); } + info->sane_state = TRUE; + + gtk_editable_delete_text (GTK_EDITABLE (info->widget), 0, -1); + gtk_editable_insert_text (GTK_EDITABLE (info->widget), text, strlen (text), &pos); - /* free the allocated string */ - g_free (value); + g_free (text); } static int -get_index (const char *config_name, GList *senum) +get_index_from_value (const GValue *value, GList *string_enum) { - int index = 0; - char *val; + int index = -1; + const char *val; GList *s = NULL; - if (senum) + if (string_enum) { - val = eel_gconf_get_string (config_name); + val = g_value_get_string (value); if (val) { - s = g_list_find_custom (senum, val, (GCompareFunc)strcmp); - g_free (val); + s = g_list_find_custom (string_enum, val, (GCompareFunc) strcmp); } if (s) { - index = g_list_position (senum, s); + index = g_list_position (string_enum, s); } } else { - index = eel_gconf_get_integer (config_name); + index = g_value_get_int (value); } return index; } - -static void -set_optionmenu_from_config (GtkWidget *optionmenu, const char *config_name, GList *senum) -{ - gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), - get_index (config_name, senum)); -} - - static void -set_radiobuttongroup_from_config (GtkWidget *radiobutton, const char *config_name, GList *senum) +set_optionmenu_from_value (PropertyInfo *info, const GValue *value) { - GtkToggleButton *button; - GSList *list; - gint length; int index; - index = get_index (config_name, senum); + g_return_if_fail (GTK_IS_OPTION_MENU (info->widget)); - /* get the list */ - list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton)); + index = get_index_from_value (value, info->string_enum); + if (index < 0) + { + info->sane_state = FALSE; + g_warning ("Index < 0 when setting optionmenu %s\n", info->id); + return; + } - /* check out the length */ - length = g_slist_length (list); + info->sane_state = TRUE; - /* new buttons are *preppended* to the list, so button added as first - * has last position in the list */ - index = (length - 1) - index; + gtk_option_menu_set_history (GTK_OPTION_MENU (info->widget), index); +} - /* find the right button */ - button = GTK_TOGGLE_BUTTON (g_slist_nth_data (list, index)); +static gboolean +compare_values (const GValue *a, const GValue *b) +{ + if (G_VALUE_HOLDS (a, G_TYPE_STRING)) + { + const char *ta, *tb; - /* set it... this will de-activate the others in the group */ - if (gtk_toggle_button_get_active (button) == FALSE) + ta = g_value_get_string (a); + tb = g_value_get_string (b); + + return (ta && tb && strcmp (ta, tb) == 0); + } + else if (G_VALUE_HOLDS (a, G_TYPE_INT)) { - gtk_toggle_button_set_active (button, TRUE); + return g_value_get_int (a) == g_value_get_int (b); + } + else if (G_VALUE_HOLDS (a, G_TYPE_FLOAT)) + { + return g_value_get_float (a) == g_value_get_float (b); + } + else if (G_VALUE_HOLDS (a, G_TYPE_BOOLEAN)) + { + return g_value_get_boolean (a) == g_value_get_boolean (b); } + + return FALSE; } static void -set_spin_button_from_config (GtkWidget *spinbutton, const char *config_name) +set_combo_box_from_value (PropertyInfo *info, const GValue *value) { - gdouble value; - gint use_int; + int index = -1; - use_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON(spinbutton)) == 0); + g_return_if_fail (GTK_IS_COMBO_BOX (info->widget)); - if (use_int) + if (info->data_col != -1) { - /* get the current value from the configuration space */ - value = eel_gconf_get_integer (config_name); + GValue data = { 0, }; + GtkTreeModel *model; + GtkTreeIter iter; + gboolean valid, found = FALSE; + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (info->widget)); + + g_return_if_fail (gtk_tree_model_get_column_type (model, info->data_col) == info->data_type); + + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid) + { + gtk_tree_model_get_value (model, &iter, info->data_col, &data); + found = compare_values (&data, value); + if (found) break; + + g_value_unset (&data); + valid = gtk_tree_model_iter_next (model, &iter); + } + + if (found) + { + GtkTreePath *path; + gint *indices; + + path = gtk_tree_model_get_path (model, &iter); + indices = gtk_tree_path_get_indices (path); + index = indices[0]; + gtk_tree_path_free (path); + } + } + else if (info->data_type == G_TYPE_INT) + { + index = g_value_get_int (value); } else { - /* get the current value from the configuration space */ - value = eel_gconf_get_float (config_name); + g_warning ("Unsupported data type for combo box %s\n", info->id); + } + + if (index < 0) + { + info->sane_state = FALSE; + + g_return_if_fail (index >= 0); } - /* set this option value in the widget */ - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton), value); + LOG ("index[%s] is %d", info->id, index) + + info->sane_state = TRUE; + + gtk_combo_box_set_active (GTK_COMBO_BOX (info->widget), index); } static void -set_togglebutton_from_config (GtkWidget *togglebutton, const char *config_name) +set_radiobuttongroup_from_value (PropertyInfo *info, const GValue *value) { - gboolean value; + GtkToggleButton *button; + GSList *list; + gint length; + int index; - /* get the current value from the configuration space */ - value = eel_gconf_get_boolean (config_name); + g_return_if_fail (GTK_IS_RADIO_BUTTON (info->widget)); - /* set this option value in the widget */ - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (togglebutton), value); -} + list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (info->widget)); -static PrefType -get_pref_type_from_widget (GtkWidget *widget) -{ - if (GTK_IS_OPTION_MENU (widget)) + length = g_slist_length (list); + + index = get_index_from_value (value, info->string_enum); + + /* new buttons are *prepended* to the list, so button added as first + * has last position in the list */ + index = (length - 1) - index; + + if (index < 0 || index >= length) { - return PT_OPTIONMENU; + info->sane_state = FALSE; + g_return_if_fail (index >= 0 && index < length); } - else if (GTK_IS_SPIN_BUTTON (widget)) + + button = GTK_TOGGLE_BUTTON (g_slist_nth_data (list, index)); + g_return_if_fail (button != NULL); + + info->sane_state = TRUE; + + if (gtk_toggle_button_get_active (button) == FALSE) { - return PT_SPINBUTTON; + gtk_toggle_button_set_active (button, TRUE); } - else if (GTK_IS_RADIO_BUTTON (widget)) +} + +static void +set_spin_button_from_value (PropertyInfo *info, const GValue *value) +{ + gdouble f = 0.0; + gboolean is_int; + + g_return_if_fail (GTK_IS_SPIN_BUTTON (info->widget)); + + is_int = (gtk_spin_button_get_digits (GTK_SPIN_BUTTON (info->widget)) == 0); + + if (info->data_type == G_TYPE_INT && is_int) { - return PT_RADIOBUTTON; + f = (float) g_value_get_int (value); } - else if (GTK_IS_TOGGLE_BUTTON (widget)) + else if (info->data_type == G_TYPE_FLOAT) { - return PT_TOGGLEBUTTON; + f = g_value_get_float (value); } - else if (GTK_IS_ENTRY (widget)) + else { - return PT_ENTRY; + info->sane_state = FALSE; + g_warning ("Unsupported data type for spin button %s\n", info->id); + return; } - return PT_UNKNOWN; + info->sane_state = TRUE; + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (info->widget), f); } -static int * -set_controls_sensitivity (EphyDialog *dialog, - int *sg, gboolean s) +static void +set_togglebutton_from_value (PropertyInfo *info, const GValue *value) { - GtkWidget *widget; + gboolean active; - while (*sg != SY_END_GROUP) - { - widget = ephy_dialog_get_control (dialog, - *sg); - gtk_widget_set_sensitive (widget, s); + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (info->widget)); + g_return_if_fail (info->data_type == G_TYPE_BOOLEAN); - sg++; - } + active = g_value_get_boolean (value); + + info->sane_state = TRUE; - return sg; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (info->widget), active); } static void -prefs_set_group_sensitivity (GtkWidget *widget, - PrefType type, int *sg) +set_info_from_value (PropertyInfo *info, const GValue *value) { - int group = -1; - EphyDialog *dialog; - int i = 0; - - if (sg == NULL) return; - - dialog = EPHY_DIALOG (g_object_get_data - (G_OBJECT(widget), "dialog")); - - if (GTK_IS_RADIO_BUTTON (widget)) - { - group = get_radio_button_active_index (widget); - } - else if (GTK_IS_TOGGLE_BUTTON (widget)) + if (!G_VALUE_HOLDS (value, info->data_type)) { - group = !gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON(widget)); + g_warning ("Incompatible value types for id %s\n", info->id); + return; } - else + + switch (info->widget_type) { - g_assert (FALSE); + case PT_SPINBUTTON: + set_spin_button_from_value (info, value); + break; + case PT_RADIOBUTTON: + set_radiobuttongroup_from_value (info, value); + break; + case PT_TOGGLEBUTTON: + set_togglebutton_from_value (info, value); + break; + case PT_EDITABLE: + set_editable_from_value (info, value); + break; + case PT_OPTIONMENU: + set_optionmenu_from_value (info, value); + break; + case PT_COMBOBOX: + set_combo_box_from_value (info, value); + break; + default: + g_warning ("Unknown widget type\n"); + break; } +} - while (*sg != SY_END) - { - if ((*sg == SY_BEGIN_GROUP) || - (*sg == SY_BEGIN_GROUP_INVERSE)) - { - gboolean b; +/* widget changed callbacks */ - b = (i == group); - if (*sg == SY_BEGIN_GROUP_INVERSE) b = !b; +static void +set_pref_from_info (PropertyInfo *info) +{ + GValue value = { 0, }; - sg++; - sg = set_controls_sensitivity - (dialog, sg, b); - } + if (info->pref != NULL && info->sane_state) + { + set_value_from_info (info, &value); + set_pref_from_value (info, &value); + g_value_unset (&value); + } - i++; - sg++; + if (info->pref != NULL && !info->sane_state) + { + g_warning ("Not persisting insane state of id[%s] to pref %s!\n", info->id, info->pref); } } static void -prefs_togglebutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi) +togglebutton_clicked_cb (GtkWidget *widget, PropertyInfo *info) { - if (pi->type == PT_AUTOAPPLY) + if (info->apply_type == PT_AUTOAPPLY) { - set_config_from_togglebutton (widget, pi->pref); + set_pref_from_info (info); } - - prefs_set_group_sensitivity (widget, pi->type, pi->sg); } static void -prefs_radiobutton_clicked_cb (GtkWidget *widget, PropertyInfo *pi) +radiobutton_clicked_cb (GtkWidget *widget, PropertyInfo *info) { if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget))) { return; } - if (pi->type == PT_AUTOAPPLY) + if (info->apply_type == PT_AUTOAPPLY) { - set_config_from_radiobuttongroup (widget, pi->pref, pi->string_enum); + set_pref_from_info (info); } - - prefs_set_group_sensitivity (widget, pi->type, pi->sg); } -static gint -prefs_spinbutton_timeout_cb (EphyDialog *dialog) +static gboolean +spinbutton_timeout_cb (PropertyInfo *info) { - PropertyInfo pi = dialog->priv->props[dialog->priv->spin_item_id]; + GTimer *spin_timer; - /* timer still valid? */ - if (dialog->priv->spin_timer == NULL) - { - return FALSE; - } + spin_timer = (GTimer *) g_object_get_data (G_OBJECT (info->widget), "timer"); + + /* timer still valid? */ + if (spin_timer == NULL) + { + /* don't call me again */ + return FALSE; + } - /* okay, we're ready to set */ - if (g_timer_elapsed (dialog->priv->spin_timer, NULL) >= SPIN_DELAY) - { - /* kill off the timer */ - g_timer_destroy (dialog->priv->spin_timer); - dialog->priv->spin_timer = NULL; + /* okay, we're ready to set */ + if (g_timer_elapsed (spin_timer, NULL) >= SPIN_DELAY) + { + /* kill off the timer */ + g_timer_destroy (spin_timer); + g_object_set_data (G_OBJECT (info->widget), "timer", NULL); /* HACK update the spinbutton here so that the * changes made directly in the entry are accepted * and set in the pref. Otherwise the old value is used */ - gtk_spin_button_update (GTK_SPIN_BUTTON(pi.widget)); + gtk_spin_button_update (GTK_SPIN_BUTTON (info->widget)); - /* set */ - set_config_from_spin_button (pi.widget, pi.pref); + set_pref_from_info (info); - /* done now */ - return FALSE; - } + /* done, don't run again */ + return FALSE; + } - /* call me again */ - return TRUE; + /* not elapsed yet, call me again */ + return TRUE; } static void -prefs_spinbutton_changed_cb (GtkWidget *widget, PropertyInfo *pi) +spinbutton_changed_cb (GtkWidget *widget, PropertyInfo *info) { - EphyDialog *dialog; - - if (pi->type != PT_AUTOAPPLY) return; + GTimer *spin_timer; - dialog = EPHY_DIALOG (g_object_get_data - (G_OBJECT(widget), "dialog")); + if (info->apply_type != PT_AUTOAPPLY) return; - dialog->priv->spin_item_id = pi->id; + spin_timer = g_object_get_data (G_OBJECT (info->widget), "timer"); - /* destroy any existing timer */ - if (dialog->priv->spin_timer != NULL) + /* destroy an existing timer */ + if (spin_timer != NULL) { - g_timer_destroy (dialog->priv->spin_timer); + g_timer_destroy (spin_timer); } - /* start the new one */ - dialog->priv->spin_timer = g_timer_new(); - g_timer_start (dialog->priv->spin_timer); - g_timeout_add (50, (GSourceFunc) prefs_spinbutton_timeout_cb, - dialog); + /* start tnew timer */ + spin_timer = g_timer_new(); + g_timer_start (spin_timer); + g_object_set_data (G_OBJECT (info->widget), "timer", spin_timer); + + g_timeout_add (50, (GSourceFunc) spinbutton_timeout_cb, info); } static void -prefs_entry_changed_cb (GtkWidget *widget, PropertyInfo *pi) +changed_cb (GtkWidget *widget, PropertyInfo *info) { - if (pi->type == PT_AUTOAPPLY) + if (info->apply_type == PT_AUTOAPPLY) { - set_config_from_editable (widget, pi->pref); + set_pref_from_info (info); } } static void -prefs_optionmenu_selected_cb (GtkWidget *widget, PropertyInfo *pi) +set_info_from_pref (PropertyInfo *info) { - if (pi->type == PT_AUTOAPPLY) + GValue value = { 0, }; + + g_return_if_fail (info->widget != NULL); + + if (info->pref != NULL) { - set_config_from_optionmenu (widget, pi->pref, pi->string_enum); + set_value_from_pref (info, &value); + set_info_from_value (info, &value); + g_value_unset (&value); + + if (eel_gconf_key_is_writable (info->pref) == FALSE) + { + set_sensitivity (info, FALSE); + } } } static void -prefs_connect_signals (EphyDialog *dialog) +connect_signals (gpointer key, PropertyInfo *info, EphyDialog *dialog) { - int i; GSList *list; - PropertyInfo *props = dialog->priv->props; - for (i = 0; props[i].widget != NULL; i++) - { - PrefType type; - PropertyInfo *info; + g_return_if_fail (info->widget != NULL); - if ((props[i].type != PT_AUTOAPPLY) && - (props[i].sg == NULL)) - continue; + if (info->apply_type != PT_AUTOAPPLY) return; - info = &dialog->priv->props[i]; - type = get_pref_type_from_widget - (dialog->priv->props[i].widget); - - switch (type) - { + switch (info->widget_type) + { case PT_TOGGLEBUTTON: - g_object_set_data (G_OBJECT(info->widget), "dialog", dialog); g_signal_connect (G_OBJECT (info->widget), "clicked", - G_CALLBACK(prefs_togglebutton_clicked_cb), + G_CALLBACK (togglebutton_clicked_cb), (gpointer)info); break; case PT_RADIOBUTTON: list = gtk_radio_button_get_group - (GTK_RADIO_BUTTON(info->widget)); + (GTK_RADIO_BUTTON (info->widget)); for (; list != NULL; list = list->next) { - g_object_set_data (G_OBJECT(list->data), - "dialog", dialog); g_signal_connect (G_OBJECT (list->data), "clicked", - G_CALLBACK(prefs_radiobutton_clicked_cb), - (gpointer)info); + G_CALLBACK (radiobutton_clicked_cb), + info); } break; case PT_SPINBUTTON: - g_object_set_data (G_OBJECT(info->widget), "dialog", dialog); g_signal_connect (G_OBJECT (info->widget), "changed", - G_CALLBACK(prefs_spinbutton_changed_cb), - (gpointer)info); + G_CALLBACK (spinbutton_changed_cb), + info); break; case PT_OPTIONMENU: - g_signal_connect (G_OBJECT (info->widget), - "changed", - G_CALLBACK(prefs_optionmenu_selected_cb), - (gpointer)info); + g_signal_connect (G_OBJECT (info->widget), "changed", + G_CALLBACK (changed_cb), info); break; - case PT_ENTRY: + case PT_COMBOBOX: g_signal_connect (G_OBJECT (info->widget), "changed", - G_CALLBACK(prefs_entry_changed_cb), - (gpointer)info); + G_CALLBACK (changed_cb), info); + break; + case PT_EDITABLE: + g_signal_connect (G_OBJECT (info->widget), "changed", + G_CALLBACK (changed_cb), info); break; case PT_UNKNOWN: + g_warning ("Unsupported widget type\n"); break; - } } } static void -ephy_dialog_init (EphyDialog *dialog) +disconnect_signals (gpointer key, PropertyInfo *info, EphyDialog *dialog) { - dialog->priv = EPHY_DIALOG_GET_PRIVATE (dialog); - - dialog->priv->parent = NULL; - dialog->priv->dialog = NULL; - dialog->priv->props = NULL; - dialog->priv->spin_timer = NULL; - dialog->priv->name = NULL; - dialog->priv->initialized = FALSE; - dialog->priv->has_default_size = FALSE; - dialog->priv->disposing = FALSE; -} - -static void -prefs_set_sensitivity (PropertyInfo *props) -{ - int i; - - for (i=0 ; props[i].id >= 0; i++) - { - if (props[i].sg == NULL) continue; + g_return_if_fail (info->widget != NULL); - g_return_if_fail (props[i].widget != NULL); - - if (GTK_IS_RADIO_BUTTON(props[i].widget) || - GTK_IS_TOGGLE_BUTTON(props[i].widget)) - { - prefs_set_group_sensitivity (props[i].widget, - props[i].type, - props[i].sg); - } - } + g_signal_handlers_disconnect_matched (info->widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, info); } static void -load_props (PropertyInfo *props) +init_props (EphyDialog *dialog, const EphyDialogProperty *properties, GladeXML *gxml) { int i; - for (i=0 ; props[i].id >= 0; i++) + for (i = 0 ; properties[i].id != NULL; i++) { - if (props[i].pref == NULL) continue; - - g_return_if_fail (props[i].widget != NULL); - - if (GTK_IS_SPIN_BUTTON(props[i].widget)) - { - set_spin_button_from_config (props[i].widget, - props[i].pref); - } - else if (GTK_IS_RADIO_BUTTON(props[i].widget)) - { - set_radiobuttongroup_from_config (props[i].widget, - props[i].pref, - props[i].string_enum); - } - else if (GTK_IS_TOGGLE_BUTTON(props[i].widget)) + PropertyInfo *info = g_new0 (PropertyInfo, 1); + + info->id = properties[i].id; + info->pref = g_strdup (properties[i].pref); + info->apply_type = properties[i].apply_type; + info->string_enum = NULL; + info->data_col = -1; + + info->widget = glade_xml_get_widget (gxml, info->id); + + if (GTK_IS_OPTION_MENU (info->widget)) { - set_togglebutton_from_config (props[i].widget, - props[i].pref); + info->widget_type = PT_OPTIONMENU; + info->data_type = G_TYPE_INT; } - else if (GTK_IS_EDITABLE(props[i].widget)) + else if (GTK_IS_COMBO_BOX (info->widget)) { - set_editable_from_config (props[i].widget, - props[i].pref); + info->widget_type = PT_COMBOBOX; + info->data_type = G_TYPE_INT; } - else if (GTK_IS_OPTION_MENU(props[i].widget)) + else if (GTK_IS_SPIN_BUTTON (info->widget)) { - set_optionmenu_from_config (props[i].widget, - props[i].pref, - props[i].string_enum); + info->widget_type = PT_SPINBUTTON; + info->data_type = G_TYPE_INT; } - } - -} - -static void -save_props (PropertyInfo *props) -{ - int i; - - for (i=0 ; props[i].id >= 0; i++) - { - if ((props[i].pref == NULL) || - (props[i].type != PT_NORMAL)) continue; - g_return_if_fail (props[i].widget != NULL); - - if (GTK_IS_SPIN_BUTTON(props[i].widget)) + else if (GTK_IS_RADIO_BUTTON (info->widget)) { - set_config_from_spin_button (props[i].widget, - props[i].pref); + info->widget_type = PT_RADIOBUTTON; + info->data_type = G_TYPE_INT; } - else if (GTK_IS_RADIO_BUTTON(props[i].widget)) + else if (GTK_IS_TOGGLE_BUTTON (info->widget)) { - set_config_from_radiobuttongroup (props[i].widget, - props[i].pref, - props[i].string_enum); + info->widget_type = PT_TOGGLEBUTTON; + info->data_type = G_TYPE_BOOLEAN; } - else if (GTK_IS_TOGGLE_BUTTON(props[i].widget)) + else if (GTK_IS_EDITABLE (info->widget)) { - set_config_from_togglebutton (props[i].widget, - props[i].pref); + info->widget_type = PT_EDITABLE; + info->data_type = G_TYPE_STRING; } - else if (GTK_IS_EDITABLE(props[i].widget)) + else { - set_config_from_editable (props[i].widget, - props[i].pref); + info->widget_type = PT_UNKNOWN; + info->data_type = G_TYPE_INVALID; } - else if (GTK_IS_OPTION_MENU(props[i].widget)) + + if (properties[i].data_type != 0) { - set_config_from_optionmenu (props[i].widget, - props[i].pref, - props[i].string_enum); + info->data_type = properties[i].data_type; } + + info->loaded = FALSE; + info->sane_state = FALSE; + + g_hash_table_insert (dialog->priv->props, (char *) info->id, info); } } static void -free_props (PropertyInfo *properties) +load_info (gpointer key, PropertyInfo *info, EphyDialog *dialog) { - int i; + set_info_from_pref (info); - for (i = 0; properties[i].string_enum != NULL; i++) + info->loaded = TRUE; +} + +static void +save_info (gpointer key, PropertyInfo *info, EphyDialog *dialog) +{ + if (info->apply_type == PT_NORMAL) { - g_list_foreach (properties[i].string_enum, (GFunc)g_free, NULL); - g_list_free (properties[i].string_enum); + set_pref_from_info (info); } } static void -ephy_dialog_finalize (GObject *object) +setup_default_size (EphyDialog *dialog) { - EphyDialog *dialog = EPHY_DIALOG (object); - - free_props (dialog->priv->props); - - g_free (dialog->priv->name); - g_free (dialog->priv->props); + if (dialog->priv->has_default_size == FALSE) + { + ephy_state_add_window (dialog->priv->dialog, + dialog->priv->name, -1, -1, + EPHY_STATE_WINDOW_SAVE_SIZE); - G_OBJECT_CLASS (parent_class)->finalize (object); + dialog->priv->has_default_size = TRUE; + } } static void -ephy_dialog_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +dialog_destroy_cb (GtkWidget *widget, EphyDialog *dialog) { - EphyDialog *d = EPHY_DIALOG (object); + g_hash_table_foreach (dialog->priv->props, (GHFunc) save_info, dialog); - switch (prop_id) - { - case PROP_PARENT_WINDOW: - ephy_dialog_set_parent (d, g_value_get_object (value)); - break; - case PROP_MODAL: - ephy_dialog_set_modal (d, g_value_get_boolean (value)); - break; - } + if (dialog->priv->disposing == FALSE) + { + g_object_unref (dialog); + } } static void -ephy_dialog_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +impl_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name) { - EphyDialog *d = EPHY_DIALOG (object); + GladeXML *gxml; - switch (prop_id) - { - case PROP_PARENT_WINDOW: - g_value_set_object (value, d->priv->parent); - break; - case PROP_MODAL: - g_value_set_boolean (value, d->priv->modal); - } + gxml = ephy_glade_widget_new (file, name, &(dialog->priv->dialog), dialog); + + if (dialog->priv->name == NULL) + { + dialog->priv->name = g_strdup (name); + } + + if (properties) + { + init_props (dialog, properties, gxml); + } + + g_signal_connect_object (dialog->priv->dialog, + "destroy", + G_CALLBACK(dialog_destroy_cb), + dialog, 0); + + g_object_unref (gxml); } static void -ephy_dialog_set_parent (EphyDialog *dialog, - GtkWidget *parent) +impl_show (EphyDialog *dialog) { - g_return_if_fail (dialog->priv->parent == NULL); - g_return_if_fail (GTK_IS_WINDOW(parent)); - g_return_if_fail (GTK_IS_WINDOW(dialog->priv->dialog)); + if (dialog->priv->initialized == FALSE) + { + dialog->priv->initialized = TRUE; - dialog->priv->parent = parent; + g_hash_table_foreach (dialog->priv->props, (GHFunc) load_info, dialog); + g_hash_table_foreach (dialog->priv->props, (GHFunc) connect_signals, dialog); + } - gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), - GTK_WINDOW (parent)); + setup_default_size (dialog); - g_object_notify (G_OBJECT (dialog), "ParentWindow"); -} + if (dialog->priv->parent) + { + /* make the dialog transient again, because it seems to get + * forgotten after gtk_widget_hide + */ + gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), + GTK_WINDOW (dialog->priv->parent)); + } -EphyDialog * -ephy_dialog_new (void) -{ - return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG, NULL)); + gtk_window_present (GTK_WINDOW (dialog->priv->dialog)); } -EphyDialog * -ephy_dialog_new_with_parent (GtkWidget *parent_window) +void +ephy_dialog_set_modal (EphyDialog *dialog, + gboolean is_modal) { - return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG, - "ParentWindow", parent_window, - NULL)); + dialog->priv->modal = is_modal; + + gtk_window_set_modal (GTK_WINDOW(dialog->priv->dialog), is_modal); } void ephy_dialog_add_enum (EphyDialog *dialog, - int id, + const char *id, guint n_items, const char **items) { + PropertyInfo *info; int i = 0; GList *l = NULL; + info = lookup_info (dialog, id); + g_return_if_fail (info != NULL); + for (i = 0; i < n_items; i++) { - l = g_list_append (l, g_strdup (items[i])); + l = g_list_prepend (l, g_strdup (items[i])); } - dialog->priv->props[id].string_enum = l; + info->string_enum = g_list_reverse (l); } -static PropertyInfo * -init_props (const EphyDialogProperty *properties, GladeXML *gxml) +void +ephy_dialog_set_data_column (EphyDialog *dialog, + const char *id, + int column) { - PropertyInfo *props; - int i; + PropertyInfo *info; - for (i=0 ; properties[i].control_name != NULL; i++); + info = lookup_info (dialog, id); + g_return_if_fail (info != NULL); - props = g_new0 (PropertyInfo, i+1); + info->data_col = column; +} - for (i=0 ; properties[i].control_name != NULL; i++) - { - props[i].id = properties[i].id; - props[i].widget = glade_xml_get_widget - (gxml, properties[i].control_name); - props[i].pref = properties[i].state_pref; - props[i].sg = properties[i].sg; - props[i].type = properties[i].type; - props[i].string_enum = NULL; - } +void +ephy_dialog_set_pref (EphyDialog *dialog, + const char *property_id, + const char *pref) +{ + PropertyInfo *info; - props[i].id = -1; - props[i].widget = NULL; - props[i].pref = NULL; - props[i].sg = NULL; - props[i].type = 0; - props[i].string_enum = NULL; + info = lookup_info (dialog, property_id); + g_return_if_fail (info != NULL); - return props; -} + disconnect_signals (NULL, info, dialog); -static void -dialog_destroy_cb (GtkWidget *widget, EphyDialog *dialog) -{ - if (dialog->priv->props) - { - save_props (dialog->priv->props); - } + info->loaded = FALSE; + info->sane_state = FALSE; + g_free (info->pref); + info->pref = g_strdup (pref); - if (!dialog->priv->disposing) + if (dialog->priv->initialized) { - g_object_unref (dialog); + /* dialog is already initialised, so initialise this here */ + load_info (NULL, info, dialog); + connect_signals (NULL, info, dialog); } } -static void -impl_construct (EphyDialog *dialog, - const EphyDialogProperty *properties, - const char *file, - const char *name) +void +ephy_dialog_set_size_group (EphyDialog *dialog, + const char **controls_id, + guint n_controls) { - GladeXML *gxml; + GtkSizeGroup *size_group; + int i; - gxml = ephy_glade_widget_new - (file, name, &(dialog->priv->dialog), dialog); + size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - if (dialog->priv->name == NULL) + for (i = 0; i < n_controls; i++) { - dialog->priv->name = g_strdup (name); - } + PropertyInfo *info; - if (properties) - { - dialog->priv->props = init_props (properties, gxml); + info = lookup_info (dialog, controls_id[i]); + g_return_if_fail (info != NULL); + + g_return_if_fail (info->widget != NULL); + + gtk_size_group_add_widget (size_group, info->widget); } +} - g_signal_connect_object (dialog->priv->dialog, - "destroy", - G_CALLBACK(dialog_destroy_cb), - dialog, 0); +void +ephy_dialog_construct (EphyDialog *dialog, + const EphyDialogProperty *properties, + const char *file, + const char *name) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + return klass->construct (dialog, properties, file, name); +} - g_object_unref (gxml); +void +ephy_dialog_show (EphyDialog *dialog) +{ + EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); + klass->show (dialog); } -static GtkWidget * -impl_get_control (EphyDialog *dialog, - int property_id) +int +ephy_dialog_run (EphyDialog *dialog) { - return dialog->priv->props[property_id].widget; + ephy_dialog_show (dialog); + + return gtk_dialog_run (GTK_DIALOG (dialog->priv->dialog)); } -static void -impl_get_value (EphyDialog *dialog, - int property_id, - GValue *value) +GtkWidget * +ephy_dialog_get_control (EphyDialog *dialog, + const char *property_id) { - GtkWidget *widget = ephy_dialog_get_control (dialog, - property_id); + PropertyInfo *info; - if (GTK_IS_SPIN_BUTTON (widget)) - { - float val; - g_value_init (value, G_TYPE_FLOAT); - val = gtk_spin_button_get_value (GTK_SPIN_BUTTON(widget)); - g_value_set_float (value, val); - } - else if (GTK_IS_RADIO_BUTTON (widget)) - { - int val; - g_value_init (value, G_TYPE_INT); - val = get_radio_button_active_index (widget); - g_value_set_int (value, val); - } - else if (GTK_IS_TOGGLE_BUTTON (widget)) - { - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, gtk_toggle_button_get_active - (GTK_TOGGLE_BUTTON(widget))); - } - else if (GTK_IS_EDITABLE (widget)) - { - gchar *text = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1); - g_value_init (value, G_TYPE_STRING); - g_value_set_string (value, text); - g_free (text); - } - else if (GTK_IS_OPTION_MENU (widget)) - { - int val; - g_value_init (value, G_TYPE_INT); - val = gtk_option_menu_get_history (GTK_OPTION_MENU(widget)); - g_value_set_int (value, val); - } + info = lookup_info (dialog, property_id); + g_return_val_if_fail (info != NULL, NULL); + + return info->widget; } -static void -setup_default_size (EphyDialog *dialog) +void +ephy_dialog_get_value (EphyDialog *dialog, + const char *property_id, + GValue *value) { - if (!dialog->priv->has_default_size) - { - ephy_state_add_window (dialog->priv->dialog, - dialog->priv->name, -1, -1, - EPHY_STATE_WINDOW_SAVE_SIZE); - } + PropertyInfo *info; - dialog->priv->has_default_size = TRUE; + info = lookup_info (dialog, property_id); + g_return_if_fail (info != NULL); + + set_value_from_info (info, value); } -static gint -impl_run (EphyDialog *dialog) +void +ephy_dialog_set_value (EphyDialog *dialog, + const char *property_id, + const GValue *value) { - ephy_dialog_show (dialog); + PropertyInfo *info; - return gtk_dialog_run (GTK_DIALOG(dialog->priv->dialog)); + info = lookup_info (dialog, property_id); + g_return_if_fail (info != NULL); + + set_info_from_value (info, value); } static void -impl_show (EphyDialog *dialog) +free_prop_info (PropertyInfo *info) { - if (dialog->priv->props && !dialog->priv->initialized) + if (info->string_enum) { - load_props (dialog->priv->props); - prefs_connect_signals (dialog); - prefs_set_sensitivity (dialog->priv->props); - dialog->priv->initialized = TRUE; + g_list_foreach (info->string_enum, (GFunc)g_free, NULL); + g_list_free (info->string_enum); } - setup_default_size (dialog); + g_free (info->pref); - if (dialog->priv->parent) - { - /* make the dialog transient again, because it seems to get - * forgotten after gtk_widget_hide - */ - gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), - GTK_WINDOW (dialog->priv->parent)); - } - gtk_window_present (GTK_WINDOW(dialog->priv->dialog)); + g_free (info); } -void -ephy_dialog_set_modal (EphyDialog *dialog, - gboolean is_modal) +static void +ephy_dialog_init (EphyDialog *dialog) { - dialog->priv->modal = is_modal; + dialog->priv = EPHY_DIALOG_GET_PRIVATE (dialog); - gtk_window_set_modal (GTK_WINDOW(dialog->priv->dialog), - is_modal); + dialog->priv->parent = NULL; + dialog->priv->dialog = NULL; + dialog->priv->name = NULL; + dialog->priv->initialized = FALSE; + dialog->priv->has_default_size = FALSE; + dialog->priv->disposing = FALSE; + + dialog->priv->props = g_hash_table_new_full + (g_str_hash, g_str_equal, NULL, (GDestroyNotify) free_prop_info); } -void -ephy_dialog_construct (EphyDialog *dialog, - const EphyDialogProperty *properties, - const char *file, - const char *name) +static void +ephy_dialog_dispose (GObject *object) { - EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); - return klass->construct (dialog, properties, file, name); + EphyDialog *dialog = EPHY_DIALOG (object); + + if (dialog->priv->dialog) + { + dialog->priv->disposing = TRUE; + gtk_widget_destroy (dialog->priv->dialog); + dialog->priv->dialog = NULL; + } } -gint -ephy_dialog_run (EphyDialog *dialog) +static void +ephy_dialog_finalize (GObject *object) { - EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); - return klass->run (dialog); + EphyDialog *dialog = EPHY_DIALOG (object); + + g_hash_table_destroy (dialog->priv->props); + + g_free (dialog->priv->name); + + G_OBJECT_CLASS (parent_class)->finalize (object); } -void -ephy_dialog_show (EphyDialog *dialog) +static void +ephy_dialog_set_parent (EphyDialog *dialog, + GtkWidget *parent) { - EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); - klass->show (dialog); + g_return_if_fail (dialog->priv->parent == NULL); + g_return_if_fail (GTK_IS_WINDOW (parent)); + g_return_if_fail (GTK_IS_WINDOW (dialog->priv->dialog)); + + dialog->priv->parent = parent; + + gtk_window_set_transient_for (GTK_WINDOW (dialog->priv->dialog), + GTK_WINDOW (parent)); + + g_object_notify (G_OBJECT (dialog), "parent-window"); } -GtkWidget * -ephy_dialog_get_control (EphyDialog *dialog, - int property_id) +static void +ephy_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); - return klass->get_control (dialog, property_id); + EphyDialog *dialog = EPHY_DIALOG (object); + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + ephy_dialog_set_parent (dialog, g_value_get_object (value)); + break; + case PROP_MODAL: + ephy_dialog_set_modal (dialog, g_value_get_boolean (value)); + break; + } } -void -ephy_dialog_get_value (EphyDialog *dialog, - int property_id, - GValue *value) +static void +ephy_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - EphyDialogClass *klass = EPHY_DIALOG_GET_CLASS (dialog); - return klass->get_value (dialog, property_id, value); + EphyDialog *dialog = EPHY_DIALOG (object); + + switch (prop_id) + { + case PROP_PARENT_WINDOW: + g_value_set_object (value, dialog->priv->parent); + break; + case PROP_MODAL: + g_value_set_boolean (value, dialog->priv->modal); + } } -void -ephy_dialog_set_size_group (EphyDialog *dialog, - int *controls_id, - guint n_controls) +static void +ephy_dialog_class_init (EphyDialogClass *klass) { - GtkSizeGroup *size_group; - int i; + GObjectClass *object_class = G_OBJECT_CLASS (klass); - size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + parent_class = g_type_class_peek_parent (klass); - for (i = 0; i < n_controls; i++) - { - GtkWidget *widget; - guint id; + object_class->finalize = ephy_dialog_finalize; + object_class->dispose = ephy_dialog_dispose; + object_class->set_property = ephy_dialog_set_property; + object_class->get_property = ephy_dialog_get_property; - id = controls_id[i]; - widget = dialog->priv->props[id].widget; - g_return_if_fail (GTK_IS_WIDGET (widget)); + klass->construct = impl_construct; + klass->show = impl_show; + + g_object_class_install_property (object_class, + PROP_PARENT_WINDOW, + g_param_spec_object ("parent-window", + "Parent window", + "Parent window", + GTK_TYPE_WINDOW, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_MODAL, + g_param_spec_boolean ("Modal", + "Modal", + "Modal dialog", + FALSE, + G_PARAM_READWRITE)); - gtk_size_group_add_widget (size_group, widget); - } + g_type_class_add_private (object_class, sizeof (EphyDialogPrivate)); +} + +EphyDialog * +ephy_dialog_new (void) +{ + return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG, NULL)); +} + +EphyDialog * +ephy_dialog_new_with_parent (GtkWidget *parent_window) +{ + return EPHY_DIALOG (g_object_new (EPHY_TYPE_DIALOG, + "parent-window", parent_window, + NULL)); } diff --git a/lib/ephy-dialog.h b/lib/ephy-dialog.h index a440dd625..a1ed97f1f 100644 --- a/lib/ephy-dialog.h +++ b/lib/ephy-dialog.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2000-2003 Marco Pesenti Gritti + * Copyright (C) 2003 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 @@ -27,102 +28,96 @@ G_BEGIN_DECLS -#define EPHY_TYPE_DIALOG (ephy_dialog_get_type ()) -#define EPHY_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_DIALOG, EphyDialog)) -#define EPHY_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_DIALOG, EphyDialogClass)) -#define EPHY_IS_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_DIALOG)) -#define EPHY_IS_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_DIALOG)) -#define EPHY_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_DIALOG, EphyDialogClass)) +#define EPHY_TYPE_DIALOG (ephy_dialog_get_type ()) +#define EPHY_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EPHY_TYPE_DIALOG, EphyDialog)) +#define EPHY_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), EPHY_TYPE_DIALOG, EphyDialogClass)) +#define EPHY_IS_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EPHY_TYPE_DIALOG)) +#define EPHY_IS_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EPHY_TYPE_DIALOG)) +#define EPHY_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EPHY_TYPE_DIALOG, EphyDialogClass)) -typedef struct EphyDialogClass EphyDialogClass; -typedef struct EphyDialog EphyDialog; -typedef struct EphyDialogPrivate EphyDialogPrivate; - -#define SY_BEGIN_GROUP -20 -#define SY_END_GROUP -21 -#define SY_END -22 -#define SY_BEGIN_GROUP_INVERSE -23 - -struct EphyDialog -{ - GObject parent; - - /*< private >*/ - EphyDialogPrivate *priv; -}; +typedef struct EphyDialogClass EphyDialogClass; +typedef struct EphyDialog EphyDialog; +typedef struct EphyDialogPrivate EphyDialogPrivate; typedef enum { PT_NORMAL, PT_AUTOAPPLY -} PropertyType; +} EphyDialogApplyType; typedef struct { - int id; - const char *control_name; - const char *state_pref; - PropertyType type; - int *sg; + const char *id; + const char *pref; + EphyDialogApplyType apply_type; + GType data_type; } EphyDialogProperty; struct EphyDialogClass { - GObjectClass parent_class; + GObjectClass parent_class; - void (* construct) (EphyDialog *dialog, + void (* construct) (EphyDialog *dialog, const EphyDialogProperty *properties, const char *file, - const char *name); - gint (* run) (EphyDialog *dialog); - void (* show) (EphyDialog *dialog); - GtkWidget * (* get_control) (EphyDialog *dialog, - int property_id); - void (* get_value) (EphyDialog *dialog, - int property_id, - GValue *value); + const char *name); + void (* show) (EphyDialog *dialog); }; -GType ephy_dialog_get_type (void); +struct EphyDialog +{ + GObject parent; -EphyDialog *ephy_dialog_new (void); + /*< private >*/ + EphyDialogPrivate *priv; +}; -EphyDialog *ephy_dialog_new_with_parent (GtkWidget *parent_window); +GType ephy_dialog_get_type (void); -void ephy_dialog_construct (EphyDialog *dialog, +EphyDialog *ephy_dialog_new (void); + +EphyDialog *ephy_dialog_new_with_parent (GtkWidget *parent_window); + +void ephy_dialog_construct (EphyDialog *dialog, const EphyDialogProperty *properties, const char *file, const char *name); -void ephy_dialog_add_enum (EphyDialog *dialog, - int id, +void ephy_dialog_add_enum (EphyDialog *dialog, + const char *id, guint n_items, const char **items); -void ephy_dialog_set_size_group (EphyDialog *dialog, - int *controls_id, - guint n_controls); +void ephy_dialog_set_data_column (EphyDialog *dialog, + const char *id, + int col); -gint ephy_dialog_run (EphyDialog *dialog); - -void ephy_dialog_show (EphyDialog *dialog); +void ephy_dialog_set_size_group (EphyDialog *dialog, + const char **controls_id, + guint n_controls); -void ephy_dialog_show_embedded (EphyDialog *dialog, - GtkWidget *container); +int ephy_dialog_run (EphyDialog *dialog); -void ephy_dialog_remove_embedded (EphyDialog *dialog); +void ephy_dialog_show (EphyDialog *dialog); -void ephy_dialog_set_modal (EphyDialog *dialog, +void ephy_dialog_set_modal (EphyDialog *dialog, gboolean is_modal); -GtkWidget *ephy_dialog_get_control (EphyDialog *dialog, - int property_id); +GtkWidget *ephy_dialog_get_control (EphyDialog *dialog, + const char *property_id); -void ephy_dialog_get_value (EphyDialog *dialog, - int property_id, +void ephy_dialog_get_value (EphyDialog *dialog, + const char *property_id, GValue *value); +void ephy_dialog_set_value (EphyDialog *dialog, + const char *property_id, + const GValue *value); + +void ephy_dialog_set_pref (EphyDialog *dialog, + const char *property_id, + const char *pref); + G_END_DECLS #endif - diff --git a/lib/ephy-file-chooser.c b/lib/ephy-file-chooser.c index ec8cf2d27..668c7b522 100644 --- a/lib/ephy-file-chooser.c +++ b/lib/ephy-file-chooser.c @@ -237,7 +237,10 @@ ephy_file_chooser_new (const char *title, * _after_ our instance_init and construct-param setters will have * run. */ - ephy_file_chooser_set_persist_key (dialog, persist_key); + if (persist_key != NULL) + { + ephy_file_chooser_set_persist_key (dialog, persist_key); + } if (action == GTK_FILE_CHOOSER_ACTION_OPEN) { |