GUI: Move .ui files from goffice resources to glib resources
[gnumeric.git] / src / dialogs / dialog-preferences.c
blob686b783e96f7554187cf1e8bf3b568ab6681cad9
1 /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dialog-preferences.c: Dialog to edit application wide preferences and default values
5 * Author:
6 * Andreas J. Guelzow <aguelzow@taliesin.ca>
8 * (C) Copyright 2000-2002 Jody Goldberg <jody@gnome.org>
9 * (C) Copyright 2003-2004 Andreas J. Guelzow <aguelzow@taliesin.ca>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses/>.
25 #include <gnumeric-config.h>
26 #include <gnumeric.h>
27 #include "application.h"
28 #include "dialogs.h"
29 #include "help.h"
31 #include "mstyle.h"
32 #include "value.h"
33 #include <gnm-format.h>
34 #include "workbook.h"
35 #include "workbook-control.h"
36 #include "wbc-gtk.h"
37 #include "number-match.h"
38 #include "widgets/gnumeric-cell-renderer-text.h"
40 #include "gnumeric-conf.h"
42 #include <gui-util.h>
43 #include <gtk/gtk.h>
44 #include <glib/gi18n-lib.h>
45 #include <string.h>
47 #define PREF_DIALOG_KEY "pref-dialog"
49 enum {
50 ITEM_ICON,
51 ITEM_NAME,
52 PAGE_NUMBER,
53 NUM_COLUMNS
56 typedef struct {
57 GtkBuilder *gui;
58 GtkWidget *dialog;
59 GtkNotebook *notebook;
60 GtkTreeStore *store;
61 GtkTreeView *view;
62 gulong app_wb_removed_sig;
63 } PrefState;
65 typedef void (* double_conf_setter_t) (double value);
66 typedef void (* gint_conf_setter_t) (gint value);
67 typedef void (* gboolean_conf_setter_t) (gboolean value);
68 typedef void (* enum_conf_setter_t) (int value);
69 typedef void (* wordlist_conf_setter_t) (GSList *value);
71 typedef gboolean (* gboolean_conf_getter_t) (void);
72 typedef GSList * (* wordlist_conf_getter_t) (void);
73 typedef int (* enum_conf_getter_t) (void);
74 typedef gint (* gint_conf_getter_t) (void);
75 typedef double (* double_conf_getter_t) (void);
77 static void
78 dialog_pref_add_item (PrefState *state, char const *page_name,
79 char const *icon_name,
80 int page, char const* parent_path)
82 GtkTreeIter iter, parent;
83 GdkPixbuf * icon = NULL;
85 if (icon_name != NULL)
86 icon = gtk_widget_render_icon_pixbuf (state->dialog, icon_name,
87 GTK_ICON_SIZE_MENU);
88 if ((parent_path != NULL) && gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (state->store),
89 &parent, parent_path))
90 gtk_tree_store_append (state->store, &iter, &parent);
91 else
92 gtk_tree_store_append (state->store, &iter, NULL);
94 gtk_tree_store_set (state->store, &iter,
95 ITEM_ICON, icon,
96 ITEM_NAME, _(page_name),
97 PAGE_NUMBER, page,
98 -1);
99 if (icon != NULL)
100 g_object_unref (icon);
103 static void
104 set_tip (GOConfNode *node, GtkWidget *w)
106 const char *desc = gnm_conf_get_long_desc (node);
107 if (desc != NULL)
108 gtk_widget_set_tooltip_text (w, desc);
111 static void
112 cb_pref_notification_destroy (gpointer handle)
114 go_conf_remove_monitor (GPOINTER_TO_UINT (handle));
117 static void
118 connect_notification (GOConfNode *node, GOConfMonitorFunc func,
119 gpointer data, GtkWidget *container)
121 guint handle = go_conf_add_monitor (node, NULL, func, data);
122 g_signal_connect_swapped (G_OBJECT (container), "destroy",
123 G_CALLBACK (cb_pref_notification_destroy),
124 GUINT_TO_POINTER (handle));
127 /*************************************************************************/
129 static void
130 pref_create_label (GOConfNode *node, GtkWidget *grid,
131 gint row, gchar const *default_label, GtkWidget *w)
133 GtkWidget *label;
135 if (NULL == default_label) {
136 const char *desc = gnm_conf_get_short_desc (node);
137 label = gtk_label_new (desc);
138 } else
139 label = gtk_label_new_with_mnemonic (default_label);
141 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
142 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
143 gtk_widget_set_hexpand (label, TRUE);
144 gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
146 gtk_label_set_mnemonic_widget (GTK_LABEL (label), w);
147 go_atk_setup_label (label, w);
150 /*************************************************************************/
152 static void
153 bool_pref_widget_to_conf (GtkToggleButton *button,
154 gboolean_conf_setter_t setter)
156 gboolean_conf_getter_t getter
157 = g_object_get_data (G_OBJECT (button), "getter");
158 gboolean val_in_button = gtk_toggle_button_get_active (button);
159 gboolean val_in_conf = getter ();
160 if ((!val_in_button) != (!val_in_conf))
161 setter (val_in_button);
164 static void
165 bool_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
166 GtkToggleButton *button)
168 gboolean val_in_button = gtk_toggle_button_get_active (button);
170 /* We can't use the getter here since the main preferences */
171 /* may be notified after us */
172 gboolean val_in_conf = go_conf_get_bool (node, NULL);
174 if ((!val_in_button) != (!val_in_conf))
175 gtk_toggle_button_set_active (button, val_in_conf);
178 static void
179 bool_pref_create_widget (GOConfNode *node, GtkWidget *grid,
180 gint row, gboolean_conf_setter_t setter,
181 gboolean_conf_getter_t getter,
182 char const *default_label)
184 const char *desc = gnm_conf_get_short_desc (node);
185 GtkWidget *item = gtk_check_button_new_with_label (
186 (desc != NULL) ? desc : default_label);
188 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), getter ());
190 g_object_set_data (G_OBJECT (item), "getter", getter);
191 g_signal_connect (G_OBJECT (item), "toggled",
192 G_CALLBACK (bool_pref_widget_to_conf),
193 (gpointer) setter);
194 gtk_grid_attach (GTK_GRID (grid), item, 0, row, 2, 1);
196 connect_notification (node, (GOConfMonitorFunc)bool_pref_conf_to_widget,
197 item, grid);
198 set_tip (node, item);
201 /*************************************************************************/
203 static void
204 cb_enum_changed (GtkComboBox *combo, enum_conf_setter_t setter)
206 GtkTreeIter iter;
207 if (gtk_combo_box_get_active_iter (combo, &iter)) {
208 GtkTreeModel *model = gtk_combo_box_get_model (combo);
209 GEnumValue *enum_val;
210 gtk_tree_model_get (model, &iter, 1, &enum_val, -1);
211 (*setter) (enum_val->value);
215 typedef struct {
216 char *val;
217 GtkComboBox *combo;
218 } FindEnumClosure;
220 static gboolean
221 cb_find_enum (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
222 FindEnumClosure *cls)
224 gboolean res = FALSE;
225 char *combo_val;
227 g_return_val_if_fail (model != NULL, FALSE);
228 g_return_val_if_fail (cls->val != NULL, FALSE);
230 gtk_tree_model_get (model, iter, 0, &combo_val, -1);
231 if (combo_val) {
232 if (0 == strcmp (cls->val, combo_val)) {
233 res = TRUE;
234 gtk_combo_box_set_active_iter (cls->combo, iter);
236 g_free (combo_val);
238 return res;
241 static void
242 enum_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
243 GtkComboBox *combo)
245 FindEnumClosure cls;
246 GtkTreeModel *model = gtk_combo_box_get_model (combo);
248 cls.combo = combo;
249 /* We can't use the getter here since the main preferences */
250 /* may be notified after us */
251 cls.val = go_conf_get_enum_as_str (node, NULL);
252 if (NULL != cls.val) { /* in case go_conf fails */
253 gtk_tree_model_foreach (model,
254 (GtkTreeModelForeachFunc)cb_find_enum,
255 &cls);
256 g_free (cls.val);
260 static void
261 enum_pref_create_widget (GOConfNode *node, GtkWidget *grid,
262 gint row, GType enum_type,
263 enum_conf_setter_t setter,
264 enum_conf_getter_t getter,
265 gchar const *default_label,
266 char const *(*label_getter)(int))
268 unsigned int i;
269 GtkTreeIter iter;
270 GtkCellRenderer *renderer;
271 GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (enum_type));
272 GtkWidget *combo = gtk_combo_box_new ();
273 GtkListStore *model = gtk_list_store_new (2,
274 G_TYPE_STRING, G_TYPE_POINTER);
275 gint current = getter ();
276 gint current_index = -1;
278 for (i = 0; i < enum_class->n_values ; i++) {
279 gtk_list_store_append (model, &iter);
280 gtk_list_store_set (model, &iter,
281 0, label_getter ((int) enum_class->values[i].value),
282 1, enum_class->values + i,
283 -1);
284 if (enum_class->values[i].value == current)
285 current_index = i;
288 g_type_class_unref (enum_class);
290 gtk_combo_box_set_model (GTK_COMBO_BOX (combo), GTK_TREE_MODEL (model));
291 g_object_unref (model);
292 renderer = gtk_cell_renderer_text_new ();
293 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
294 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, "text", 0, NULL);
296 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), current_index);
298 gtk_grid_attach (GTK_GRID (grid), combo, 1, row, 1, 1);
300 g_signal_connect (G_OBJECT (combo), "changed",
301 G_CALLBACK (cb_enum_changed), (gpointer) setter);
302 connect_notification (node, (GOConfMonitorFunc)enum_pref_conf_to_widget,
303 combo, grid);
305 pref_create_label (node, grid, row, default_label, combo);
306 set_tip (node, combo);
309 /*************************************************************************/
311 static void
312 int_pref_widget_to_conf (GtkSpinButton *button, gint_conf_setter_t setter)
314 gint_conf_getter_t getter
315 = g_object_get_data (G_OBJECT (button), "getter");
316 gint val_in_button = gtk_spin_button_get_value_as_int (button);
317 gint val_in_conf = getter ();
319 if (val_in_conf != val_in_button)
320 setter (val_in_button);
323 static void
324 int_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
325 GtkSpinButton *button)
327 gint val_in_button = gtk_spin_button_get_value_as_int (button);
329 /* We can't use the getter here since the main preferences */
330 /* may be notified after us */
331 gint val_in_conf = go_conf_get_int (node, NULL);
333 if (val_in_conf != val_in_button)
334 gtk_spin_button_set_value (button, (gdouble) val_in_conf);
337 static GtkWidget *
338 int_pref_create_widget (GOConfNode *node, GtkWidget *grid,
339 gint row, gint val, gint from, gint to, gint step,
340 gint_conf_setter_t setter, gint_conf_getter_t getter,
341 char const *default_label)
343 GtkAdjustment *adj = GTK_ADJUSTMENT
344 (gtk_adjustment_new (val, from, to, step, step, 0));
345 GtkWidget *w = gtk_spin_button_new (adj, 1, 0);
347 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), (gdouble) getter ());
349 g_object_set_data (G_OBJECT (w), "node", node);
350 gtk_widget_set_hexpand (w, TRUE);
351 gtk_grid_attach (GTK_GRID (grid), w, 1, row, 1, 1);
353 g_object_set_data (G_OBJECT (w), "getter", getter);
354 g_signal_connect (G_OBJECT (w), "value-changed",
355 G_CALLBACK (int_pref_widget_to_conf),
356 (gpointer) setter);
357 connect_notification (node, (GOConfMonitorFunc)int_pref_conf_to_widget,
358 w, grid);
360 pref_create_label (node, grid, row, default_label, w);
361 set_tip (node, w);
362 return w;
365 static gboolean
366 powerof_2 (int i)
368 return i > 0 && (i & (i - 1)) == 0;
371 static void
372 cb_power_of_2 (GtkAdjustment *adj)
374 int val = (int)gtk_adjustment_get_value (adj);
376 if (powerof_2 (val - 1))
377 gtk_adjustment_set_value (adj, (val - 1) * 2);
378 else if (powerof_2 (val + 1))
379 gtk_adjustment_set_value (adj, (val + 1) / 2);
382 static void
383 power_of_2_handlers (GtkWidget *w)
385 GtkSpinButton *spin = GTK_SPIN_BUTTON (w);
386 GtkAdjustment *adj = gtk_spin_button_get_adjustment (spin);
387 g_signal_connect (G_OBJECT (adj), "value_changed",
388 G_CALLBACK (cb_power_of_2), NULL);
391 /*************************************************************************/
393 static void
394 double_pref_widget_to_conf (GtkSpinButton *button, double_conf_setter_t setter)
396 double_conf_getter_t getter
397 = g_object_get_data (G_OBJECT (button), "getter");
398 double val_in_button = gtk_spin_button_get_value (button);
399 double val_in_conf = getter();
401 if (fabs (val_in_conf - val_in_button) > 1e-10) /* dead simple */
402 setter (val_in_button);
405 static void
406 double_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
407 GtkSpinButton *button)
409 double val_in_button = gtk_spin_button_get_value (button);
411 /* We can't use the getter here since the main preferences */
412 /* may be notified after us */
413 double val_in_conf = go_conf_get_double (node, NULL);
415 if (fabs (val_in_conf - val_in_button) > 1e-10) /* dead simple */
416 gtk_spin_button_set_value (button, val_in_conf);
418 static void
419 double_pref_create_widget (GOConfNode *node, GtkWidget *grid,
420 gint row, gnm_float val, gnm_float from, gnm_float to,
421 gnm_float step, gint digits,
422 double_conf_setter_t setter,
423 double_conf_getter_t getter,
424 char const *default_label)
426 GtkWidget *w = gtk_spin_button_new (GTK_ADJUSTMENT (
427 gtk_adjustment_new (val, from, to, step, step, 0)),
428 1, digits);
429 gtk_spin_button_set_value (GTK_SPIN_BUTTON (w), getter ());
430 g_object_set_data (G_OBJECT (w), "node", node);
431 gtk_widget_set_hexpand (w, TRUE);
432 gtk_grid_attach (GTK_GRID (grid), w, 1, row, 1, 1);
434 g_object_set_data (G_OBJECT (w), "getter", getter);
435 g_signal_connect (G_OBJECT (w), "value-changed",
436 G_CALLBACK (double_pref_widget_to_conf), (gpointer) setter);
437 connect_notification (node,
438 (GOConfMonitorFunc)double_pref_conf_to_widget,
439 w, grid);
441 pref_create_label (node, grid, row, default_label, w);
442 set_tip (node, w);
446 /*************************************************************************/
450 static void
451 wordlist_pref_conf_to_widget (GOConfNode *node, G_GNUC_UNUSED char const *key,
452 GtkListStore *store)
454 /* We can't use the getter here since the main preferences */
455 /* may be notified after us */
456 GSList *l, *list = go_conf_get_str_list (node, NULL);
457 GtkTreeIter iter;
459 gtk_list_store_clear (store);
461 for (l = list; l != NULL; l = l->next) {
462 gtk_list_store_append (store, &iter);
463 gtk_list_store_set (store, &iter,
464 0, l->data,
465 -1);
466 g_free (l->data);
468 g_slist_free (list);
471 static void
472 wordlist_pref_remove (GtkButton *button, wordlist_conf_setter_t setter) {
473 GtkTreeView *tree = g_object_get_data (G_OBJECT (button), "treeview");
474 GtkTreeSelection *select = gtk_tree_view_get_selection (tree);
475 GtkTreeIter iter;
476 GtkTreeModel *model;
478 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
479 char *text;
480 wordlist_conf_getter_t getter = g_object_get_data (G_OBJECT (button), "getter");
481 GSList *l, *list = getter ();
483 list = go_string_slist_copy (list);
485 gtk_tree_model_get (model, &iter,
486 0, &text,
487 -1);
488 l = g_slist_find_custom (list, text, (GCompareFunc)strcmp);
489 if (l != NULL) {
490 g_free (l->data);
491 list = g_slist_delete_link (list, l);
492 setter (list);
494 g_slist_free_full (list, g_free);
495 g_free (text);
499 static void
500 wordlist_pref_add (GtkButton *button, wordlist_conf_setter_t setter)
502 GtkEntry *entry = g_object_get_data (G_OBJECT (button), "entry");
503 const gchar *text = gtk_entry_get_text (entry);
505 if (text[0]) {
506 wordlist_conf_getter_t getter = g_object_get_data (G_OBJECT (button), "getter");
507 GSList *l, *list = getter ();
508 l = g_slist_find_custom (list, text, (GCompareFunc)strcmp);
509 if (l == NULL) {
510 list = go_string_slist_copy (list);
511 list = g_slist_append (list, g_strdup (text));
512 setter (list);
513 g_slist_free_full (list, g_free);
518 static void
519 wordlist_pref_update_remove_button (GtkTreeSelection *selection, GtkButton *button)
521 gtk_widget_set_sensitive (GTK_WIDGET (button),
522 gtk_tree_selection_get_selected (selection, NULL, NULL));
525 static GtkWidget *
526 wordlist_pref_create_widget (GOConfNode *node, GtkWidget *grid,
527 gint row, wordlist_conf_setter_t setter,
528 wordlist_conf_getter_t getter,
529 char const *default_label)
531 GtkWidget *w = gtk_grid_new ();
532 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
533 GtkWidget *tv = gtk_tree_view_new ();
534 GtkWidget *entry = gtk_entry_new ();
535 GtkWidget *add_button = gtk_button_new_from_stock (GTK_STOCK_ADD);
536 GtkWidget *remove_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
537 GtkListStore *model = gtk_list_store_new (1, G_TYPE_STRING);
538 GtkTreeSelection *selection;
540 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
541 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
542 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
543 GTK_SHADOW_ETCHED_IN);
544 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), FALSE);
545 gtk_container_add (GTK_CONTAINER (sw), tv);
547 g_object_set (w, "column-spacing", 12, "row-spacing", 6,
548 "hexpand", TRUE, "vexpand", TRUE, NULL);
549 gtk_grid_attach (GTK_GRID (grid), w, 0, row, 2, 1);
550 g_object_set (sw, "hexpand", TRUE, "vexpand", TRUE, NULL);
551 gtk_grid_attach (GTK_GRID (w), sw, 0, 1, 1, 3);
552 gtk_widget_set_hexpand (entry, TRUE);
553 gtk_grid_attach (GTK_GRID (w), entry, 0, 4, 1, 1);
554 gtk_widget_set_valign (remove_button, GTK_ALIGN_END);
555 gtk_grid_attach (GTK_GRID (w), remove_button, 1, 3, 1, 1);
556 gtk_grid_attach (GTK_GRID (w), add_button, 1, 4, 1, 1);
558 gtk_tree_view_set_model (GTK_TREE_VIEW (tv),
559 GTK_TREE_MODEL (model));
560 g_object_unref (model);
561 gtk_tree_view_append_column (GTK_TREE_VIEW (tv),
562 gtk_tree_view_column_new_with_attributes
563 (NULL,
564 gtk_cell_renderer_text_new (),
565 "text", 0,
566 NULL));
567 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
568 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
569 wordlist_pref_conf_to_widget (node, "", model);
571 g_object_set_data (G_OBJECT (remove_button), "treeview", tv);
572 g_object_set_data (G_OBJECT (add_button), "entry", entry);
573 g_object_set_data (G_OBJECT (remove_button), "getter", getter);
574 g_object_set_data (G_OBJECT (add_button), "getter", getter);
575 g_signal_connect (G_OBJECT (remove_button), "clicked",
576 G_CALLBACK (wordlist_pref_remove), setter);
577 g_signal_connect (G_OBJECT (add_button), "clicked",
578 G_CALLBACK (wordlist_pref_add), setter);
579 g_signal_connect (G_OBJECT (selection), "changed",
580 G_CALLBACK (wordlist_pref_update_remove_button), remove_button);
581 wordlist_pref_update_remove_button (selection,
582 GTK_BUTTON (remove_button));
584 connect_notification (node, (GOConfMonitorFunc)wordlist_pref_conf_to_widget,
585 model, grid);
587 pref_create_label (node, w, 0, default_label, tv);
588 set_tip (node, tv);
589 return w;
592 /*******************************************************************************************/
593 /* Default Font Selector */
594 /*******************************************************************************************/
596 static void
597 do_set_font (GOFontSel *fs,
598 const char *name, double size,
599 gboolean is_bold, gboolean is_italic)
601 PangoFontDescription *desc;
603 desc = pango_font_description_new ();
604 pango_font_description_set_family (desc, name);
605 pango_font_description_set_size (desc, PANGO_SCALE * size);
606 pango_font_description_set_weight
607 (desc,
608 is_bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
609 pango_font_description_set_style
610 (desc,
611 is_italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
613 go_font_sel_set_font_desc (fs, desc);
614 pango_font_description_free (desc);
618 static void
619 cb_pref_font_set_fonts (G_GNUC_UNUSED GOConfNode *node,
620 G_GNUC_UNUSED char const *key,
621 GtkWidget *page)
623 GOFontSel *fs = GO_FONT_SEL (page);
625 do_set_font (fs,
626 gnm_conf_get_core_defaultfont_name (),
627 gnm_conf_get_core_defaultfont_size (),
628 gnm_conf_get_core_defaultfont_bold (),
629 gnm_conf_get_core_defaultfont_italic ());
632 static gboolean
633 cb_pref_font_has_changed (GOFontSel *fs, G_GNUC_UNUSED PangoAttrList *attrs,
634 PrefState *state)
636 PangoFontDescription *desc = go_font_sel_get_font_desc (fs);
637 PangoFontMask fields = pango_font_description_get_set_fields (desc);
639 if (fields & PANGO_FONT_MASK_FAMILY)
640 gnm_conf_set_core_defaultfont_name
641 (pango_font_description_get_family (desc));
642 if (fields & PANGO_FONT_MASK_SIZE)
643 gnm_conf_set_core_defaultfont_size
644 (pango_font_description_get_size (desc) / (double)PANGO_SCALE);
645 if (fields & PANGO_FONT_MASK_WEIGHT)
646 gnm_conf_set_core_defaultfont_bold
647 (pango_font_description_get_weight (desc) >= PANGO_WEIGHT_BOLD);
648 if (fields & PANGO_FONT_MASK_STYLE)
649 gnm_conf_set_core_defaultfont_italic
650 (pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL);
652 pango_font_description_free (desc);
654 return TRUE;
657 static GtkWidget *
658 pref_font_initializer (PrefState *state,
659 G_GNUC_UNUSED gpointer data,
660 G_GNUC_UNUSED GtkNotebook *notebook,
661 G_GNUC_UNUSED gint page_num)
663 GtkWidget *page = g_object_new (GO_TYPE_FONT_SEL,
664 "show-style", TRUE,
665 NULL);
667 cb_pref_font_set_fonts (NULL, NULL, page);
669 connect_notification (gnm_conf_get_core_defaultfont_dir_node (),
670 (GOConfMonitorFunc) cb_pref_font_set_fonts,
671 page, page);
672 g_signal_connect (G_OBJECT (page),
673 "font_changed",
674 G_CALLBACK (cb_pref_font_has_changed), state);
676 gtk_widget_show_all (page);
678 return page;
681 /*******************************************************************************************/
682 /* Default Header/Footer Font Selector */
683 /*******************************************************************************************/
685 static void
686 cb_pref_font_hf_set_fonts (G_GNUC_UNUSED GOConfNode *node,
687 G_GNUC_UNUSED char const *key,
688 GtkWidget *page)
690 GOFontSel *fs = GO_FONT_SEL (page);
691 do_set_font (fs,
692 gnm_conf_get_printsetup_hf_font_name (),
693 gnm_conf_get_printsetup_hf_font_size (),
694 gnm_conf_get_printsetup_hf_font_bold (),
695 gnm_conf_get_printsetup_hf_font_italic ());
698 static gboolean
699 cb_pref_font_hf_has_changed (GOFontSel *fs, G_GNUC_UNUSED PangoAttrList *attrs,
700 PrefState *state)
702 PangoFontDescription *desc = go_font_sel_get_font_desc (fs);
703 PangoFontMask fields = pango_font_description_get_set_fields (desc);
705 if (fields & PANGO_FONT_MASK_FAMILY)
706 gnm_conf_set_printsetup_hf_font_name
707 (pango_font_description_get_family (desc));
708 if (fields & PANGO_FONT_MASK_SIZE)
709 gnm_conf_set_printsetup_hf_font_size
710 (pango_font_description_get_size (desc) / (double)PANGO_SCALE);
711 if (fields & PANGO_FONT_MASK_WEIGHT)
712 gnm_conf_set_printsetup_hf_font_bold
713 (pango_font_description_get_weight (desc) >= PANGO_WEIGHT_BOLD);
714 if (fields & PANGO_FONT_MASK_STYLE)
715 gnm_conf_set_printsetup_hf_font_italic
716 (pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL);
718 pango_font_description_free (desc);
720 return TRUE;
723 static GtkWidget *
724 pref_font_hf_initializer (PrefState *state,
725 G_GNUC_UNUSED gpointer data,
726 G_GNUC_UNUSED GtkNotebook *notebook,
727 G_GNUC_UNUSED gint page_num)
729 GtkWidget *page = g_object_new (GO_TYPE_FONT_SEL,
730 "show-style", TRUE,
731 NULL);
733 cb_pref_font_hf_set_fonts (NULL, NULL, page);
734 connect_notification (gnm_conf_get_printsetup_dir_node (),
735 (GOConfMonitorFunc) cb_pref_font_hf_set_fonts,
736 page, page);
737 g_signal_connect (G_OBJECT (page),
738 "font_changed",
739 G_CALLBACK (cb_pref_font_hf_has_changed), state);
741 gtk_widget_show_all (page);
743 return page;
746 /*******************************************************************************************/
747 /* Undo Preferences Page */
748 /*******************************************************************************************/
750 static GtkWidget *
751 pref_undo_page_initializer (PrefState *state,
752 G_GNUC_UNUSED gpointer data,
753 G_GNUC_UNUSED GtkNotebook *notebook,
754 G_GNUC_UNUSED gint page_num)
756 GtkWidget *page = gtk_grid_new ();
757 gint row = 0;
759 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
760 "vexpand", TRUE, NULL);
761 int_pref_create_widget (gnm_conf_get_undo_max_descriptor_width_node (),
762 page, row++, 5, 5, 200, 1,
763 gnm_conf_set_undo_max_descriptor_width,
764 gnm_conf_get_undo_max_descriptor_width,
765 _("Length of Undo Descriptors"));
766 int_pref_create_widget (gnm_conf_get_undo_size_node (),
767 page, row++, 1000, 0, 30000, 100,
768 gnm_conf_set_undo_size,
769 gnm_conf_get_undo_size,
770 _("Maximal Undo Size"));
771 int_pref_create_widget (gnm_conf_get_undo_maxnum_node (),
772 page, row++, 20, 1, 200, 1,
773 gnm_conf_set_undo_maxnum,
774 gnm_conf_get_undo_maxnum,
775 _("Number of Undo Items"));
776 bool_pref_create_widget (gnm_conf_get_undo_show_sheet_name_node (),
777 page, row++,
778 gnm_conf_set_undo_show_sheet_name,
779 gnm_conf_get_undo_show_sheet_name,
780 _("Show Sheet Name in Undo List"));
782 gtk_widget_show_all (page);
783 return page;
786 /*******************************************************************************************/
787 /* Sort Preferences Page */
788 /*******************************************************************************************/
790 static GtkWidget *
791 pref_sort_page_initializer (PrefState *state,
792 G_GNUC_UNUSED gpointer data,
793 G_GNUC_UNUSED GtkNotebook *notebook,
794 G_GNUC_UNUSED gint page_num)
796 GtkWidget *page = gtk_grid_new ();
797 gint row = 0;
799 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
800 "vexpand", TRUE, NULL);
801 int_pref_create_widget (gnm_conf_get_core_sort_dialog_max_initial_clauses_node (),
802 page, row++, 10, 0, 50, 1,
803 gnm_conf_set_core_sort_dialog_max_initial_clauses,
804 gnm_conf_get_core_sort_dialog_max_initial_clauses,
805 _("Number of Automatic Clauses"));
806 bool_pref_create_widget (gnm_conf_get_core_sort_default_retain_formats_node (),
807 page, row++,
808 gnm_conf_set_core_sort_default_retain_formats,
809 gnm_conf_get_core_sort_default_retain_formats,
810 _("Sorting Preserves Formats"));
811 bool_pref_create_widget (gnm_conf_get_core_sort_default_by_case_node (),
812 page, row++,
813 gnm_conf_set_core_sort_default_by_case,
814 gnm_conf_get_core_sort_default_by_case,
815 _("Sorting is Case-Sensitive"));
816 bool_pref_create_widget (gnm_conf_get_core_sort_default_ascending_node (),
817 page, row++,
818 gnm_conf_set_core_sort_default_ascending,
819 gnm_conf_get_core_sort_default_ascending,
820 _("Sort Ascending"));
822 gtk_widget_show_all (page);
823 return page;
826 /*******************************************************************************************/
827 /* Window Preferences Page */
828 /*******************************************************************************************/
830 static GtkWidget *
831 pref_window_page_initializer (PrefState *state,
832 G_GNUC_UNUSED gpointer data,
833 G_GNUC_UNUSED GtkNotebook *notebook,
834 G_GNUC_UNUSED gint page_num)
836 GtkWidget *page = gtk_grid_new ();
837 gint row = 0;
838 GtkWidget *w;
840 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
841 "vexpand", TRUE, NULL);
842 double_pref_create_widget (gnm_conf_get_core_gui_window_y_node (),
843 page, row++, 0.75, 0.25, 1, 0.05, 2,
844 gnm_conf_set_core_gui_window_y,
845 gnm_conf_get_core_gui_window_y,
846 _("Default Vertical Window Size"));
847 double_pref_create_widget (gnm_conf_get_core_gui_window_x_node (),
848 page, row++, 0.75, 0.25, 1, 0.05, 2,
849 gnm_conf_set_core_gui_window_x,
850 gnm_conf_get_core_gui_window_x,
851 _("Default Horizontal Window Size"));
852 double_pref_create_widget (gnm_conf_get_core_gui_window_zoom_node (),
853 page, row++, 1.00, 0.10, 5.00, 0.05, 2,
854 gnm_conf_set_core_gui_window_zoom,
855 gnm_conf_get_core_gui_window_zoom,
856 _("Default Zoom Factor"));
857 int_pref_create_widget (gnm_conf_get_core_workbook_n_sheet_node (),
858 page, row++, 1, 1, 64, 1,
859 gnm_conf_set_core_workbook_n_sheet,
860 gnm_conf_get_core_workbook_n_sheet,
861 _("Default Number of Sheets"));
863 w = int_pref_create_widget (gnm_conf_get_core_workbook_n_rows_node (),
864 page, row++,
865 GNM_DEFAULT_ROWS, GNM_MIN_ROWS, GNM_MAX_ROWS, 1,
866 gnm_conf_set_core_workbook_n_rows,
867 gnm_conf_get_core_workbook_n_rows,
868 _("Default Number of Rows in a Sheet"));
869 power_of_2_handlers (w);
871 w = int_pref_create_widget (gnm_conf_get_core_workbook_n_cols_node (),
872 page, row++,
873 GNM_DEFAULT_COLS, GNM_MIN_COLS, GNM_MAX_COLS, 1,
874 gnm_conf_set_core_workbook_n_cols,
875 gnm_conf_get_core_workbook_n_cols,
876 _("Default Number of Columns in a Sheet"));
877 power_of_2_handlers (w);
879 bool_pref_create_widget (gnm_conf_get_core_gui_cells_function_markers_node (),
880 page, row++,
881 gnm_conf_set_core_gui_cells_function_markers,
882 gnm_conf_get_core_gui_cells_function_markers,
883 _("By default, mark cells with spreadsheet functions"));
884 bool_pref_create_widget (gnm_conf_get_core_gui_cells_extension_markers_node (),
885 page, row++,
886 gnm_conf_set_core_gui_cells_extension_markers,
887 gnm_conf_get_core_gui_cells_extension_markers,
888 _("By default, mark cells with truncated content"));
890 gtk_widget_show_all (page);
891 return page;
894 /*******************************************************************************************/
895 /* File/XML Preferences Page */
896 /*******************************************************************************************/
898 static void
899 gnm_conf_set_core_file_save_extension_check_disabled_wrap (gboolean val)
901 GSList *list = NULL;
903 if (val)
904 list = g_slist_prepend (NULL, (char *)"Gnumeric_stf:stf_assistant");
905 gnm_conf_set_core_file_save_extension_check_disabled (list);
906 g_slist_free (list);
908 static gboolean
909 gnm_conf_get_core_file_save_extension_check_disabled_wrap (void)
911 GSList *list = gnm_conf_get_core_file_save_extension_check_disabled ();
912 return (NULL != g_slist_find_custom (list, "Gnumeric_stf:stf_assistant", go_str_compare));
915 static void
916 custom_pref_conf_to_widget_ecd (GOConfNode *node, G_GNUC_UNUSED char const *key,
917 GtkToggleButton *button)
919 gboolean val_in_button = gtk_toggle_button_get_active (button);
921 /* We can't use the getter here since the main preferences */
922 /* may be notified after us */
923 GSList *list = go_conf_get_str_list (node, NULL);
924 gboolean val_in_conf
925 = (NULL != g_slist_find_custom (list, "Gnumeric_stf:stf_assistant", go_str_compare));
927 if ((!val_in_button) != (!val_in_conf))
928 gtk_toggle_button_set_active (button, val_in_conf);
930 static void
931 custom_pref_create_widget_ecd (GOConfNode *node, GtkWidget *grid,
932 gint row, gboolean_conf_setter_t setter,
933 gboolean_conf_getter_t getter,
934 char const *default_label)
936 GtkWidget *item = gtk_check_button_new_with_label (default_label);
938 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), getter ());
940 g_object_set_data (G_OBJECT (item), "getter", getter);
941 g_signal_connect (G_OBJECT (item), "toggled",
942 G_CALLBACK (bool_pref_widget_to_conf),
943 (gpointer) setter);
944 gtk_grid_attach (GTK_GRID (grid), item, 0, row, 2, 1);
946 connect_notification (node, (GOConfMonitorFunc)custom_pref_conf_to_widget_ecd,
947 item, grid);
953 static GtkWidget *
954 pref_file_page_initializer (PrefState *state,
955 G_GNUC_UNUSED gpointer data,
956 G_GNUC_UNUSED GtkNotebook *notebook,
957 G_GNUC_UNUSED gint page_num)
959 GtkWidget *page = gtk_grid_new ();
960 gint row = 0;
962 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
963 "vexpand", TRUE, NULL);
964 int_pref_create_widget (gnm_conf_get_core_xml_compression_level_node (),
965 page, row++, 9, 0, 9, 1,
966 gnm_conf_set_core_xml_compression_level,
967 gnm_conf_get_core_xml_compression_level,
968 _("Default Compression Level For "
969 "Gnumeric Files"));
970 int_pref_create_widget (gnm_conf_get_core_workbook_autosave_time_node (),
971 page, row++, 0, 0, 365*24*60*60, 60,
972 gnm_conf_set_core_workbook_autosave_time,
973 gnm_conf_get_core_workbook_autosave_time,
974 _("Default autosave frequency in seconds"));
975 bool_pref_create_widget (gnm_conf_get_core_file_save_def_overwrite_node (),
976 page, row++,
977 gnm_conf_set_core_file_save_def_overwrite,
978 gnm_conf_get_core_file_save_def_overwrite,
979 _("Default To Overwriting Files"));
980 bool_pref_create_widget (gnm_conf_get_core_file_save_single_sheet_node (),
981 page, row++,
982 gnm_conf_set_core_file_save_single_sheet,
983 gnm_conf_get_core_file_save_single_sheet,
984 _("Warn When Exporting Into Single "
985 "Sheet Format"));
986 bool_pref_create_widget (gnm_conf_get_plugin_latex_use_utf8_node (),
987 page, row++,
988 gnm_conf_set_plugin_latex_use_utf8,
989 gnm_conf_get_plugin_latex_use_utf8,
990 _("Use UTF-8 in LaTeX Export"));
991 custom_pref_create_widget_ecd ( gnm_conf_get_core_file_save_extension_check_disabled_node (),
992 page, row++,
993 gnm_conf_set_core_file_save_extension_check_disabled_wrap,
994 gnm_conf_get_core_file_save_extension_check_disabled_wrap,
995 _("Disable Extension Check for Configurable Text Exporter"));
997 gtk_widget_show_all (page);
998 return page;
1001 /*******************************************************************************************/
1002 /* Screen Preferences Page */
1003 /*******************************************************************************************/
1005 static GtkWidget *
1006 pref_screen_page_initializer (PrefState *state,
1007 G_GNUC_UNUSED gpointer data,
1008 G_GNUC_UNUSED GtkNotebook *notebook,
1009 G_GNUC_UNUSED gint page_num)
1011 GtkWidget *page = gtk_grid_new ();
1012 gint row = 0;
1014 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1015 "vexpand", TRUE, NULL);
1016 double_pref_create_widget (gnm_conf_get_core_gui_screen_horizontaldpi_node (),
1017 page, row++, 96, 50, 250, 1, 1,
1018 gnm_conf_set_core_gui_screen_horizontaldpi,
1019 gnm_conf_get_core_gui_screen_horizontaldpi,
1020 _("Horizontal DPI"));
1021 double_pref_create_widget (gnm_conf_get_core_gui_screen_verticaldpi_node (),
1022 page, row++, 96, 50, 250, 1, 1,
1023 gnm_conf_set_core_gui_screen_verticaldpi,
1024 gnm_conf_get_core_gui_screen_verticaldpi,
1025 _("Vertical DPI"));
1027 gtk_widget_show_all (page);
1028 return page;
1031 /*******************************************************************************************/
1032 /* Tool Preferences Page */
1033 /*******************************************************************************************/
1035 static GtkWidget *
1036 pref_tool_page_initializer (PrefState *state,
1037 G_GNUC_UNUSED gpointer data,
1038 G_GNUC_UNUSED GtkNotebook *notebook,
1039 G_GNUC_UNUSED gint page_num)
1041 GtkWidget *page = gtk_grid_new ();
1042 gint row = 0;
1044 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1045 "vexpand", TRUE, NULL);
1046 enum_pref_create_widget (gnm_conf_get_core_gui_editing_enter_moves_dir_node (),
1047 page, row++,
1048 GO_TYPE_DIRECTION,
1049 (enum_conf_setter_t)gnm_conf_set_core_gui_editing_enter_moves_dir,
1050 (enum_conf_getter_t)gnm_conf_get_core_gui_editing_enter_moves_dir,
1051 _("Enter _Moves Selection"), (char const *(*) (int)) go_direction_get_name);
1052 bool_pref_create_widget (gnm_conf_get_core_gui_editing_transitionkeys_node (),
1053 page, row++,
1054 gnm_conf_set_core_gui_editing_transitionkeys,
1055 gnm_conf_get_core_gui_editing_transitionkeys,
1056 _("Transition Keys"));
1057 bool_pref_create_widget (gnm_conf_get_core_gui_editing_autocomplete_node (),
1058 page, row++,
1059 gnm_conf_set_core_gui_editing_autocomplete,
1060 gnm_conf_get_core_gui_editing_autocomplete,
1061 _("Autocomplete"));
1062 int_pref_create_widget (gnm_conf_get_core_gui_editing_autocomplete_min_chars_node (),
1063 page, row++, 3, 1, 10, 1,
1064 gnm_conf_set_core_gui_editing_autocomplete_min_chars,
1065 gnm_conf_get_core_gui_editing_autocomplete_min_chars,
1066 _("Minimum Number of Characters for Autocompletion"));
1067 bool_pref_create_widget (gnm_conf_get_core_gui_editing_function_name_tooltips_node (),
1068 page, row++,
1069 gnm_conf_set_core_gui_editing_function_name_tooltips,
1070 gnm_conf_get_core_gui_editing_function_name_tooltips,
1071 _("Show Function Name Tooltips"));
1072 bool_pref_create_widget (gnm_conf_get_core_gui_editing_function_argument_tooltips_node (),
1073 page, row++,
1074 gnm_conf_set_core_gui_editing_function_argument_tooltips,
1075 gnm_conf_get_core_gui_editing_function_argument_tooltips,
1076 _("Show Function Argument Tooltips"));
1077 bool_pref_create_widget (gnm_conf_get_dialogs_rs_unfocused_node (),
1078 page, row++,
1079 gnm_conf_set_dialogs_rs_unfocused,
1080 gnm_conf_get_dialogs_rs_unfocused,
1081 _("Allow Unfocused Range Selections"));
1082 int_pref_create_widget (gnm_conf_get_functionselector_num_of_recent_node (),
1083 page, row++, 10, 0, 40, 1,
1084 gnm_conf_set_functionselector_num_of_recent,
1085 gnm_conf_get_functionselector_num_of_recent,
1086 _("Maximum Length of Recently "
1087 "Used Functions List"));
1089 gtk_widget_show_all (page);
1090 return page;
1093 /*******************************************************************************************/
1094 /* Copy/Paste Preferences Page */
1095 /*******************************************************************************************/
1097 #ifndef G_OS_WIN32
1099 static GtkWidget *
1100 pref_copypaste_page_initializer (PrefState *state,
1101 G_GNUC_UNUSED gpointer data,
1102 G_GNUC_UNUSED GtkNotebook *notebook,
1103 G_GNUC_UNUSED gint page_num)
1105 GtkWidget *page = gtk_grid_new ();
1106 gint row = 0;
1108 g_object_set (page, "column-spacing", 12, "row-spacing", 6,
1109 "vexpand", TRUE, NULL);
1110 bool_pref_create_widget (gnm_conf_get_cut_and_paste_prefer_clipboard_node (),
1111 page, row++,
1112 gnm_conf_set_cut_and_paste_prefer_clipboard,
1113 gnm_conf_get_cut_and_paste_prefer_clipboard,
1114 /* xgettext : see https://en.wikipedia.org/wiki/X_Window_selection#Clipboard */
1115 _("Prefer CLIPBOARD Over PRIMARY Selection"));
1117 gtk_widget_show_all (page);
1118 return page;
1121 #endif
1123 /*******************************************************************************************/
1124 /* AutoCorrect Preferences Page (General) */
1125 /*******************************************************************************************/
1127 static GtkWidget *
1128 pref_autocorrect_general_page_initializer (PrefState *state,
1129 G_GNUC_UNUSED gpointer data,
1130 G_GNUC_UNUSED GtkNotebook *notebook,
1131 G_GNUC_UNUSED gint page_num)
1133 GtkWidget *page = gtk_grid_new ();
1134 gint row = 0;
1136 bool_pref_create_widget (gnm_conf_get_autocorrect_names_of_days_node (),
1137 page, row++,
1138 gnm_conf_set_autocorrect_names_of_days,
1139 gnm_conf_get_autocorrect_names_of_days,
1140 _("Capitalize _names of days"));
1142 gtk_widget_show_all (page);
1143 return page;
1146 /*******************************************************************************************/
1147 /* AutoCorrect Preferences Page (InitialCaps) */
1148 /*******************************************************************************************/
1150 static GtkWidget *
1151 pref_autocorrect_initialcaps_page_initializer (PrefState *state,
1152 G_GNUC_UNUSED gpointer data,
1153 G_GNUC_UNUSED GtkNotebook *notebook,
1154 G_GNUC_UNUSED gint page_num)
1156 GtkWidget *page = gtk_grid_new ();
1157 gint row = 0;
1159 bool_pref_create_widget (gnm_conf_get_autocorrect_init_caps_node (),
1160 page, row++,
1161 gnm_conf_set_autocorrect_init_caps,
1162 gnm_conf_get_autocorrect_init_caps,
1163 _("Correct _TWo INitial CApitals"));
1164 wordlist_pref_create_widget (gnm_conf_get_autocorrect_init_caps_list_node (), page,
1165 row++, gnm_conf_set_autocorrect_init_caps_list,
1166 gnm_conf_get_autocorrect_init_caps_list,
1167 _("Do _not correct:"));
1169 gtk_widget_show_all (page);
1170 return page;
1173 /*******************************************************************************************/
1174 /* AutoCorrect Preferences Page (FirstLetter) */
1175 /*******************************************************************************************/
1177 static GtkWidget *
1178 pref_autocorrect_firstletter_page_initializer (PrefState *state,
1179 G_GNUC_UNUSED gpointer data,
1180 G_GNUC_UNUSED GtkNotebook *notebook,
1181 G_GNUC_UNUSED gint page_num)
1183 GtkWidget *page = gtk_grid_new ();
1184 gint row = 0;
1186 bool_pref_create_widget (gnm_conf_get_autocorrect_first_letter_node (),
1187 page, row++,
1188 gnm_conf_set_autocorrect_first_letter,
1189 gnm_conf_get_autocorrect_first_letter,
1190 _("Capitalize _first letter of sentence"));
1191 wordlist_pref_create_widget (gnm_conf_get_autocorrect_first_letter_list_node (), page,
1192 row++, gnm_conf_set_autocorrect_first_letter_list,
1193 gnm_conf_get_autocorrect_first_letter_list,
1194 _("Do _not capitalize after:"));
1196 gtk_widget_show_all (page);
1197 return page;
1202 /*******************************************************************************************/
1203 /* General Preference Dialog Routines */
1204 /*******************************************************************************************/
1206 typedef struct {
1207 char const *page_name;
1208 char const *icon_name;
1209 char const *parent_path;
1210 GtkWidget * (*page_initializer) (PrefState *state, gpointer data,
1211 GtkNotebook *notebook, gint page_num);
1212 } page_info_t;
1214 /* Note that the page names are used in calls to dialog_preferences and as default in dialog_pref_select_page! */
1215 static page_info_t const page_info[] = {
1216 {N_("Auto Correct"), GTK_STOCK_DIALOG_ERROR, NULL, &pref_autocorrect_general_page_initializer},
1217 {N_("Font"), GTK_STOCK_ITALIC, NULL, &pref_font_initializer },
1218 {N_("Files"), GTK_STOCK_FLOPPY, NULL, &pref_file_page_initializer },
1219 {N_("Tools"), GTK_STOCK_EXECUTE, NULL, &pref_tool_page_initializer },
1220 {N_("Undo"), GTK_STOCK_UNDO, NULL, &pref_undo_page_initializer },
1221 {N_("Windows"), "gnumeric-object-combo", NULL, &pref_window_page_initializer },
1222 {N_("Header/Footer"), GTK_STOCK_ITALIC, "1", &pref_font_hf_initializer },
1223 #ifndef G_OS_WIN32
1224 {N_("Copy and Paste"),GTK_STOCK_PASTE, "3", &pref_copypaste_page_initializer},
1225 #endif
1226 {N_("Sorting"), GTK_STOCK_SORT_ASCENDING, "3", &pref_sort_page_initializer },
1227 {N_("Screen"), GTK_STOCK_PREFERENCES, "5", &pref_screen_page_initializer },
1228 {N_("INitial CApitals"), NULL, "0", &pref_autocorrect_initialcaps_page_initializer },
1229 {N_("First Letter"), NULL, "0", &pref_autocorrect_firstletter_page_initializer },
1230 {NULL, NULL, NULL, NULL },
1233 typedef struct {
1234 gchar const *page;
1235 GtkTreePath *path;
1236 } page_search_t;
1238 static gboolean
1239 dialog_pref_select_page_search (GtkTreeModel *model,
1240 GtkTreePath *path,
1241 GtkTreeIter *iter,
1242 page_search_t *pst)
1244 gchar *page;
1245 gtk_tree_model_get (model, iter, ITEM_NAME, &page, -1);
1246 if (0 == strcmp (page, pst->page)) {
1247 g_free (page);
1248 pst->path = gtk_tree_path_copy (path);
1249 return TRUE;
1250 } else {
1251 g_free (page);
1252 return FALSE;
1256 static void
1257 dialog_pref_select_page (PrefState *state, gchar const *page)
1259 page_search_t pst = {NULL, NULL};
1261 if (page == NULL)
1262 page = "Tools";
1264 pst.page = _(page);
1265 gtk_tree_model_foreach (GTK_TREE_MODEL (state->store),
1266 (GtkTreeModelForeachFunc) dialog_pref_select_page_search,
1267 &pst);
1269 if (pst.path == NULL)
1270 pst.path = gtk_tree_path_new_first ();
1272 if (pst.path != NULL) {
1273 gtk_tree_view_set_cursor (state->view, pst.path, NULL, FALSE);
1274 gtk_tree_view_expand_row (state->view, pst.path, TRUE);
1275 gtk_tree_path_free (pst.path);
1279 static void
1280 cb_dialog_pref_selection_changed (GtkTreeSelection *selection,
1281 PrefState *state)
1283 GtkTreeIter iter;
1284 int page;
1286 if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
1287 gtk_tree_model_get (GTK_TREE_MODEL (state->store), &iter,
1288 PAGE_NUMBER, &page,
1289 -1);
1290 gtk_notebook_set_current_page (state->notebook, page);
1291 } else {
1292 dialog_pref_select_page (state, 0);
1296 static void
1297 cb_preferences_destroy (PrefState *state)
1299 if (state->store) {
1300 g_object_unref (state->store);
1301 state->store = NULL;
1303 if (state->gui != NULL) {
1304 g_object_unref (state->gui);
1305 state->gui = NULL;
1307 if (state->app_wb_removed_sig) {
1308 g_signal_handler_disconnect (gnm_app_get_app (),
1309 state->app_wb_removed_sig);
1310 state->app_wb_removed_sig = 0;
1312 g_object_set_data (gnm_app_get_app (), PREF_DIALOG_KEY, NULL);
1315 static void
1316 cb_close_clicked (PrefState *state)
1318 gtk_widget_destroy (GTK_WIDGET (state->dialog));
1321 static void
1322 cb_workbook_removed (PrefState *state)
1324 if (gnm_app_workbook_list () == NULL)
1325 cb_close_clicked (state);
1328 void
1329 dialog_preferences (WBCGtk *wbcg, gchar const *page)
1331 PrefState *state;
1332 GtkBuilder *gui;
1333 GtkWidget *w;
1334 gint i;
1335 GtkTreeViewColumn *column;
1336 GtkTreeSelection *selection;
1338 w = g_object_get_data (gnm_app_get_app (), PREF_DIALOG_KEY);
1339 if (w) {
1340 gtk_widget_show (w);
1341 gdk_window_raise (gtk_widget_get_window (w));
1342 return;
1345 gui = gnm_gtk_builder_load ("res:ui/preferences.ui", NULL, GO_CMD_CONTEXT (wbcg));
1346 if (gui == NULL)
1347 return;
1349 state = g_new0 (PrefState, 1);
1350 state->gui = gui;
1351 state->dialog = go_gtk_builder_get_widget (gui, "preferences");
1352 state->notebook = (GtkNotebook*)go_gtk_builder_get_widget (gui, "notebook");
1354 state->view = GTK_TREE_VIEW(go_gtk_builder_get_widget (gui, "itemlist"));
1355 state->store = gtk_tree_store_new (NUM_COLUMNS,
1356 GDK_TYPE_PIXBUF,
1357 G_TYPE_STRING,
1358 G_TYPE_INT);
1359 gtk_tree_view_set_model (state->view, GTK_TREE_MODEL(state->store));
1360 selection = gtk_tree_view_get_selection (state->view);
1361 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1362 column = gtk_tree_view_column_new_with_attributes ("",
1363 gtk_cell_renderer_pixbuf_new (),
1364 "pixbuf", ITEM_ICON,
1365 NULL);
1366 gtk_tree_view_append_column (state->view, column);
1367 column = gtk_tree_view_column_new_with_attributes ("",
1368 gtk_cell_renderer_text_new (),
1369 "text", ITEM_NAME,
1370 NULL);
1371 gtk_tree_view_append_column (state->view, column);
1372 gtk_tree_view_set_expander_column (state->view, column);
1374 g_signal_connect (selection,
1375 "changed",
1376 G_CALLBACK (cb_dialog_pref_selection_changed), state);
1378 g_signal_connect_swapped (G_OBJECT (go_gtk_builder_get_widget (gui, "close_button")),
1379 "clicked",
1380 G_CALLBACK (cb_close_clicked), state);
1382 gnm_init_help_button (
1383 go_gtk_builder_get_widget (state->gui, "help_button"),
1384 GNUMERIC_HELP_LINK_PREFERENCES);
1385 g_signal_connect_swapped (G_OBJECT (state->dialog),
1386 "destroy",
1387 G_CALLBACK(cb_preferences_destroy),
1388 state);
1389 g_object_set_data_full (G_OBJECT (state->dialog),
1390 "state", state,
1391 (GDestroyNotify)g_free);
1393 g_object_set_data (gnm_app_get_app (), PREF_DIALOG_KEY, state->dialog);
1395 state->app_wb_removed_sig =
1396 g_signal_connect_swapped (gnm_app_get_app (),
1397 "workbook_removed",
1398 G_CALLBACK (cb_workbook_removed),
1399 state);
1401 for (i = 0; page_info[i].page_initializer; i++) {
1402 const page_info_t *this_page = &page_info[i];
1403 GtkWidget *page_widget =
1404 this_page->page_initializer (state, NULL,
1405 state->notebook, i);
1406 gtk_notebook_append_page (state->notebook, page_widget, NULL);
1407 dialog_pref_add_item (state, this_page->page_name,
1408 this_page->icon_name, i,
1409 this_page->parent_path);
1412 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (state->store),
1413 ITEM_NAME, GTK_SORT_ASCENDING);
1415 go_gtk_nonmodal_dialog (wbcg_toplevel (wbcg),
1416 GTK_WINDOW (state->dialog));
1417 gtk_widget_show (GTK_WIDGET (state->dialog));
1419 dialog_pref_select_page (state, page);