1.12.42
[gnumeric.git] / src / dialogs / dialog-preferences.c
blobae8447190309d5b3691c8e4ad149f8a96b390c11
1 /*
2 * dialog-preferences.c: Dialog to edit application wide preferences and default values
4 * Author:
5 * Andreas J. Guelzow <aguelzow@taliesin.ca>
7 * (C) Copyright 2000-2002 Jody Goldberg <jody@gnome.org>
8 * (C) Copyright 2003-2004 Andreas J. Guelzow <aguelzow@taliesin.ca>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <https://www.gnu.org/licenses/>.
24 #include <gnumeric-config.h>
25 #include <gnumeric.h>
26 #include <application.h>
27 #include <dialogs/dialogs.h>
28 #include <dialogs/help.h>
30 #include <mstyle.h>
31 #include <value.h>
32 #include <gnm-format.h>
33 #include <workbook.h>
34 #include <workbook-control.h>
35 #include <wbc-gtk.h>
36 #include <number-match.h>
37 #include <widgets/gnm-cell-renderer-text.h>
39 #include <gnumeric-conf.h>
41 #include <gui-util.h>
42 #include <glib/gi18n-lib.h>
43 #include <string.h>
45 #define PREF_DIALOG_KEY "pref-dialog"
47 enum {
48 ITEM_ICON,
49 ITEM_NAME,
50 PAGE_NUMBER,
51 NUM_COLUMNS
54 typedef struct {
55 GtkBuilder *gui;
56 GtkWidget *dialog;
57 GtkNotebook *notebook;
58 GtkTreeStore *store;
59 GtkTreeView *view;
60 gulong app_wb_removed_sig;
61 } PrefState;
63 typedef void (* double_conf_setter_t) (double value);
64 typedef void (* gint_conf_setter_t) (gint value);
65 typedef void (* gboolean_conf_setter_t) (gboolean value);
66 typedef void (* enum_conf_setter_t) (int value);
67 typedef void (* wordlist_conf_setter_t) (GSList *value);
69 typedef gboolean (* gboolean_conf_getter_t) (void);
70 typedef GSList * (* wordlist_conf_getter_t) (void);
71 typedef int (* enum_conf_getter_t) (void);
72 typedef gint (* gint_conf_getter_t) (void);
73 typedef double (* double_conf_getter_t) (void);
75 static void
76 dialog_pref_add_item (PrefState *state, char const *page_name,
77 char const *icon_name,
78 int page, char const* parent_path)
80 GtkTreeIter iter, parent;
81 GdkPixbuf * icon = NULL;
83 if (icon_name != NULL)
84 icon = gtk_widget_render_icon_pixbuf (state->dialog, icon_name,
85 GTK_ICON_SIZE_MENU);
86 if ((parent_path != NULL) && gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (state->store),
87 &parent, parent_path))
88 gtk_tree_store_append (state->store, &iter, &parent);
89 else
90 gtk_tree_store_append (state->store, &iter, NULL);
92 gtk_tree_store_set (state->store, &iter,
93 ITEM_ICON, icon,
94 ITEM_NAME, _(page_name),
95 PAGE_NUMBER, page,
96 -1);
97 if (icon != NULL)
98 g_object_unref (icon);
101 static void
102 set_tip (GOConfNode *node, GtkWidget *w)
104 const char *desc = gnm_conf_get_long_desc (node);
105 if (desc != NULL)
106 gtk_widget_set_tooltip_text (w, desc);
109 static void
110 cb_pref_notification_destroy (gpointer handle)
112 go_conf_remove_monitor (GPOINTER_TO_UINT (handle));
115 static void
116 connect_notification (GOConfNode *node, GOConfMonitorFunc func,
117 gpointer data, GtkWidget *container)
119 guint handle = go_conf_add_monitor (node, NULL, func, data);
120 g_signal_connect_swapped (G_OBJECT (container), "destroy",
121 G_CALLBACK (cb_pref_notification_destroy),
122 GUINT_TO_POINTER (handle));
125 /*************************************************************************/
127 static void
128 pref_create_label (GOConfNode *node, GtkWidget *grid,
129 gint row, gchar const *default_label, GtkWidget *w)
131 GtkWidget *label;
133 if (NULL == default_label) {
134 const char *desc = gnm_conf_get_short_desc (node);
135 label = gtk_label_new (desc);
136 } else
137 label = gtk_label_new_with_mnemonic (default_label);
139 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
140 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
141 gtk_widget_set_hexpand (label, TRUE);
142 gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
144 gtk_label_set_mnemonic_widget (GTK_LABEL (label), w);
145 go_atk_setup_label (label, w);
148 /*************************************************************************/
150 static void
151 bool_pref_widget_to_conf (GtkToggleButton *button,
152 gboolean_conf_setter_t setter)
154 gboolean_conf_getter_t getter
155 = g_object_get_data (G_OBJECT (button), "getter");
156 gboolean val_in_button = gtk_toggle_button_get_active (button);
157 gboolean val_in_conf = getter ();
158 if ((!val_in_button) != (!val_in_conf))
159 setter (val_in_button);
162 static void
163 bool_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
164 GtkToggleButton *button)
166 gboolean val_in_button = gtk_toggle_button_get_active (button);
168 /* We can't use the getter here since the main preferences */
169 /* may be notified after us */
170 gboolean val_in_conf = go_conf_get_bool (node, NULL);
172 if ((!val_in_button) != (!val_in_conf))
173 gtk_toggle_button_set_active (button, val_in_conf);
176 static void
177 bool_pref_create_widget (GOConfNode *node, GtkWidget *grid,
178 gint row, gboolean_conf_setter_t setter,
179 gboolean_conf_getter_t getter,
180 char const *default_label)
182 const char *desc = gnm_conf_get_short_desc (node);
183 GtkWidget *item = gtk_check_button_new_with_label (
184 (desc != NULL) ? desc : default_label);
186 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), getter ());
188 g_object_set_data (G_OBJECT (item), "getter", getter);
189 g_signal_connect (G_OBJECT (item), "toggled",
190 G_CALLBACK (bool_pref_widget_to_conf),
191 (gpointer) setter);
192 gtk_grid_attach (GTK_GRID (grid), item, 0, row, 2, 1);
194 connect_notification (node, (GOConfMonitorFunc)bool_pref_conf_to_widget,
195 item, grid);
196 set_tip (node, item);
199 /*************************************************************************/
201 static void
202 cb_enum_changed (GtkComboBox *combo, enum_conf_setter_t setter)
204 GtkTreeIter iter;
205 if (gtk_combo_box_get_active_iter (combo, &iter)) {
206 GtkTreeModel *model = gtk_combo_box_get_model (combo);
207 GEnumValue *enum_val;
208 gtk_tree_model_get (model, &iter, 1, &enum_val, -1);
209 (*setter) (enum_val->value);
213 typedef struct {
214 char *val;
215 GtkComboBox *combo;
216 } FindEnumClosure;
218 static gboolean
219 cb_find_enum (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
220 FindEnumClosure *cls)
222 gboolean res = FALSE;
223 char *combo_val;
225 g_return_val_if_fail (model != NULL, FALSE);
226 g_return_val_if_fail (cls->val != NULL, FALSE);
228 gtk_tree_model_get (model, iter, 0, &combo_val, -1);
229 if (combo_val) {
230 if (0 == strcmp (cls->val, combo_val)) {
231 res = TRUE;
232 gtk_combo_box_set_active_iter (cls->combo, iter);
234 g_free (combo_val);
236 return res;
239 static void
240 enum_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
241 GtkComboBox *combo)
243 FindEnumClosure cls;
244 GtkTreeModel *model = gtk_combo_box_get_model (combo);
246 cls.combo = combo;
247 /* We can't use the getter here since the main preferences */
248 /* may be notified after us */
249 cls.val = go_conf_get_enum_as_str (node, NULL);
250 if (NULL != cls.val) { /* in case go_conf fails */
251 gtk_tree_model_foreach (model,
252 (GtkTreeModelForeachFunc)cb_find_enum,
253 &cls);
254 g_free (cls.val);
258 static void
259 enum_pref_create_widget (GOConfNode *node, GtkWidget *grid,
260 gint row, GType enum_type,
261 enum_conf_setter_t setter,
262 enum_conf_getter_t getter,
263 gchar const *default_label,
264 char const *(*label_getter)(int))
266 unsigned int i;
267 GtkTreeIter iter;
268 GtkCellRenderer *renderer;
269 GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (enum_type));
270 GtkWidget *combo = gtk_combo_box_new ();
271 GtkListStore *model = gtk_list_store_new (2,
272 G_TYPE_STRING, G_TYPE_POINTER);
273 gint current = getter ();
274 gint current_index = -1;
276 for (i = 0; i < enum_class->n_values ; i++) {
277 gtk_list_store_append (model, &iter);
278 gtk_list_store_set (model, &iter,
279 0, label_getter ((int) enum_class->values[i].value),
280 1, enum_class->values + i,
281 -1);
282 if (enum_class->values[i].value == current)
283 current_index = i;
286 g_type_class_unref (enum_class);
288 gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (model));
289 g_object_unref (model);
290 renderer = gtk_cell_renderer_text_new ();
291 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
292 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, "text", 0, NULL);
294 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), current_index);
296 gtk_grid_attach (GTK_GRID (grid), combo, 1, row, 1, 1);
298 g_signal_connect (G_OBJECT (combo), "changed",
299 G_CALLBACK (cb_enum_changed), (gpointer) setter);
300 connect_notification (node, (GOConfMonitorFunc)enum_pref_conf_to_widget,
301 combo, grid);
303 pref_create_label (node, grid, row, default_label, combo);
304 set_tip (node, combo);
307 /*************************************************************************/
309 static void
310 int_pref_widget_to_conf (GtkSpinButton *button, gint_conf_setter_t setter)
312 gint_conf_getter_t getter
313 = g_object_get_data (G_OBJECT (button), "getter");
314 gint val_in_button = gtk_spin_button_get_value_as_int (button);
315 gint val_in_conf = getter ();
317 if (val_in_conf != val_in_button)
318 setter (val_in_button);
321 static void
322 int_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
323 GtkSpinButton *button)
325 gint val_in_button = gtk_spin_button_get_value_as_int (button);
327 /* We can't use the getter here since the main preferences */
328 /* may be notified after us */
329 gint val_in_conf = go_conf_get_int (node, NULL);
331 if (val_in_conf != val_in_button)
332 gtk_spin_button_set_value (button, (gdouble) val_in_conf);
335 static GtkWidget *
336 int_pref_create_widget (GOConfNode *node, GtkWidget *grid,
337 gint row, gint val, gint from, gint to, gint step,
338 gint_conf_setter_t setter, gint_conf_getter_t getter,
339 char const *default_label)
341 GtkAdjustment *adj = GTK_ADJUSTMENT
342 (gtk_adjustment_new (val, from, to, step, step, 0));
343 GtkWidget *w = gtk_spin_button_new (adj, 1, 0);
345 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), (gdouble) getter ());
347 g_object_set_data (G_OBJECT (w), "node", node);
348 gtk_widget_set_hexpand (w, TRUE);
349 gtk_grid_attach (GTK_GRID (grid), w, 1, row, 1, 1);
351 g_object_set_data (G_OBJECT (w), "getter", getter);
352 g_signal_connect (G_OBJECT (w), "value-changed",
353 G_CALLBACK (int_pref_widget_to_conf),
354 (gpointer) setter);
355 connect_notification (node, (GOConfMonitorFunc)int_pref_conf_to_widget,
356 w, grid);
358 pref_create_label (node, grid, row, default_label, w);
359 set_tip (node, w);
360 return w;
363 static gboolean
364 powerof_2 (int i)
366 return i > 0 && (i & (i - 1)) == 0;
369 static void
370 cb_power_of_2 (GtkAdjustment *adj)
372 int val = (int)gtk_adjustment_get_value (adj);
374 if (powerof_2 (val - 1))
375 gtk_adjustment_set_value (adj, (val - 1) * 2);
376 else if (powerof_2 (val + 1))
377 gtk_adjustment_set_value (adj, (val + 1) / 2);
380 static void
381 power_of_2_handlers (GtkWidget *w)
383 GtkSpinButton *spin = GTK_SPIN_BUTTON (w);
384 GtkAdjustment *adj = gtk_spin_button_get_adjustment (spin);
385 g_signal_connect (G_OBJECT (adj), "value_changed",
386 G_CALLBACK (cb_power_of_2), NULL);
389 /*************************************************************************/
391 static void
392 double_pref_widget_to_conf (GtkSpinButton *button, double_conf_setter_t setter)
394 double_conf_getter_t getter
395 = g_object_get_data (G_OBJECT (button), "getter");
396 double val_in_button = gtk_spin_button_get_value (button);
397 double val_in_conf = getter();
399 if (fabs (val_in_conf - val_in_button) > 1e-10) /* dead simple */
400 setter (val_in_button);
403 static void
404 double_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
405 GtkSpinButton *button)
407 double val_in_button = gtk_spin_button_get_value (button);
409 /* We can't use the getter here since the main preferences */
410 /* may be notified after us */
411 double val_in_conf = go_conf_get_double (node, NULL);
413 if (fabs (val_in_conf - val_in_button) > 1e-10) /* dead simple */
414 gtk_spin_button_set_value (button, val_in_conf);
416 static void
417 double_pref_create_widget (GOConfNode *node, GtkWidget *grid,
418 gint row, gnm_float val, gnm_float from, gnm_float to,
419 gnm_float step, gint digits,
420 double_conf_setter_t setter,
421 double_conf_getter_t getter,
422 char const *default_label)
424 GtkWidget *w = gtk_spin_button_new (GTK_ADJUSTMENT (
425 gtk_adjustment_new (val, from, to, step, step, 0)),
426 1, digits);
427 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), getter ());
428 g_object_set_data (G_OBJECT (w), "node", node);
429 gtk_widget_set_hexpand (w, TRUE);
430 gtk_grid_attach (GTK_GRID (grid), w, 1, row, 1, 1);
432 g_object_set_data (G_OBJECT (w), "getter", getter);
433 g_signal_connect (G_OBJECT (w), "value-changed",
434 G_CALLBACK (double_pref_widget_to_conf), (gpointer) setter);
435 connect_notification (node,
436 (GOConfMonitorFunc)double_pref_conf_to_widget,
437 w, grid);
439 pref_create_label (node, grid, row, default_label, w);
440 set_tip (node, w);
444 /*************************************************************************/
448 static void
449 wordlist_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
450 GtkListStore *store)
452 /* We can't use the getter here since the main preferences */
453 /* may be notified after us */
454 GSList *l, *list = go_conf_get_str_list (node, NULL);
455 GtkTreeIter iter;
457 gtk_list_store_clear (store);
459 for (l = list; l != NULL; l = l->next) {
460 gtk_list_store_append (store, &iter);
461 gtk_list_store_set (store, &iter,
462 0, l->data,
463 -1);
464 g_free (l->data);
466 g_slist_free (list);
469 static void
470 wordlist_pref_remove (GtkButton *button, wordlist_conf_setter_t setter) {
471 GtkTreeView *tree = g_object_get_data (G_OBJECT (button), "treeview");
472 GtkTreeSelection *select = gtk_tree_view_get_selection (tree);
473 GtkTreeIter iter;
474 GtkTreeModel *model;
476 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
477 char *text;
478 wordlist_conf_getter_t getter = g_object_get_data (G_OBJECT (button), "getter");
479 GSList *l, *list = getter ();
481 list = go_string_slist_copy (list);
483 gtk_tree_model_get (model, &iter,
484 0, &text,
485 -1);
486 l = g_slist_find_custom (list, text, (GCompareFunc)strcmp);
487 if (l != NULL) {
488 g_free (l->data);
489 list = g_slist_delete_link (list, l);
490 setter (list);
492 g_slist_free_full (list, g_free);
493 g_free (text);
497 static void
498 wordlist_pref_add (GtkButton *button, wordlist_conf_setter_t setter)
500 GtkEntry *entry = g_object_get_data (G_OBJECT (button), "entry");
501 const gchar *text = gtk_entry_get_text (entry);
503 if (text[0]) {
504 wordlist_conf_getter_t getter = g_object_get_data (G_OBJECT (button), "getter");
505 GSList *l, *list = getter ();
506 l = g_slist_find_custom (list, text, (GCompareFunc)strcmp);
507 if (l == NULL) {
508 list = go_string_slist_copy (list);
509 list = g_slist_append (list, g_strdup (text));
510 setter (list);
511 g_slist_free_full (list, g_free);
516 static void
517 wordlist_pref_update_remove_button (GtkTreeSelection *selection, GtkButton *button)
519 gtk_widget_set_sensitive (GTK_WIDGET (button),
520 gtk_tree_selection_get_selected (selection, NULL, NULL));
523 static GtkWidget *
524 wordlist_pref_create_widget (GOConfNode *node, GtkWidget *grid,
525 gint row, wordlist_conf_setter_t setter,
526 wordlist_conf_getter_t getter,
527 char const *default_label)
529 GtkWidget *w = gtk_grid_new ();
530 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
531 GtkWidget *tv = gtk_tree_view_new ();
532 GtkWidget *entry = gtk_entry_new ();
533 GtkWidget *add_button = gtk_button_new_from_stock (GTK_STOCK_ADD);
534 GtkWidget *remove_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
535 GtkListStore *model = gtk_list_store_new (1, G_TYPE_STRING);
536 GtkTreeSelection *selection;
538 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
539 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
540 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
541 GTK_SHADOW_ETCHED_IN);
542 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), FALSE);
543 gtk_container_add (GTK_CONTAINER (sw), tv);
545 g_object_set (w, "column-spacing", 12, "row-spacing", 6,
546 "hexpand", TRUE, "vexpand", TRUE, NULL);
547 gtk_grid_attach (GTK_GRID (grid), w, 0, row, 2, 1);
548 g_object_set (sw, "hexpand", TRUE, "vexpand", TRUE, NULL);
549 gtk_grid_attach (GTK_GRID (w), sw, 0, 1, 1, 3);
550 gtk_widget_set_hexpand (entry, TRUE);
551 gtk_grid_attach (GTK_GRID (w), entry, 0, 4, 1, 1);
552 gtk_widget_set_valign (remove_button, GTK_ALIGN_END);
553 gtk_grid_attach (GTK_GRID (w), remove_button, 1, 3, 1, 1);
554 gtk_grid_attach (GTK_GRID (w), add_button, 1, 4, 1, 1);
556 gtk_tree_view_set_model (GTK_TREE_VIEW (tv),
557 GTK_TREE_MODEL (model));
558 g_object_unref (model);
559 gtk_tree_view_append_column (GTK_TREE_VIEW (tv),
560 gtk_tree_view_column_new_with_attributes
561 (NULL,
562 gtk_cell_renderer_text_new (),
563 "text", 0,
564 NULL));
565 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
566 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
567 wordlist_pref_conf_to_widget (node, "", model);
569 g_object_set_data (G_OBJECT (remove_button), "treeview", tv);
570 g_object_set_data (G_OBJECT (add_button), "entry", entry);
571 g_object_set_data (G_OBJECT (remove_button), "getter", getter);
572 g_object_set_data (G_OBJECT (add_button), "getter", getter);
573 g_signal_connect (G_OBJECT (remove_button), "clicked",
574 G_CALLBACK (wordlist_pref_remove), setter);
575 g_signal_connect (G_OBJECT (add_button), "clicked",
576 G_CALLBACK (wordlist_pref_add), setter);
577 g_signal_connect (G_OBJECT (selection), "changed",
578 G_CALLBACK (wordlist_pref_update_remove_button), remove_button);
579 wordlist_pref_update_remove_button (selection,
580 GTK_BUTTON (remove_button));
582 connect_notification (node, (GOConfMonitorFunc)wordlist_pref_conf_to_widget,
583 model, grid);
585 pref_create_label (node, w, 0, default_label, tv);
586 set_tip (node, tv);
587 return w;
590 /*******************************************************************************************/
591 /* Default Font Selector */
592 /*******************************************************************************************/
594 static void
595 do_set_font (GOFontSel *fs,
596 const char *name, double size,
597 gboolean is_bold, gboolean is_italic)
599 PangoFontDescription *desc;
601 desc = pango_font_description_new ();
602 pango_font_description_set_family (desc, name);
603 pango_font_description_set_size (desc, PANGO_SCALE * size);
604 pango_font_description_set_weight
605 (desc,
606 is_bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
607 pango_font_description_set_style
608 (desc,
609 is_italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
611 go_font_sel_set_font_desc (fs, desc);
612 pango_font_description_free (desc);
616 static void
617 cb_pref_font_set_fonts (G_GNUC_UNUSED GOConfNode *node,
618 G_GNUC_UNUSED char const *key,
619 GtkWidget *page)
621 GOFontSel *fs = GO_FONT_SEL (page);
623 do_set_font (fs,
624 gnm_conf_get_core_defaultfont_name (),
625 gnm_conf_get_core_defaultfont_size (),
626 gnm_conf_get_core_defaultfont_bold (),
627 gnm_conf_get_core_defaultfont_italic ());
630 static gboolean
631 cb_pref_font_has_changed (GOFontSel *fs, G_GNUC_UNUSED PangoAttrList *attrs,
632 PrefState *state)
634 PangoFontDescription *desc = go_font_sel_get_font_desc (fs);
635 PangoFontMask fields = pango_font_description_get_set_fields (desc);
637 if (fields & PANGO_FONT_MASK_FAMILY)
638 gnm_conf_set_core_defaultfont_name
639 (pango_font_description_get_family (desc));
640 if (fields & PANGO_FONT_MASK_SIZE)
641 gnm_conf_set_core_defaultfont_size
642 (pango_font_description_get_size (desc) / (double)PANGO_SCALE);
643 if (fields & PANGO_FONT_MASK_WEIGHT)
644 gnm_conf_set_core_defaultfont_bold
645 (pango_font_description_get_weight (desc) >= PANGO_WEIGHT_BOLD);
646 if (fields & PANGO_FONT_MASK_STYLE)
647 gnm_conf_set_core_defaultfont_italic
648 (pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL);
650 pango_font_description_free (desc);
652 return TRUE;
655 static GtkWidget *
656 pref_font_initializer (PrefState *state,
657 G_GNUC_UNUSED gpointer data,
658 G_GNUC_UNUSED GtkNotebook *notebook,
659 G_GNUC_UNUSED gint page_num)
661 GtkWidget *page = g_object_new (GO_TYPE_FONT_SEL,
662 "show-style", TRUE,
663 NULL);
665 cb_pref_font_set_fonts (NULL, NULL, page);
667 connect_notification (gnm_conf_get_core_defaultfont_dir_node (),
668 (GOConfMonitorFunc) cb_pref_font_set_fonts,
669 page, page);
670 g_signal_connect (G_OBJECT (page),
671 "font_changed",
672 G_CALLBACK (cb_pref_font_has_changed), state);
674 gtk_widget_show_all (page);
676 return page;
679 /*******************************************************************************************/
680 /* Default Header/Footer Font Selector */
681 /*******************************************************************************************/
683 static void
684 cb_pref_font_hf_set_fonts (G_GNUC_UNUSED GOConfNode *node,
685 G_GNUC_UNUSED char const *key,
686 GtkWidget *page)
688 GOFontSel *fs = GO_FONT_SEL (page);
689 do_set_font (fs,
690 gnm_conf_get_printsetup_hf_font_name (),
691 gnm_conf_get_printsetup_hf_font_size (),
692 gnm_conf_get_printsetup_hf_font_bold (),
693 gnm_conf_get_printsetup_hf_font_italic ());
696 static gboolean
697 cb_pref_font_hf_has_changed (GOFontSel *fs, G_GNUC_UNUSED PangoAttrList *attrs,
698 PrefState *state)
700 PangoFontDescription *desc = go_font_sel_get_font_desc (fs);
701 PangoFontMask fields = pango_font_description_get_set_fields (desc);
703 if (fields & PANGO_FONT_MASK_FAMILY)
704 gnm_conf_set_printsetup_hf_font_name
705 (pango_font_description_get_family (desc));
706 if (fields & PANGO_FONT_MASK_SIZE)
707 gnm_conf_set_printsetup_hf_font_size
708 (pango_font_description_get_size (desc) / (double)PANGO_SCALE);
709 if (fields & PANGO_FONT_MASK_WEIGHT)
710 gnm_conf_set_printsetup_hf_font_bold
711 (pango_font_description_get_weight (desc) >= PANGO_WEIGHT_BOLD);
712 if (fields & PANGO_FONT_MASK_STYLE)
713 gnm_conf_set_printsetup_hf_font_italic
714 (pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL);
716 pango_font_description_free (desc);
718 return TRUE;
721 static GtkWidget *
722 pref_font_hf_initializer (PrefState *state,
723 G_GNUC_UNUSED gpointer data,
724 G_GNUC_UNUSED GtkNotebook *notebook,
725 G_GNUC_UNUSED gint page_num)
727 GtkWidget *page = g_object_new (GO_TYPE_FONT_SEL,
728 "show-style", TRUE,
729 NULL);
731 cb_pref_font_hf_set_fonts (NULL, NULL, page);
732 connect_notification (gnm_conf_get_printsetup_dir_node (),
733 (GOConfMonitorFunc) cb_pref_font_hf_set_fonts,
734 page, page);
735 g_signal_connect (G_OBJECT (page),
736 "font_changed",
737 G_CALLBACK (cb_pref_font_hf_has_changed), state);
739 gtk_widget_show_all (page);
741 return page;
744 /*******************************************************************************************/
745 /* Undo Preferences Page */
746 /*******************************************************************************************/
748 static GtkWidget *
749 pref_undo_page_initializer (PrefState *state,
750 G_GNUC_UNUSED gpointer data,
751 G_GNUC_UNUSED GtkNotebook *notebook,
752 G_GNUC_UNUSED gint page_num)
754 GtkWidget *page = gtk_grid_new ();
755 gint row = 0;
757 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
758 "vexpand", TRUE, NULL);
759 int_pref_create_widget (gnm_conf_get_undo_max_descriptor_width_node (),
760 page, row++, 5, 5, 200, 1,
761 gnm_conf_set_undo_max_descriptor_width,
762 gnm_conf_get_undo_max_descriptor_width,
763 _("Length of Undo Descriptors"));
764 int_pref_create_widget (gnm_conf_get_undo_size_node (),
765 page, row++, 1000, 0, 30000, 100,
766 gnm_conf_set_undo_size,
767 gnm_conf_get_undo_size,
768 _("Maximal Undo Size"));
769 int_pref_create_widget (gnm_conf_get_undo_maxnum_node (),
770 page, row++, 20, 1, 200, 1,
771 gnm_conf_set_undo_maxnum,
772 gnm_conf_get_undo_maxnum,
773 _("Number of Undo Items"));
774 bool_pref_create_widget (gnm_conf_get_undo_show_sheet_name_node (),
775 page, row++,
776 gnm_conf_set_undo_show_sheet_name,
777 gnm_conf_get_undo_show_sheet_name,
778 _("Show Sheet Name in Undo List"));
780 gtk_widget_show_all (page);
781 return page;
784 /*******************************************************************************************/
785 /* Sort Preferences Page */
786 /*******************************************************************************************/
788 static GtkWidget *
789 pref_sort_page_initializer (PrefState *state,
790 G_GNUC_UNUSED gpointer data,
791 G_GNUC_UNUSED GtkNotebook *notebook,
792 G_GNUC_UNUSED gint page_num)
794 GtkWidget *page = gtk_grid_new ();
795 gint row = 0;
797 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
798 "vexpand", TRUE, NULL);
799 int_pref_create_widget (gnm_conf_get_core_sort_dialog_max_initial_clauses_node (),
800 page, row++, 10, 0, 50, 1,
801 gnm_conf_set_core_sort_dialog_max_initial_clauses,
802 gnm_conf_get_core_sort_dialog_max_initial_clauses,
803 _("Number of Automatic Clauses"));
804 bool_pref_create_widget (gnm_conf_get_core_sort_default_retain_formats_node (),
805 page, row++,
806 gnm_conf_set_core_sort_default_retain_formats,
807 gnm_conf_get_core_sort_default_retain_formats,
808 _("Sorting Preserves Formats"));
809 bool_pref_create_widget (gnm_conf_get_core_sort_default_by_case_node (),
810 page, row++,
811 gnm_conf_set_core_sort_default_by_case,
812 gnm_conf_get_core_sort_default_by_case,
813 _("Sorting is Case-Sensitive"));
814 bool_pref_create_widget (gnm_conf_get_core_sort_default_ascending_node (),
815 page, row++,
816 gnm_conf_set_core_sort_default_ascending,
817 gnm_conf_get_core_sort_default_ascending,
818 _("Sort Ascending"));
820 gtk_widget_show_all (page);
821 return page;
824 /*******************************************************************************************/
825 /* Window Preferences Page */
826 /*******************************************************************************************/
828 static GtkWidget *
829 pref_window_page_initializer (PrefState *state,
830 G_GNUC_UNUSED gpointer data,
831 G_GNUC_UNUSED GtkNotebook *notebook,
832 G_GNUC_UNUSED gint page_num)
834 GtkWidget *page = gtk_grid_new ();
835 gint row = 0;
836 GtkWidget *w;
838 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
839 "vexpand", TRUE, NULL);
840 double_pref_create_widget (gnm_conf_get_core_gui_window_y_node (),
841 page, row++, 0.75, 0.25, 1, 0.05, 2,
842 gnm_conf_set_core_gui_window_y,
843 gnm_conf_get_core_gui_window_y,
844 _("Default Vertical Window Size"));
845 double_pref_create_widget (gnm_conf_get_core_gui_window_x_node (),
846 page, row++, 0.75, 0.25, 1, 0.05, 2,
847 gnm_conf_set_core_gui_window_x,
848 gnm_conf_get_core_gui_window_x,
849 _("Default Horizontal Window Size"));
850 double_pref_create_widget (gnm_conf_get_core_gui_window_zoom_node (),
851 page, row++, 1.00, 0.10, 5.00, 0.05, 2,
852 gnm_conf_set_core_gui_window_zoom,
853 gnm_conf_get_core_gui_window_zoom,
854 _("Default Zoom Factor"));
855 int_pref_create_widget (gnm_conf_get_core_workbook_n_sheet_node (),
856 page, row++, 1, 1, 64, 1,
857 gnm_conf_set_core_workbook_n_sheet,
858 gnm_conf_get_core_workbook_n_sheet,
859 _("Default Number of Sheets"));
861 w = int_pref_create_widget (gnm_conf_get_core_workbook_n_rows_node (),
862 page, row++,
863 GNM_DEFAULT_ROWS, GNM_MIN_ROWS, GNM_MAX_ROWS, 1,
864 gnm_conf_set_core_workbook_n_rows,
865 gnm_conf_get_core_workbook_n_rows,
866 _("Default Number of Rows in a Sheet"));
867 power_of_2_handlers (w);
869 w = int_pref_create_widget (gnm_conf_get_core_workbook_n_cols_node (),
870 page, row++,
871 GNM_DEFAULT_COLS, GNM_MIN_COLS, GNM_MAX_COLS, 1,
872 gnm_conf_set_core_workbook_n_cols,
873 gnm_conf_get_core_workbook_n_cols,
874 _("Default Number of Columns in a Sheet"));
875 power_of_2_handlers (w);
877 bool_pref_create_widget (gnm_conf_get_core_gui_cells_function_markers_node (),
878 page, row++,
879 gnm_conf_set_core_gui_cells_function_markers,
880 gnm_conf_get_core_gui_cells_function_markers,
881 _("By default, mark cells with spreadsheet functions"));
882 bool_pref_create_widget (gnm_conf_get_core_gui_cells_extension_markers_node (),
883 page, row++,
884 gnm_conf_set_core_gui_cells_extension_markers,
885 gnm_conf_get_core_gui_cells_extension_markers,
886 _("By default, mark cells with truncated content"));
888 gtk_widget_show_all (page);
889 return page;
892 /*******************************************************************************************/
893 /* File/XML Preferences Page */
894 /*******************************************************************************************/
896 static void
897 gnm_conf_set_core_file_save_extension_check_disabled_wrap (gboolean val)
899 GSList *list = NULL;
901 if (val)
902 list = g_slist_prepend (NULL, (char *)"Gnumeric_stf:stf_assistant");
903 gnm_conf_set_core_file_save_extension_check_disabled (list);
904 g_slist_free (list);
906 static gboolean
907 gnm_conf_get_core_file_save_extension_check_disabled_wrap (void)
909 GSList *list = gnm_conf_get_core_file_save_extension_check_disabled ();
910 return (NULL != g_slist_find_custom (list, "Gnumeric_stf:stf_assistant", go_str_compare));
913 static void
914 custom_pref_conf_to_widget_ecd (GOConfNode *node, G_GNUC_UNUSED char const *key,
915 GtkToggleButton *button)
917 gboolean val_in_button = gtk_toggle_button_get_active (button);
919 /* We can't use the getter here since the main preferences */
920 /* may be notified after us */
921 GSList *list = go_conf_get_str_list (node, NULL);
922 gboolean val_in_conf
923 = (NULL != g_slist_find_custom (list, "Gnumeric_stf:stf_assistant", go_str_compare));
925 if ((!val_in_button) != (!val_in_conf))
926 gtk_toggle_button_set_active (button, val_in_conf);
928 static void
929 custom_pref_create_widget_ecd (GOConfNode *node, GtkWidget *grid,
930 gint row, gboolean_conf_setter_t setter,
931 gboolean_conf_getter_t getter,
932 char const *default_label)
934 GtkWidget *item = gtk_check_button_new_with_label (default_label);
936 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), getter ());
938 g_object_set_data (G_OBJECT (item), "getter", getter);
939 g_signal_connect (G_OBJECT (item), "toggled",
940 G_CALLBACK (bool_pref_widget_to_conf),
941 (gpointer) setter);
942 gtk_grid_attach (GTK_GRID (grid), item, 0, row, 2, 1);
944 connect_notification (node, (GOConfMonitorFunc)custom_pref_conf_to_widget_ecd,
945 item, grid);
951 static GtkWidget *
952 pref_file_page_initializer (PrefState *state,
953 G_GNUC_UNUSED gpointer data,
954 G_GNUC_UNUSED GtkNotebook *notebook,
955 G_GNUC_UNUSED gint page_num)
957 GtkWidget *page = gtk_grid_new ();
958 gint row = 0;
960 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
961 "vexpand", TRUE, NULL);
962 int_pref_create_widget (gnm_conf_get_core_xml_compression_level_node (),
963 page, row++, 9, 0, 9, 1,
964 gnm_conf_set_core_xml_compression_level,
965 gnm_conf_get_core_xml_compression_level,
966 _("Default Compression Level For "
967 "Gnumeric Files"));
968 int_pref_create_widget (gnm_conf_get_core_workbook_autosave_time_node (),
969 page, row++, 0, 0, 365*24*60*60, 60,
970 gnm_conf_set_core_workbook_autosave_time,
971 gnm_conf_get_core_workbook_autosave_time,
972 _("Default autosave frequency in seconds"));
973 bool_pref_create_widget (gnm_conf_get_core_file_save_def_overwrite_node (),
974 page, row++,
975 gnm_conf_set_core_file_save_def_overwrite,
976 gnm_conf_get_core_file_save_def_overwrite,
977 _("Default To Overwriting Files"));
978 bool_pref_create_widget (gnm_conf_get_core_file_save_single_sheet_node (),
979 page, row++,
980 gnm_conf_set_core_file_save_single_sheet,
981 gnm_conf_get_core_file_save_single_sheet,
982 _("Warn When Exporting Into Single "
983 "Sheet Format"));
984 bool_pref_create_widget (gnm_conf_get_plugin_latex_use_utf8_node (),
985 page, row++,
986 gnm_conf_set_plugin_latex_use_utf8,
987 gnm_conf_get_plugin_latex_use_utf8,
988 _("Use UTF-8 in LaTeX Export"));
989 custom_pref_create_widget_ecd ( gnm_conf_get_core_file_save_extension_check_disabled_node (),
990 page, row++,
991 gnm_conf_set_core_file_save_extension_check_disabled_wrap,
992 gnm_conf_get_core_file_save_extension_check_disabled_wrap,
993 _("Disable Extension Check for Configurable Text Exporter"));
995 gtk_widget_show_all (page);
996 return page;
999 /*******************************************************************************************/
1000 /* Screen Preferences Page */
1001 /*******************************************************************************************/
1003 static GtkWidget *
1004 pref_screen_page_initializer (PrefState *state,
1005 G_GNUC_UNUSED gpointer data,
1006 G_GNUC_UNUSED GtkNotebook *notebook,
1007 G_GNUC_UNUSED gint page_num)
1009 GtkWidget *page = gtk_grid_new ();
1010 gint row = 0;
1012 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1013 "vexpand", TRUE, NULL);
1014 double_pref_create_widget (gnm_conf_get_core_gui_screen_horizontaldpi_node (),
1015 page, row++, 96, 50, 250, 1, 1,
1016 gnm_conf_set_core_gui_screen_horizontaldpi,
1017 gnm_conf_get_core_gui_screen_horizontaldpi,
1018 _("Horizontal DPI"));
1019 double_pref_create_widget (gnm_conf_get_core_gui_screen_verticaldpi_node (),
1020 page, row++, 96, 50, 250, 1, 1,
1021 gnm_conf_set_core_gui_screen_verticaldpi,
1022 gnm_conf_get_core_gui_screen_verticaldpi,
1023 _("Vertical DPI"));
1025 gtk_widget_show_all (page);
1026 return page;
1029 /*******************************************************************************************/
1030 /* Tool Preferences Page */
1031 /*******************************************************************************************/
1033 static GtkWidget *
1034 pref_tool_page_initializer (PrefState *state,
1035 G_GNUC_UNUSED gpointer data,
1036 G_GNUC_UNUSED GtkNotebook *notebook,
1037 G_GNUC_UNUSED gint page_num)
1039 GtkWidget *page = gtk_grid_new ();
1040 gint row = 0;
1042 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1043 "vexpand", TRUE, NULL);
1044 enum_pref_create_widget (gnm_conf_get_core_gui_editing_enter_moves_dir_node (),
1045 page, row++,
1046 GO_TYPE_DIRECTION,
1047 (enum_conf_setter_t)gnm_conf_set_core_gui_editing_enter_moves_dir,
1048 (enum_conf_getter_t)gnm_conf_get_core_gui_editing_enter_moves_dir,
1049 _("Enter _Moves Selection"), (char const *(*) (int)) go_direction_get_name);
1050 bool_pref_create_widget (gnm_conf_get_core_gui_editing_transitionkeys_node (),
1051 page, row++,
1052 gnm_conf_set_core_gui_editing_transitionkeys,
1053 gnm_conf_get_core_gui_editing_transitionkeys,
1054 _("Transition Keys"));
1055 bool_pref_create_widget (gnm_conf_get_core_gui_editing_autocomplete_node (),
1056 page, row++,
1057 gnm_conf_set_core_gui_editing_autocomplete,
1058 gnm_conf_get_core_gui_editing_autocomplete,
1059 _("Autocomplete"));
1060 int_pref_create_widget (gnm_conf_get_core_gui_editing_autocomplete_min_chars_node (),
1061 page, row++, 3, 1, 10, 1,
1062 gnm_conf_set_core_gui_editing_autocomplete_min_chars,
1063 gnm_conf_get_core_gui_editing_autocomplete_min_chars,
1064 _("Minimum Number of Characters for Autocompletion"));
1065 bool_pref_create_widget (gnm_conf_get_core_gui_editing_function_name_tooltips_node (),
1066 page, row++,
1067 gnm_conf_set_core_gui_editing_function_name_tooltips,
1068 gnm_conf_get_core_gui_editing_function_name_tooltips,
1069 _("Show Function Name Tooltips"));
1070 bool_pref_create_widget (gnm_conf_get_core_gui_editing_function_argument_tooltips_node (),
1071 page, row++,
1072 gnm_conf_set_core_gui_editing_function_argument_tooltips,
1073 gnm_conf_get_core_gui_editing_function_argument_tooltips,
1074 _("Show Function Argument Tooltips"));
1075 bool_pref_create_widget (gnm_conf_get_dialogs_rs_unfocused_node (),
1076 page, row++,
1077 gnm_conf_set_dialogs_rs_unfocused,
1078 gnm_conf_get_dialogs_rs_unfocused,
1079 _("Allow Unfocused Range Selections"));
1080 int_pref_create_widget (gnm_conf_get_functionselector_num_of_recent_node (),
1081 page, row++, 10, 0, 40, 1,
1082 gnm_conf_set_functionselector_num_of_recent,
1083 gnm_conf_get_functionselector_num_of_recent,
1084 _("Maximum Length of Recently "
1085 "Used Functions List"));
1087 gtk_widget_show_all (page);
1088 return page;
1091 /*******************************************************************************************/
1092 /* Copy/Paste Preferences Page */
1093 /*******************************************************************************************/
1095 #ifndef G_OS_WIN32
1097 static GtkWidget *
1098 pref_copypaste_page_initializer (PrefState *state,
1099 G_GNUC_UNUSED gpointer data,
1100 G_GNUC_UNUSED GtkNotebook *notebook,
1101 G_GNUC_UNUSED gint page_num)
1103 GtkWidget *page = gtk_grid_new ();
1104 gint row = 0;
1106 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1107 "vexpand", TRUE, NULL);
1108 bool_pref_create_widget (gnm_conf_get_cut_and_paste_prefer_clipboard_node (),
1109 page, row++,
1110 gnm_conf_set_cut_and_paste_prefer_clipboard,
1111 gnm_conf_get_cut_and_paste_prefer_clipboard,
1112 /* xgettext : see https://en.wikipedia.org/wiki/X_Window_selection#Clipboard */
1113 _("Prefer CLIPBOARD Over PRIMARY Selection"));
1115 gtk_widget_show_all (page);
1116 return page;
1119 #endif
1121 /*******************************************************************************************/
1122 /* AutoCorrect Preferences Page (General) */
1123 /*******************************************************************************************/
1125 static GtkWidget *
1126 pref_autocorrect_general_page_initializer (PrefState *state,
1127 G_GNUC_UNUSED gpointer data,
1128 G_GNUC_UNUSED GtkNotebook *notebook,
1129 G_GNUC_UNUSED gint page_num)
1131 GtkWidget *page = gtk_grid_new ();
1132 gint row = 0;
1134 bool_pref_create_widget (gnm_conf_get_autocorrect_names_of_days_node (),
1135 page, row++,
1136 gnm_conf_set_autocorrect_names_of_days,
1137 gnm_conf_get_autocorrect_names_of_days,
1138 _("Capitalize _names of days"));
1140 gtk_widget_show_all (page);
1141 return page;
1144 /*******************************************************************************************/
1145 /* AutoCorrect Preferences Page (InitialCaps) */
1146 /*******************************************************************************************/
1148 static GtkWidget *
1149 pref_autocorrect_initialcaps_page_initializer (PrefState *state,
1150 G_GNUC_UNUSED gpointer data,
1151 G_GNUC_UNUSED GtkNotebook *notebook,
1152 G_GNUC_UNUSED gint page_num)
1154 GtkWidget *page = gtk_grid_new ();
1155 gint row = 0;
1157 bool_pref_create_widget (gnm_conf_get_autocorrect_init_caps_node (),
1158 page, row++,
1159 gnm_conf_set_autocorrect_init_caps,
1160 gnm_conf_get_autocorrect_init_caps,
1161 _("Correct _TWo INitial CApitals"));
1162 wordlist_pref_create_widget (gnm_conf_get_autocorrect_init_caps_list_node (), page,
1163 row++, gnm_conf_set_autocorrect_init_caps_list,
1164 gnm_conf_get_autocorrect_init_caps_list,
1165 _("Do _not correct:"));
1167 gtk_widget_show_all (page);
1168 return page;
1171 /*******************************************************************************************/
1172 /* AutoCorrect Preferences Page (FirstLetter) */
1173 /*******************************************************************************************/
1175 static GtkWidget *
1176 pref_autocorrect_firstletter_page_initializer (PrefState *state,
1177 G_GNUC_UNUSED gpointer data,
1178 G_GNUC_UNUSED GtkNotebook *notebook,
1179 G_GNUC_UNUSED gint page_num)
1181 GtkWidget *page = gtk_grid_new ();
1182 gint row = 0;
1184 bool_pref_create_widget (gnm_conf_get_autocorrect_first_letter_node (),
1185 page, row++,
1186 gnm_conf_set_autocorrect_first_letter,
1187 gnm_conf_get_autocorrect_first_letter,
1188 _("Capitalize _first letter of sentence"));
1189 wordlist_pref_create_widget (gnm_conf_get_autocorrect_first_letter_list_node (), page,
1190 row++, gnm_conf_set_autocorrect_first_letter_list,
1191 gnm_conf_get_autocorrect_first_letter_list,
1192 _("Do _not capitalize after:"));
1194 gtk_widget_show_all (page);
1195 return page;
1200 /*******************************************************************************************/
1201 /* General Preference Dialog Routines */
1202 /*******************************************************************************************/
1204 typedef struct {
1205 char const *page_name;
1206 char const *icon_name;
1207 char const *parent_path;
1208 GtkWidget * (*page_initializer) (PrefState *state, gpointer data,
1209 GtkNotebook *notebook, gint page_num);
1210 } page_info_t;
1212 /* Note that the page names are used in calls to dialog_preferences and as default in dialog_pref_select_page! */
1213 static page_info_t const page_info[] = {
1214 {N_("Auto Correct"), GTK_STOCK_DIALOG_ERROR, NULL, &pref_autocorrect_general_page_initializer},
1215 {N_("Font"), GTK_STOCK_ITALIC, NULL, &pref_font_initializer },
1216 {N_("Files"), GTK_STOCK_FLOPPY, NULL, &pref_file_page_initializer },
1217 {N_("Tools"), GTK_STOCK_EXECUTE, NULL, &pref_tool_page_initializer },
1218 {N_("Undo"), GTK_STOCK_UNDO, NULL, &pref_undo_page_initializer },
1219 {N_("Windows"), "gnumeric-object-combo", NULL, &pref_window_page_initializer },
1220 {N_("Header/Footer"), GTK_STOCK_ITALIC, "1", &pref_font_hf_initializer },
1221 #ifndef G_OS_WIN32
1222 {N_("Copy and Paste"),GTK_STOCK_PASTE, "3", &pref_copypaste_page_initializer},
1223 #endif
1224 {N_("Sorting"), GTK_STOCK_SORT_ASCENDING, "3", &pref_sort_page_initializer },
1225 {N_("Screen"), GTK_STOCK_PREFERENCES, "5", &pref_screen_page_initializer },
1226 {N_("INitial CApitals"), NULL, "0", &pref_autocorrect_initialcaps_page_initializer },
1227 {N_("First Letter"), NULL, "0", &pref_autocorrect_firstletter_page_initializer },
1228 {NULL, NULL, NULL, NULL },
1231 typedef struct {
1232 gchar const *page;
1233 GtkTreePath *path;
1234 } page_search_t;
1236 static gboolean
1237 dialog_pref_select_page_search (GtkTreeModel *model,
1238 GtkTreePath *path,
1239 GtkTreeIter *iter,
1240 page_search_t *pst)
1242 gchar *page;
1243 gtk_tree_model_get (model, iter, ITEM_NAME, &page, -1);
1244 if (0 == strcmp (page, pst->page)) {
1245 g_free (page);
1246 pst->path = gtk_tree_path_copy (path);
1247 return TRUE;
1248 } else {
1249 g_free (page);
1250 return FALSE;
1254 static void
1255 dialog_pref_select_page (PrefState *state, gchar const *page)
1257 page_search_t pst = {NULL, NULL};
1259 if (page == NULL)
1260 page = "Tools";
1262 pst.page = _(page);
1263 gtk_tree_model_foreach (GTK_TREE_MODEL (state->store),
1264 (GtkTreeModelForeachFunc) dialog_pref_select_page_search,
1265 &pst);
1267 if (pst.path == NULL)
1268 pst.path = gtk_tree_path_new_first ();
1270 if (pst.path != NULL) {
1271 gtk_tree_view_set_cursor (state->view, pst.path, NULL, FALSE);
1272 gtk_tree_view_expand_row (state->view, pst.path, TRUE);
1273 gtk_tree_path_free (pst.path);
1277 static void
1278 cb_dialog_pref_selection_changed (GtkTreeSelection *selection,
1279 PrefState *state)
1281 GtkTreeIter iter;
1282 int page;
1284 if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
1285 gtk_tree_model_get (GTK_TREE_MODEL (state->store), &iter,
1286 PAGE_NUMBER, &page,
1287 -1);
1288 gtk_notebook_set_current_page (state->notebook, page);
1289 } else {
1290 dialog_pref_select_page (state, 0);
1294 static void
1295 cb_preferences_destroy (PrefState *state)
1297 if (state->store) {
1298 g_object_unref (state->store);
1299 state->store = NULL;
1301 if (state->gui != NULL) {
1302 g_object_unref (state->gui);
1303 state->gui = NULL;
1305 if (state->app_wb_removed_sig) {
1306 g_signal_handler_disconnect (gnm_app_get_app (),
1307 state->app_wb_removed_sig);
1308 state->app_wb_removed_sig = 0;
1310 g_object_set_data (gnm_app_get_app (), PREF_DIALOG_KEY, NULL);
1313 static void
1314 cb_close_clicked (PrefState *state)
1316 gtk_widget_destroy (GTK_WIDGET (state->dialog));
1319 static void
1320 cb_workbook_removed (PrefState *state)
1322 if (gnm_app_workbook_list () == NULL)
1323 cb_close_clicked (state);
1326 void
1327 dialog_preferences (WBCGtk *wbcg, gchar const *page)
1329 PrefState *state;
1330 GtkBuilder *gui;
1331 GtkWidget *w;
1332 gint i;
1333 GtkTreeViewColumn *column;
1334 GtkTreeSelection *selection;
1336 w = g_object_get_data (gnm_app_get_app (), PREF_DIALOG_KEY);
1337 if (w) {
1338 gtk_widget_show (w);
1339 gdk_window_raise (gtk_widget_get_window (w));
1340 return;
1343 gui = gnm_gtk_builder_load ("res:ui/preferences.ui", NULL, GO_CMD_CONTEXT (wbcg));
1344 if (gui == NULL)
1345 return;
1347 state = g_new0 (PrefState, 1);
1348 state->gui = gui;
1349 state->dialog = go_gtk_builder_get_widget (gui, "preferences");
1350 state->notebook = (GtkNotebook*)go_gtk_builder_get_widget (gui, "notebook");
1352 state->view = GTK_TREE_VIEW(go_gtk_builder_get_widget (gui, "itemlist"));
1353 state->store = gtk_tree_store_new (NUM_COLUMNS,
1354 GDK_TYPE_PIXBUF,
1355 G_TYPE_STRING,
1356 G_TYPE_INT);
1357 gtk_tree_view_set_model (state->view, GTK_TREE_MODEL(state->store));
1358 selection = gtk_tree_view_get_selection (state->view);
1359 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1360 column = gtk_tree_view_column_new_with_attributes ("",
1361 gtk_cell_renderer_pixbuf_new (),
1362 "pixbuf", ITEM_ICON,
1363 NULL);
1364 gtk_tree_view_append_column (state->view, column);
1365 column = gtk_tree_view_column_new_with_attributes ("",
1366 gtk_cell_renderer_text_new (),
1367 "text", ITEM_NAME,
1368 NULL);
1369 gtk_tree_view_append_column (state->view, column);
1370 gtk_tree_view_set_expander_column (state->view, column);
1372 g_signal_connect (selection,
1373 "changed",
1374 G_CALLBACK (cb_dialog_pref_selection_changed), state);
1376 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "close_button")),
1377 "clicked",
1378 G_CALLBACK (cb_close_clicked), state);
1380 gnm_init_help_button (
1381 go_gtk_builder_get_widget (state->gui, "help_button"),
1382 GNUMERIC_HELP_LINK_PREFERENCES);
1383 g_signal_connect_swapped (G_OBJECT (state->dialog),
1384 "destroy",
1385 G_CALLBACK(cb_preferences_destroy),
1386 state);
1387 g_object_set_data_full (G_OBJECT (state->dialog),
1388 "state", state,
1389 (GDestroyNotify)g_free);
1391 g_object_set_data (gnm_app_get_app (), PREF_DIALOG_KEY, state->dialog);
1393 state->app_wb_removed_sig =
1394 g_signal_connect_swapped (gnm_app_get_app (),
1395 "workbook_removed",
1396 G_CALLBACK (cb_workbook_removed),
1397 state);
1399 for (i = 0; page_info[i].page_initializer; i++) {
1400 const page_info_t *this_page = &page_info[i];
1401 GtkWidget *page_widget =
1402 this_page->page_initializer (state, NULL,
1403 state->notebook, i);
1404 gtk_notebook_append_page (state->notebook, page_widget, NULL);
1405 dialog_pref_add_item (state, this_page->page_name,
1406 this_page->icon_name, i,
1407 this_page->parent_path);
1410 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (state->store),
1411 ITEM_NAME, GTK_SORT_ASCENDING);
1413 go_gtk_nonmodal_dialog (wbcg_toplevel (wbcg),
1414 GTK_WINDOW (state->dialog));
1415 gtk_widget_show (GTK_WIDGET (state->dialog));
1417 dialog_pref_select_page (state, page);