1 /********************************************************************\
2  * dialog-options.c -- GNOME option handling                        *
3  * Copyright (C) 1998-2000 Linas Vepstas                            *
4  * Copyright (c) 2006 David Hampton <hampton@employees.org>         *
5  * Copyright (c) 2011 Robert Fewell                                 *
6  *                                                                  *
7  * This program is free software; you can redistribute it and/or    *
8  * modify it under the terms of the GNU General Public License as   *
9  * published by the Free Software Foundation; either version 2 of   *
10  * the License, or (at your option) any later version.              *
11  *                                                                  *
12  * This program is distributed in the hope that it will be useful,  *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
15  * GNU General Public License for more details.                     *
16  *                                                                  *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact:                        *
19  *                                                                  *
20  * Free Software Foundation           Voice:  +1-617-542-5942       *
21  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
22  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
23 \********************************************************************/
24 
25 #include <config.h>
26 
27 #include <gtk/gtk.h>
28 #include <gdk/gdk.h>
29 #include <glib/gi18n.h>
30 #include "swig-runtime.h"
31 
32 #include "gnc-tree-model-budget.h" //FIXME?
33 #include "gnc-budget.h"
34 
35 #include "dialog-options.h"
36 #include "dialog-utils.h"
37 #include "gnc-engine-guile.h"
38 #include "glib-guile.h"
39 #include "gnc-account-sel.h"
40 #include "gnc-tree-view-account.h"
41 #include "gnc-tree-model-account.h"
42 #include "gnc-commodity-edit.h"
43 #include "gnc-component-manager.h"
44 #include "gnc-general-select.h"
45 #include "gnc-currency-edit.h"
46 #include "gnc-date-edit.h"
47 #include "gnc-engine.h"
48 #include "gnc-prefs.h"
49 #include "gnc-gui-query.h"
50 #include "gnc-session.h"
51 #include "gnc-ui.h"
52 #include "gnc-guile-utils.h"
53 #include "option-util.h"
54 #include "guile-mappings.h"
55 #include "gnc-date-format.h"
56 #include "misc-gnome-utils.h"
57 
58 #define GNC_PREF_CLOCK_24H "clock-24h"
59 
60 #define FUNC_NAME G_STRFUNC
61 /* TODO: clean up "register-stocks" junk
62  */
63 
64 
65 /* This static indicates the debugging module that this .o belongs to.  */
66 static QofLogModule log_module = GNC_MOD_GUI;
67 
68 #define DIALOG_OPTIONS_CM_CLASS      "dialog-options"
69 #define DIALOG_BOOK_OPTIONS_CM_CLASS "dialog-book-options"
70 
71 #define GNC_PREFS_GROUP              "dialogs.options"
72 
73 /*
74  * Point where preferences switch control method from a set of
75  * notebook tabs to a list.
76  */
77 #define MAX_TAB_COUNT 6
78 
79 /* A pointer to the last selected filename */
80 #define LAST_SELECTION "last-selection"
81 
82 /* A Hash-table of GNCOptionDef_t keyed with option names. */
83 static GHashTable *optionTable = NULL;
84 
85 static int gain_loss_accounts_in_filter = 0;
86 
87 struct gnc_option_win
88 {
89     GtkWidget  * window;
90     GtkWidget  * notebook;
91     GtkWidget  * page_list_view;
92     GtkWidget  * page_list;
93 
94     gboolean toplevel;
95 
96     GNCOptionWinCallback apply_cb;
97     gpointer             apply_cb_data;
98 
99     GNCOptionWinCallback help_cb;
100     gpointer             help_cb_data;
101 
102     GNCOptionWinCallback close_cb;
103     gpointer             close_cb_data;
104 
105     /* Hold onto this for a complete reset */
106     GNCOptionDB *option_db;
107 
108     /* Hold on to this to unregister the right class */
109     const char *component_class;
110 
111     /* widget being destroyed */
112     gboolean destroyed;
113 };
114 
115 typedef enum
116 {
117     GNC_RD_WID_AB_BUTTON_POS = 0,
118     GNC_RD_WID_AB_WIDGET_POS,
119     GNC_RD_WID_REL_BUTTON_POS,
120     GNC_RD_WID_REL_WIDGET_POS
121 } GNCRdPositions;
122 
123 enum page_tree
124 {
125     PAGE_INDEX = 0,
126     PAGE_NAME,
127     NUM_COLUMNS
128 };
129 
130 typedef struct
131 {
132     GtkWidget *gnc_currency_radiobutton_0;
133     GtkWidget *gnc_currency_radiobutton_1;
134     GtkWidget *gnc_currency_radiobutton_2;
135     GtkWidget *book_currency_widget;
136     GtkWidget *default_cost_policy_widget;
137     GtkWidget *default_gain_loss_account_widget;
138     GtkWidget *book_currency_table;
139     GtkWidget *book_currency_vbox;
140     GtkWidget *gain_loss_account_del_button;
141     GtkWidget *gain_loss_account_table;
142     GtkWidget *default_gain_loss_account_text;
143     GNCOption *option;
144     Account   *prior_gain_loss_account;
145     gnc_commodity *retrieved_book_currency;
146 
147     SCM retrieved_policy_scm;
148     SCM retrieved_gain_loss_acct_guid_scm;
149 
150 } currency_accounting_data;
151 
152 static currency_accounting_data *book_currency_data = NULL;
153 
154 static GNCOptionWinCallback global_help_cb = NULL;
155 gpointer global_help_cb_data = NULL;
156 
157 static void gnc_options_dialog_reset_cb (GtkWidget * w, gpointer data);
158 void gnc_options_dialog_list_select_cb (GtkTreeSelection *selection,
159                                         gpointer data);
160 void gnc_set_default_cost_policy_widget (SCM list_symbol);
161 void gnc_set_default_gain_loss_account_widget (gnc_commodity *commodity);
162 void gnc_option_changed_book_currency_widget_cb (GtkWidget *widget);
163 void gnc_option_changed_gain_loss_account_widget_cb (GtkTreeSelection *selection,
164                                                      gpointer data);
165 void gnc_option_changed_gain_loss_account_del_button_widget_cb (GtkButton *button,
166                                                                 gpointer data);
167 static void component_close_handler (gpointer data);
168 
169 GtkWidget *
gnc_option_get_gtk_widget(GNCOption * option)170 gnc_option_get_gtk_widget (GNCOption *option)
171 {
172     return (GtkWidget *)gnc_option_get_widget (option);
173 }
174 
175 static void
gnc_options_dialog_changed_internal(GtkWidget * widget,gboolean sensitive)176 gnc_options_dialog_changed_internal (GtkWidget *widget, gboolean sensitive)
177 {
178     GtkButton *button = NULL;
179 
180     while (widget && !GTK_IS_WINDOW(widget))
181         widget = gtk_widget_get_parent (widget);
182     if (widget == NULL)
183         return;
184 
185     /* find the ok and cancel buttons, we know where they will be so do it
186        this way as opposed to using gtk_container_foreach, much less iteration */
187     if (GTK_IS_CONTAINER(widget))
188     {
189         GList *children = gtk_container_get_children (GTK_CONTAINER(widget));
190         for (GList *it = children; it; it = it->next)
191         {
192             if (GTK_IS_BOX(GTK_WIDGET(it->data)))
193             {
194                 GList *children = gtk_container_get_children (GTK_CONTAINER(it->data));
195                 for (GList *it = children; it; it = it->next)
196                 {
197                     if (GTK_IS_BUTTON_BOX(GTK_WIDGET(it->data)))
198                     {
199                         GList *children = gtk_container_get_children (GTK_CONTAINER(it->data));
200                         for (GList *it = children; it; it = it->next)
201                         {
202                             if (g_strcmp0 (gtk_widget_get_name (GTK_WIDGET(it->data)), "ok_button") == 0)
203                                 gtk_widget_set_sensitive (GTK_WIDGET(it->data), sensitive);
204 
205                             if (g_strcmp0 (gtk_widget_get_name (GTK_WIDGET(it->data)), "apply_button") == 0)
206                                 gtk_widget_set_sensitive (GTK_WIDGET(it->data), sensitive);
207 
208                             if (g_strcmp0 (gtk_widget_get_name (GTK_WIDGET(it->data)), "cancel_button") == 0)
209                                 button = GTK_BUTTON(it->data);
210                         }
211                         g_list_free (children);
212                     }
213                 }
214                 g_list_free (children);
215             }
216         }
217         g_list_free (children);
218     }
219 
220     if (button)
221     {
222         if (sensitive)
223            gtk_button_set_label (button, _("_Cancel"));
224         else
225            gtk_button_set_label (button, _("_Close"));
226     }
227 }
228 
229 void
gnc_options_dialog_changed(GNCOptionWin * win)230 gnc_options_dialog_changed (GNCOptionWin *win)
231 {
232     if (!win) return;
233 
234     gnc_options_dialog_changed_internal (win->window, TRUE);
235 }
236 
237 void
gnc_option_changed_widget_cb(GtkWidget * widget,GNCOption * option)238 gnc_option_changed_widget_cb (GtkWidget *widget, GNCOption *option)
239 {
240     gnc_option_set_changed (option, TRUE);
241     gnc_option_call_option_widget_changed_proc (option, FALSE);
242     gnc_options_dialog_changed_internal (widget, TRUE);
243 }
244 
245 void
gnc_option_changed_option_cb(GtkWidget * dummy,GNCOption * option)246 gnc_option_changed_option_cb (GtkWidget *dummy, GNCOption *option)
247 {
248     GtkWidget *widget = gnc_option_get_gtk_widget (option);
249     gnc_option_changed_widget_cb (widget, option);
250 }
251 
252 static void
gnc_date_option_set_select_method(GNCOption * option,gboolean use_absolute,gboolean set_buttons)253 gnc_date_option_set_select_method (GNCOption *option,
254                                    gboolean use_absolute,
255                                    gboolean set_buttons)
256 {
257     GList* widget_list;
258     GtkWidget *ab_button, *rel_button, *rel_widget, *ab_widget;
259     GtkWidget *widget;
260 
261     widget = gnc_option_get_gtk_widget (option);
262 
263     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
264     ab_button = g_list_nth_data (widget_list, GNC_RD_WID_AB_BUTTON_POS);
265     ab_widget = g_list_nth_data (widget_list, GNC_RD_WID_AB_WIDGET_POS);
266     rel_button = g_list_nth_data (widget_list, GNC_RD_WID_REL_BUTTON_POS);
267     rel_widget = g_list_nth_data (widget_list, GNC_RD_WID_REL_WIDGET_POS);
268     g_list_free (widget_list);
269 
270     if (use_absolute)
271     {
272         gtk_widget_set_sensitive (ab_widget, TRUE);
273         gtk_widget_set_sensitive (rel_widget, FALSE);
274         if (set_buttons)
275             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(ab_button), TRUE);
276     }
277     else
278     {
279         gtk_widget_set_sensitive (rel_widget, TRUE);
280         gtk_widget_set_sensitive (ab_widget, FALSE);
281         if (set_buttons)
282             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(rel_button), TRUE);
283     }
284 }
285 
286 static void
gnc_rd_option_ab_set_cb(GtkWidget * widget,gpointer * raw_option)287 gnc_rd_option_ab_set_cb (GtkWidget *widget, gpointer *raw_option)
288 {
289     GNCOption *option = (GNCOption *) raw_option;
290     gnc_date_option_set_select_method (option, TRUE, FALSE);
291     gnc_option_changed_option_cb (widget, option);
292 }
293 
294 static void
gnc_rd_option_rel_set_cb(GtkWidget * widget,gpointer * raw_option)295 gnc_rd_option_rel_set_cb (GtkWidget *widget, gpointer *raw_option)
296 {
297     GNCOption *option = (GNCOption *) raw_option;
298     gnc_date_option_set_select_method (option, FALSE, FALSE);
299     gnc_option_changed_option_cb (widget, option);
300     return;
301 }
302 
303 static void
gnc_image_option_update_preview_cb(GtkFileChooser * chooser,GNCOption * option)304 gnc_image_option_update_preview_cb (GtkFileChooser *chooser,
305                                     GNCOption *option)
306 {
307     gchar *filename;
308     GtkImage *image;
309     GdkPixbuf *pixbuf;
310     gboolean have_preview;
311 
312     g_return_if_fail (chooser != NULL);
313 
314     ENTER("chooser %p, option %p", chooser, option);
315     filename = gtk_file_chooser_get_preview_filename (chooser);
316     DEBUG("chooser preview name is %s.", filename ? filename : "(null)");
317     if (filename == NULL)
318     {
319         filename = g_strdup (g_object_get_data (G_OBJECT(chooser), LAST_SELECTION));
320         DEBUG("using last selection of %s", filename ? filename : "(null)");
321         if (filename == NULL)
322         {
323             LEAVE("no usable name");
324             return;
325         }
326     }
327 
328     image = GTK_IMAGE(gtk_file_chooser_get_preview_widget (chooser));
329     pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);
330     g_free (filename);
331     have_preview = (pixbuf != NULL);
332 
333     gtk_image_set_from_pixbuf (image, pixbuf);
334     if (pixbuf)
335         g_object_unref (pixbuf);
336 
337     gtk_file_chooser_set_preview_widget_active (chooser, have_preview);
338     LEAVE("preview visible is %d", have_preview);
339 }
340 
341 static void
gnc_image_option_selection_changed_cb(GtkFileChooser * chooser,GNCOption * option)342 gnc_image_option_selection_changed_cb (GtkFileChooser *chooser,
343                                        GNCOption *option)
344 {
345     gchar *filename = gtk_file_chooser_get_preview_filename (chooser);
346     if (!filename)
347         return;
348     g_object_set_data_full (G_OBJECT(chooser), LAST_SELECTION, filename, g_free);
349 }
350 
351 /********************************************************************\
352  * gnc_option_set_ui_value_internal                                 *
353  *   sets the GUI representation of an option with either its       *
354  *   current guile value, or its default value                      *
355  *                                                                  *
356  * Args: option      - option structure containing option           *
357  *       use_default - if true, use the default value, otherwise    *
358  *                     use the current value                        *
359  * Return: nothing                                                  *
360 \********************************************************************/
361 static void
gnc_option_set_ui_value_internal(GNCOption * option,gboolean use_default)362 gnc_option_set_ui_value_internal (GNCOption *option, gboolean use_default)
363 {
364     gboolean bad_value = FALSE;
365     GtkWidget *widget;
366     char *type;
367     SCM getter;
368     SCM value;
369     GNCOptionDef_t *option_def;
370 
371     widget = gnc_option_get_gtk_widget (option);
372     if (!widget)
373         return;
374 
375     type = gnc_option_type (option);
376 
377     if (use_default)
378     {
379         SCM opt_getter = gnc_option_getter (option);
380         SCM opt_value = scm_call_0 (opt_getter);
381         SCM def_value;
382 
383         getter = gnc_option_default_getter (option);
384         def_value = scm_call_0 (getter);
385 
386         // only set changed if the values have changed
387         if (!scm_is_true (scm_equal_p (opt_value, def_value)))
388             gnc_option_set_changed (option, TRUE);
389     }
390     else
391         getter = gnc_option_getter (option);
392 
393     value = scm_call_0 (getter);
394 
395     option_def = gnc_options_ui_get_option (type);
396     if (option_def && option_def->set_value)
397     {
398         bad_value = option_def->set_value (option, use_default, widget, value);
399         if (bad_value)
400         {
401             gchar *name = gnc_option_name (option);
402             gchar *val = scm_to_locale_string (scm_object_to_string
403                                                (value, scm_c_eval_string ("write")));
404             PERR ("option '%s' bad value '%s'\n", name, val);
405             g_free (name);
406             g_free (val);
407         }
408     }
409     else
410         PERR("Unknown type. Ignoring.\n");
411 
412     free (type);
413 }
414 
415 /********************************************************************\
416  * gnc_option_get_ui_value_internal                                 *
417  *   returns the SCM representation of the GUI option value         *
418  *                                                                  *
419  * Args: option - option structure containing option                *
420  * Return: SCM handle to GUI option value                           *
421 \********************************************************************/
422 static SCM
gnc_option_get_ui_value_internal(GNCOption * option)423 gnc_option_get_ui_value_internal (GNCOption *option)
424 {
425     SCM result = SCM_UNDEFINED;
426     GtkWidget *widget;
427     char *type;
428     GNCOptionDef_t *option_def;
429 
430     widget = gnc_option_get_gtk_widget (option);
431     if (!widget)
432         return result;
433 
434     type = gnc_option_type (option);
435 
436     option_def = gnc_options_ui_get_option (type);
437 
438     if (option_def && option_def->get_value)
439         result = option_def->get_value (option, widget);
440     else
441         PERR("Unknown type for refresh. Ignoring.\n");
442 
443     free (type);
444 
445     return result;
446 }
447 
448 /********************************************************************\
449  * gnc_option_set_selectable_internal                               *
450  *   Change the selectable state of the widget that represents a    *
451  *   GUI option.                                                    *
452  *                                                                  *
453  * Args: option      - option to change widget state for            *
454  *       selectable  - if false, update the widget so that it       *
455  *                     cannot be selected by the user.  If true,    *
456  *                     update the widget so that it can be selected.*
457  * Return: nothing                                                  *
458 \********************************************************************/
459 static void
gnc_option_set_selectable_internal(GNCOption * option,gboolean selectable)460 gnc_option_set_selectable_internal (GNCOption *option, gboolean selectable)
461 {
462     GtkWidget *widget;
463 
464     widget = gnc_option_get_gtk_widget (option);
465     if (!widget)
466         return;
467 
468     gtk_widget_set_sensitive (widget, selectable);
469 }
470 
471 static void
gnc_option_default_cb(GtkWidget * widget,GNCOption * option)472 gnc_option_default_cb (GtkWidget *widget, GNCOption *option)
473 {
474     gnc_option_set_ui_value (option, TRUE);
475     gnc_option_set_changed (option, TRUE);
476     gnc_options_dialog_changed_internal (widget, TRUE);
477 }
478 
479 static void
gnc_option_show_hidden_toggled_cb(GtkWidget * widget,GNCOption * option)480 gnc_option_show_hidden_toggled_cb (GtkWidget *widget, GNCOption* option)
481 {
482     AccountViewInfo avi;
483     GncTreeViewAccount *tree_view;
484 
485     tree_view = GNC_TREE_VIEW_ACCOUNT(gnc_option_get_gtk_widget (option));
486     gnc_tree_view_account_get_view_info (tree_view, &avi);
487     avi.show_hidden = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
488     gnc_tree_view_account_set_view_info (tree_view, &avi);
489     gnc_option_changed_widget_cb (widget, option);
490 }
491 
492 static void
gnc_option_multichoice_cb(GtkWidget * widget,gpointer data)493 gnc_option_multichoice_cb (GtkWidget *widget, gpointer data)
494 {
495     GNCOption *option = data;
496     gnc_option_changed_widget_cb (widget, option);
497 }
498 
499 static void
gnc_option_radiobutton_cb(GtkWidget * w,gpointer data)500 gnc_option_radiobutton_cb (GtkWidget *w, gpointer data)
501 {
502     GNCOption *option = data;
503     GtkWidget *widget;
504     gpointer _current, _new_value;
505     gint current, new_value;
506 
507     widget = gnc_option_get_gtk_widget (option);
508 
509     _current = g_object_get_data (G_OBJECT(widget), "gnc_radiobutton_index");
510     current = GPOINTER_TO_INT(_current);
511 
512     _new_value = g_object_get_data (G_OBJECT(w), "gnc_radiobutton_index");
513     new_value = GPOINTER_TO_INT(_new_value);
514 
515     if (current == new_value)
516         return;
517 
518     g_object_set_data (G_OBJECT(widget), "gnc_radiobutton_index",
519                        GINT_TO_POINTER(new_value));
520     gnc_option_changed_widget_cb (widget, option);
521 }
522 
523 static gboolean
gnc_gain_loss_account_view_filter(Account * account,gpointer data)524 gnc_gain_loss_account_view_filter (Account  *account, gpointer  data)
525 {
526     GNCAccountType type = xaccAccountGetType (account);
527 
528     /* gain/loss accts must be an Income or Expense accts and not hidden;
529        placeholder accounts must be included, irrespective of their currency,
530        so their children are available to be considered */
531     if (((type == ACCT_TYPE_INCOME) || (type == ACCT_TYPE_EXPENSE)) &&
532         (!xaccAccountIsHidden(account)))
533     {
534         if (xaccAccountGetPlaceholder (account))
535         {
536             GList *placeholder_children = gnc_account_get_children (account);
537 
538             if (placeholder_children)
539             { /* determine if any children qualify; just need one but don't
540                  double count in gain_loss_accounts_in_filter */
541                 int saved_gain_loss_accounts_in_filter =
542                                                 gain_loss_accounts_in_filter;
543                 gboolean child_pass_filter = FALSE;
544                 GList *l = NULL;
545                 for (l = placeholder_children; l != NULL; l = l->next)
546                 {
547                     Account  *child_account = l->data;
548                     child_pass_filter =
549                         gnc_gain_loss_account_view_filter (child_account, NULL);
550                     if (child_pass_filter)
551                         break;
552                 }
553                 g_list_free (placeholder_children);
554                 gain_loss_accounts_in_filter =
555                                            saved_gain_loss_accounts_in_filter;
556                 return child_pass_filter;
557             }
558             else return FALSE; // no children, not interested
559         }
560         else
561         {
562             gnc_commodity *commodity = NULL;
563 
564             /* gain/loss accts must be in book-currency; if a book currency has been
565                specified in the widget, use it to filter */
566             if (gtk_combo_box_get_active (GTK_COMBO_BOX(
567                                           book_currency_data->book_currency_widget)) != -1)
568                 commodity = gnc_currency_edit_get_currency (
569                                 GNC_CURRENCY_EDIT(
570                                     book_currency_data->book_currency_widget));
571             if (commodity)
572             {
573                 if (gnc_commodity_equal (xaccAccountGetCommodity (account),
574                                          commodity))
575                 {
576                     gain_loss_accounts_in_filter++;
577                     return TRUE;
578                 }
579                 else return FALSE;
580             }
581             /* else use the default currency */
582             else if (gnc_commodity_equal (xaccAccountGetCommodity (account),
583                                           gnc_default_currency ()))
584             {
585                 gain_loss_accounts_in_filter++;
586                 return TRUE;
587             }
588             else return FALSE;
589         }
590     }
591     else return FALSE;
592 }
593 
594 static gboolean
gnc_gain_loss_account_all_fail_filter(Account * account,gpointer data)595 gnc_gain_loss_account_all_fail_filter (Account  *account, gpointer  data)
596 {
597     return FALSE;
598 }
599 
600 void
gnc_set_default_cost_policy_widget(SCM list_symbol)601 gnc_set_default_cost_policy_widget (SCM list_symbol)
602 {
603     GList *list_of_policies = gnc_get_valid_policy_list ();
604 
605     if (list_of_policies)
606     {
607         GList *l = NULL;
608         gint i = 0;
609         for (l = list_of_policies; l != NULL; l = l->next)
610         {
611             GNCPolicy *pcy = l->data;
612             if (g_strcmp0 (PolicyGetName (pcy),
613                            gnc_scm_symbol_to_locale_string (list_symbol))
614                            == 0)
615             {
616                 gtk_combo_box_set_active (
617                     GTK_COMBO_BOX(
618                         book_currency_data->default_cost_policy_widget), i);
619             }
620             i++;
621         }
622         g_list_free (list_of_policies);
623     }
624     else
625     {
626         gtk_combo_box_set_active (
627             GTK_COMBO_BOX(book_currency_data->default_cost_policy_widget), -1);
628     }
629 }
630 
631 void
gnc_set_default_gain_loss_account_widget(gnc_commodity * commodity)632 gnc_set_default_gain_loss_account_widget (gnc_commodity *commodity)
633 {
634     if (book_currency_data->default_gain_loss_account_widget)
635     {
636         gtk_widget_destroy (
637                     book_currency_data->default_gain_loss_account_widget);
638         book_currency_data->default_gain_loss_account_widget = NULL;
639         book_currency_data->prior_gain_loss_account = NULL;
640         gain_loss_accounts_in_filter = 0;
641     }
642     if (book_currency_data->gain_loss_account_del_button)
643     {
644         gtk_widget_destroy (
645                     book_currency_data->gain_loss_account_del_button);
646         book_currency_data->gain_loss_account_del_button = NULL;
647     }
648     if (book_currency_data->default_gain_loss_account_text)
649     {
650         gtk_widget_destroy (
651                     book_currency_data->default_gain_loss_account_text);
652         book_currency_data->default_gain_loss_account_text = NULL;
653     }
654     if (gnc_is_new_book ())
655     {
656         book_currency_data->default_gain_loss_account_text =
657                     gtk_label_new ( _("Because no accounts have " \
658                         "been set up yet, you will need to return to this " \
659                         "dialog (via File->Properties), after account setup, " \
660                         "if you want to set a default gain/loss account.") );
661 
662         gtk_label_set_line_wrap (GTK_LABEL(book_currency_data->default_gain_loss_account_text), TRUE);
663 
664         gtk_grid_attach (GTK_GRID(book_currency_data->gain_loss_account_table),
665                                   book_currency_data->default_gain_loss_account_text, 0, 1, 2, 1);
666     }
667     else
668     {
669         GtkTreeSelection *selection = NULL;
670         book_currency_data->default_gain_loss_account_widget =
671                             GTK_WIDGET(gnc_tree_view_account_new (FALSE));
672         gain_loss_accounts_in_filter = 0;
673         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(
674                         book_currency_data->default_gain_loss_account_widget));
675         if (!commodity) // that means not book currency
676         {
677             /* set the default_gain_loss_account_widget to be blank with a
678                no-acct filter */
679             gnc_tree_view_account_set_filter (GNC_TREE_VIEW_ACCOUNT(
680                         book_currency_data->default_gain_loss_account_widget),
681                         gnc_gain_loss_account_all_fail_filter,
682                         NULL,  /* user data */
683                         NULL  /* destroy callback */ );
684             gtk_tree_selection_unselect_all (selection);
685         }
686         else // that means book currency
687         {
688             /* see if there are any accounts after filter */
689             gnc_tree_view_account_set_filter (GNC_TREE_VIEW_ACCOUNT(
690                         book_currency_data->default_gain_loss_account_widget),
691                         gnc_gain_loss_account_view_filter,
692                         NULL, /* user data */
693                         NULL  /* destroy callback */);
694             if (gain_loss_accounts_in_filter > 0)
695             {   /* there are accounts; find out if one is selected */
696                 Account *gain_loss_account = NULL;
697                 Account *selected_account = NULL;
698                 GtkTreeViewColumn *col;
699 
700                 book_currency_data->gain_loss_account_del_button =
701                         gtk_button_new_with_label ( _("Select no account") );
702 
703                 g_signal_connect (GTK_BUTTON(
704                         book_currency_data->gain_loss_account_del_button),
705                         "clicked",
706                         G_CALLBACK(
707                             gnc_option_changed_gain_loss_account_del_button_widget_cb),
708                         NULL);
709                 gtk_grid_attach (GTK_GRID(book_currency_data->gain_loss_account_table),
710                                           book_currency_data->gain_loss_account_del_button, 1, 0, 1, 1);
711 
712                 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(
713                         book_currency_data->default_gain_loss_account_widget),
714                         TRUE);
715                 col = gnc_tree_view_add_text_column (GNC_TREE_VIEW(
716                         book_currency_data->default_gain_loss_account_widget),
717                          _("Currency"), /* title */
718                         "commodity", /* pref name */
719                         NULL,
720                         "Currency--", /* sizing text */
721                         GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY,
722                         GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
723                         NULL);
724                 g_object_set_data (G_OBJECT(col), DEFAULT_VISIBLE,
725                                    GINT_TO_POINTER(1));
726 
727                 // add the color background data function to the column
728                 gnc_tree_view_account_column_add_color (GNC_TREE_VIEW_ACCOUNT(
729                          book_currency_data->default_gain_loss_account_widget), col);
730 
731                 col = gnc_tree_view_add_toggle_column (GNC_TREE_VIEW(
732                         book_currency_data->default_gain_loss_account_widget),
733                         _("Placeholder"),
734                         C_("Column header for 'Placeholder'", "P"),
735                         "placeholder",
736                         GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER,
737                         GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
738                         NULL,
739                         NULL);
740                 g_object_set_data (G_OBJECT(col), DEFAULT_VISIBLE,
741                     GINT_TO_POINTER(1));
742 
743                 // add the color background data function to the column
744                 gnc_tree_view_account_column_add_color (GNC_TREE_VIEW_ACCOUNT(
745                          book_currency_data->default_gain_loss_account_widget), col);
746 
747                 gnc_tree_view_configure_columns (GNC_TREE_VIEW(
748                         book_currency_data->default_gain_loss_account_widget));
749                 gnc_tree_view_set_show_column_menu (GNC_TREE_VIEW(
750                         book_currency_data->default_gain_loss_account_widget),
751                         FALSE);
752                 if (book_currency_data->retrieved_gain_loss_acct_guid_scm &&
753                     (scm_is_string (
754                         book_currency_data->retrieved_gain_loss_acct_guid_scm)))
755                 {
756                     GncGUID *guid= g_new (GncGUID, 1);
757 
758                     if (string_to_guid (
759                         gnc_scm_to_utf8_string (
760                         book_currency_data->retrieved_gain_loss_acct_guid_scm),
761                         guid))
762                     gain_loss_account =
763                                 xaccAccountLookup (guid, gnc_get_current_book ());
764                     g_free (guid);
765                 }
766                 if (gain_loss_account)
767                 {
768                     (gnc_tree_view_account_set_selected_account
769                         (GNC_TREE_VIEW_ACCOUNT(
770                           book_currency_data->default_gain_loss_account_widget),
771                         gain_loss_account));
772                     selected_account =
773                         gnc_tree_view_account_get_selected_account (
774                             GNC_TREE_VIEW_ACCOUNT(
775                             book_currency_data->default_gain_loss_account_widget));
776                 }
777                 if (selected_account)
778                 {
779                     book_currency_data->prior_gain_loss_account =
780                         selected_account;
781                     gtk_widget_set_sensitive (
782                         book_currency_data->gain_loss_account_del_button,
783                         TRUE);
784                 }
785                 else /* none selected */
786                 {
787                     gtk_tree_selection_unselect_all (selection);
788                     gtk_widget_set_sensitive (
789                         book_currency_data->gain_loss_account_del_button,
790                         FALSE);
791                 }
792             }
793             else /* no accts in widget?; replace widget with text */
794             {
795                 gtk_widget_destroy (
796                     book_currency_data->default_gain_loss_account_widget);
797                 book_currency_data->default_gain_loss_account_widget = NULL;
798                 book_currency_data->prior_gain_loss_account = NULL;
799                 gain_loss_accounts_in_filter = 0;
800                 book_currency_data->default_gain_loss_account_text =
801                     gtk_label_new ( _("There are no income " \
802                         "or expense accounts of the specified\n" \
803                         "book currency; you will have to return to this " \
804                         "dialog\n(via File->Properties), after account setup, " \
805                         "to select a\ndefault gain/loss account.") );
806                 gtk_grid_attach (GTK_GRID(book_currency_data->gain_loss_account_table),
807                                           book_currency_data->default_gain_loss_account_text, 0, 1, 2, 1);
808             }
809         }
810         if (book_currency_data->default_gain_loss_account_widget)
811         {
812             gtk_widget_set_hexpand (GTK_WIDGET(book_currency_data->default_gain_loss_account_widget), TRUE);
813             g_signal_connect (G_OBJECT(selection),
814                               "changed",
815                               G_CALLBACK(gnc_option_changed_gain_loss_account_widget_cb),
816                               NULL);
817             gtk_grid_attach (GTK_GRID(book_currency_data->gain_loss_account_table),
818                                       book_currency_data->default_gain_loss_account_widget, 0, 1, 2, 1);
819         }
820     }
821 }
822 
823 void
gnc_option_changed_book_currency_widget_cb(GtkWidget * widget)824 gnc_option_changed_book_currency_widget_cb (GtkWidget *widget)
825 {
826     /* Once the book currency widget is set, need to set the
827        default_gain_loss_account_widget and/or del-button or text*/
828     if (gtk_combo_box_get_active (GTK_COMBO_BOX(book_currency_data->book_currency_widget)) != -1)
829     {
830         gnc_commodity *commodity = gnc_currency_edit_get_currency (
831                                        GNC_CURRENCY_EDIT(
832                                        book_currency_data->book_currency_widget));
833 
834         gnc_set_default_gain_loss_account_widget (commodity);
835     }
836     gtk_widget_show_all (book_currency_data->book_currency_vbox);
837     gnc_option_changed_widget_cb (widget, book_currency_data->option);
838 }
839 
840 void
gnc_option_changed_gain_loss_account_widget_cb(GtkTreeSelection * selection,gpointer data)841 gnc_option_changed_gain_loss_account_widget_cb (GtkTreeSelection *selection,
842                                                 gpointer data)
843 {
844     Account *account = NULL;
845     gboolean new_eq_prior_acct = FALSE;
846 
847     g_return_if_fail (book_currency_data->default_gain_loss_account_widget);
848     account = gnc_tree_view_account_get_selected_account (
849                     GNC_TREE_VIEW_ACCOUNT(
850                         book_currency_data->default_gain_loss_account_widget));
851     if (account && book_currency_data->prior_gain_loss_account)
852         new_eq_prior_acct = xaccAccountEqual (account,
853                                 book_currency_data->prior_gain_loss_account,
854                                 TRUE);
855     if (account && (!new_eq_prior_acct))
856     { /* a new account has been selected */
857         if (!xaccAccountGetPlaceholder (account))
858         {
859             GtkWidget *option_widget =
860                         gnc_option_get_gtk_widget (book_currency_data->option);
861             book_currency_data->prior_gain_loss_account = account;
862             gtk_widget_set_sensitive (
863                     book_currency_data->gain_loss_account_del_button, TRUE);
864             gtk_widget_show_all (book_currency_data->book_currency_vbox);
865             gnc_option_changed_option_cb (option_widget, book_currency_data->option);
866         }
867         else /*  new account, but placeholder */
868         {
869             const char *message = _("The account %s is a placeholder account " \
870                 "and does not allow transactions. " \
871             "Please choose a different account.");
872 
873             gnc_error_dialog (gnc_ui_get_gtk_window (book_currency_data->default_gain_loss_account_widget),
874                   message, xaccAccountGetName (account));
875             if (book_currency_data->prior_gain_loss_account)
876             {
877                 (gnc_tree_view_account_set_selected_account
878                     (GNC_TREE_VIEW_ACCOUNT(
879                           book_currency_data->default_gain_loss_account_widget),
880                         book_currency_data->prior_gain_loss_account));
881             }
882             else
883             {
884                 gtk_tree_selection_unselect_all (selection);
885             }
886         }
887     }
888     else /* a new account has not been selected */
889     {
890         if (book_currency_data->prior_gain_loss_account == NULL)
891         {
892             gtk_tree_selection_unselect_all (selection);
893             if (book_currency_data->gain_loss_account_del_button)
894             {
895                 gtk_widget_set_sensitive (
896                     book_currency_data->gain_loss_account_del_button, FALSE);
897             }
898         }
899     }
900 }
901 
902 void
gnc_option_changed_gain_loss_account_del_button_widget_cb(GtkButton * button,gpointer data)903 gnc_option_changed_gain_loss_account_del_button_widget_cb (GtkButton *button,
904                                                            gpointer data)
905 {
906     GtkTreeSelection *selection = NULL;
907     GtkWidget *option_widget =
908                         gnc_option_get_gtk_widget (book_currency_data->option);
909 
910     g_return_if_fail (book_currency_data->default_gain_loss_account_widget);
911     g_return_if_fail (book_currency_data->gain_loss_account_del_button);
912 
913     selection = gtk_tree_view_get_selection (
914                     GTK_TREE_VIEW(
915                         book_currency_data->default_gain_loss_account_widget));
916     gtk_tree_selection_unselect_all (selection);
917     book_currency_data->prior_gain_loss_account = NULL;
918     gtk_widget_set_sensitive (
919                     book_currency_data->gain_loss_account_del_button, FALSE);
920     gnc_option_changed_option_cb (option_widget, book_currency_data->option);
921 }
922 
923 static void
gnc_option_currency_accounting_non_book_cb(GtkWidget * widget,gpointer data)924 gnc_option_currency_accounting_non_book_cb (GtkWidget *widget, gpointer data)
925 {
926     gnc_currency_edit_clear_display (GNC_CURRENCY_EDIT(
927                                      book_currency_data->book_currency_widget));
928     gtk_combo_box_set_active (GTK_COMBO_BOX(
929                               book_currency_data->default_cost_policy_widget),
930                               -1);
931     gnc_set_default_gain_loss_account_widget (NULL);
932     gtk_widget_show_all (book_currency_data->book_currency_vbox);
933     gtk_widget_set_sensitive (book_currency_data->book_currency_vbox, FALSE);
934     gnc_option_radiobutton_cb (widget, (gpointer) book_currency_data->option);
935 }
936 
937 static void
gnc_option_currency_accounting_book_cb(GtkWidget * widget,gpointer data)938 gnc_option_currency_accounting_book_cb (GtkWidget *widget, gpointer data)
939 {
940     SCM list_symbol =
941             gnc_currency_accounting_option_get_default_policy (
942                                                     book_currency_data->option);
943     SCM curr_scm = gnc_currency_accounting_option_get_default_currency (
944                                                     book_currency_data->option);
945     gnc_commodity *commodity = gnc_scm_to_commodity (curr_scm);
946 
947     if (book_currency_data->retrieved_book_currency)
948     {
949         gnc_currency_edit_set_currency
950                 (GNC_CURRENCY_EDIT(book_currency_data->book_currency_widget),
951                  book_currency_data->retrieved_book_currency);
952     }
953     else if (commodity)
954     {
955         gnc_currency_edit_set_currency
956                 (GNC_CURRENCY_EDIT(book_currency_data->book_currency_widget),
957                  commodity);
958     }
959     else
960     {
961         gnc_currency_edit_set_currency
962                 (GNC_CURRENCY_EDIT(book_currency_data->book_currency_widget),
963                  gnc_default_currency());
964     }
965     if (book_currency_data->retrieved_policy_scm)
966     {
967         gnc_set_default_cost_policy_widget (
968                                       book_currency_data->retrieved_policy_scm);
969     }
970     else
971     {
972         gnc_set_default_cost_policy_widget (list_symbol);
973     }
974     gtk_widget_show_all (book_currency_data->book_currency_vbox);
975     gtk_widget_set_sensitive (book_currency_data->book_currency_vbox, TRUE);
976     gnc_option_radiobutton_cb (widget, (gpointer) book_currency_data->option);
977 }
978 
979 static GtkWidget *
gnc_option_create_date_widget(GNCOption * option)980 gnc_option_create_date_widget (GNCOption *option)
981 {
982     GtkWidget * box = NULL;
983     GtkWidget *rel_button = NULL, *ab_button = NULL;
984     GtkWidget *rel_widget = NULL, *ab_widget = NULL;
985     GtkWidget *entry;
986     gboolean show_time, use24;
987     char *type;
988     int num_values;
989 
990     type = gnc_option_date_option_get_subtype (option);
991     show_time = gnc_option_show_time (option);
992     use24 = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_CLOCK_24H);
993 
994     if (g_strcmp0 (type, "relative") != 0)
995     {
996         ab_widget = gnc_date_edit_new (time (NULL), show_time, use24);
997         entry = GNC_DATE_EDIT(ab_widget)->date_entry;
998         g_signal_connect (G_OBJECT(entry), "changed",
999                           G_CALLBACK(gnc_option_changed_option_cb), option);
1000         if (show_time)
1001         {
1002             entry = GNC_DATE_EDIT(ab_widget)->time_entry;
1003             g_signal_connect (G_OBJECT(entry), "changed",
1004                               G_CALLBACK(gnc_option_changed_option_cb), option);
1005         }
1006     }
1007 
1008     if (g_strcmp0 (type, "absolute") != 0)
1009     {
1010         int i;
1011         num_values = gnc_option_num_permissible_values (option);
1012 
1013         g_return_val_if_fail (num_values >= 0, NULL);
1014 
1015         {
1016             GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1017             GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
1018             GtkTreeIter  iter;
1019             char *itemstring;
1020 
1021             /* Add values to the list store */
1022             for (i = 0; i < num_values; i++)
1023             {
1024                 itemstring = gnc_option_permissible_value_name (option, i);
1025                 gtk_list_store_append (store, &iter);
1026                 gtk_list_store_set (store, &iter, 0, itemstring, -1);
1027                 if (itemstring)
1028                     g_free (itemstring);
1029             }
1030             /* Create the new Combo and add the store */
1031             rel_widget = GTK_WIDGET(gtk_combo_box_new_with_model (GTK_TREE_MODEL(store)));
1032 
1033             gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(rel_widget), renderer, TRUE);
1034             gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(rel_widget),
1035                                            renderer, "text", 0);
1036             g_object_unref (store);
1037 
1038             g_signal_connect (G_OBJECT(rel_widget), "changed",
1039                               G_CALLBACK(gnc_option_multichoice_cb), option);
1040         }
1041     }
1042 
1043     if (g_strcmp0 (type, "absolute") == 0)
1044     {
1045         free (type);
1046         gnc_option_set_widget (option, ab_widget);
1047         return ab_widget;
1048     }
1049     else if (g_strcmp0 (type, "relative") == 0)
1050     {
1051         gnc_option_set_widget (option, rel_widget);
1052         free (type);
1053 
1054         return rel_widget;
1055     }
1056     else if (g_strcmp0 (type, "both") == 0)
1057     {
1058         box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
1059         gtk_box_set_homogeneous (GTK_BOX(box), FALSE);
1060 
1061         ab_button = gtk_radio_button_new (NULL);
1062         g_signal_connect (G_OBJECT(ab_button), "toggled",
1063                           G_CALLBACK(gnc_rd_option_ab_set_cb), option);
1064 
1065         rel_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON(ab_button));
1066         g_signal_connect (G_OBJECT(rel_button), "toggled",
1067                           G_CALLBACK(gnc_rd_option_rel_set_cb), option);
1068 
1069         gtk_box_pack_start (GTK_BOX(box), ab_button, FALSE, FALSE, 0);
1070         gtk_box_pack_start (GTK_BOX(box), ab_widget, FALSE, FALSE, 0);
1071         gtk_box_pack_start (GTK_BOX(box), rel_button, FALSE, FALSE, 0);
1072         gtk_box_pack_start (GTK_BOX(box), rel_widget, FALSE, FALSE, 0);
1073 
1074         free (type);
1075 
1076         gnc_option_set_widget (option, box);
1077 
1078         return box;
1079     }
1080     else /* can't happen */
1081         return NULL;
1082 }
1083 
1084 static GtkWidget *
gnc_option_create_budget_widget(GNCOption * option)1085 gnc_option_create_budget_widget (GNCOption *option)
1086 {
1087     GtkTreeModel *tm;
1088     GtkComboBox *cb;
1089     GtkCellRenderer *cr;
1090 
1091     tm = gnc_tree_model_budget_new (gnc_get_current_book());
1092     cb = GTK_COMBO_BOX(gtk_combo_box_new_with_model (tm));
1093     g_object_unref (tm);
1094     cr = gtk_cell_renderer_text_new ();
1095     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(cb), cr, TRUE);
1096 
1097     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(cb), cr, "text",
1098                                     BUDGET_NAME_COLUMN, NULL);
1099     return GTK_WIDGET(cb);
1100 }
1101 
1102 static GtkWidget *
gnc_option_create_multichoice_widget(GNCOption * option)1103 gnc_option_create_multichoice_widget (GNCOption *option)
1104 {
1105     GtkWidget *widget;
1106     int num_values;
1107     int i;
1108 
1109     num_values = gnc_option_num_permissible_values (option);
1110 
1111     g_return_val_if_fail (num_values >= 0, NULL);
1112 
1113     {
1114         GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
1115         GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
1116         GtkTreeIter  iter;
1117         char *itemstring;
1118 
1119         /* Add values to the list store */
1120         for (i = 0; i < num_values; i++)
1121         {
1122             itemstring = gnc_option_permissible_value_name (option, i);
1123 
1124             gtk_list_store_append (store, &iter);
1125             gtk_list_store_set (store, &iter, 0,
1126                                 (itemstring && *itemstring) ? _(itemstring) : "", -1);
1127 
1128             if (itemstring)
1129                 g_free (itemstring);
1130         }
1131         /* Create the new Combo and add the store */
1132         widget = GTK_WIDGET(gtk_combo_box_new_with_model (GTK_TREE_MODEL(store)));
1133 
1134         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(widget), renderer, TRUE);
1135         gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(widget),
1136                                        renderer, "text", 0);
1137         g_object_unref (store);
1138 
1139         g_signal_connect (G_OBJECT(widget), "changed",
1140                           G_CALLBACK(gnc_option_multichoice_cb), option);
1141     }
1142     return widget;
1143 }
1144 
1145 static GtkWidget *
gnc_option_create_radiobutton_widget(char * name,GNCOption * option)1146 gnc_option_create_radiobutton_widget (char *name, GNCOption *option)
1147 {
1148     GtkWidget *frame, *box;
1149     GtkWidget *widget = NULL;
1150     int num_values;
1151     char *label;
1152     int i;
1153 
1154     num_values = gnc_option_num_permissible_values (option);
1155 
1156     g_return_val_if_fail (num_values >= 0, NULL);
1157 
1158     /* Create our button frame */
1159     frame = gtk_frame_new (name);
1160 
1161     /* Create the button box */
1162     box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
1163     gtk_box_set_homogeneous (GTK_BOX(box), FALSE);
1164     gtk_container_add (GTK_CONTAINER(frame), box);
1165 
1166     /* Iterate over the options and create a radio button for each one */
1167     for (i = 0; i < num_values; i++)
1168     {
1169         label = gnc_option_permissible_value_name (option, i);
1170 
1171         widget =
1172             gtk_radio_button_new_with_label_from_widget (widget ?
1173                     GTK_RADIO_BUTTON(widget) :
1174                     NULL,
1175                     label && *label ? _(label) : "");
1176         g_object_set_data (G_OBJECT(widget), "gnc_radiobutton_index",
1177                            GINT_TO_POINTER (i));
1178 
1179         g_signal_connect (G_OBJECT(widget), "toggled",
1180                           G_CALLBACK(gnc_option_radiobutton_cb), option);
1181         gtk_box_pack_start (GTK_BOX(box), widget, FALSE, FALSE, 0);
1182 
1183         if (label)
1184             free (label);
1185     }
1186     return frame;
1187 }
1188 
1189 static GtkWidget *
gnc_option_create_currency_accounting_widget(char * name,GNCOption * option)1190 gnc_option_create_currency_accounting_widget (char *name, GNCOption *option)
1191 {
1192     GtkWidget *frame = NULL,
1193               *widget = NULL,
1194               *vbox = NULL;
1195     int i;
1196     int num_values = gnc_option_num_permissible_values (option);
1197 
1198     g_return_val_if_fail (num_values == 3, NULL);
1199     book_currency_data = g_new0 (currency_accounting_data, 1);
1200     book_currency_data->option = option;
1201 
1202     /* Create the button frame */
1203     frame = gtk_frame_new (name);
1204     gtk_widget_set_halign (GTK_WIDGET(frame), GTK_ALIGN_FILL);
1205     gtk_widget_set_hexpand (GTK_WIDGET(frame), TRUE);
1206 
1207     /* Create the vertical button box */
1208     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
1209     gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
1210     gtk_container_add (GTK_CONTAINER(frame), vbox);
1211     gtk_widget_set_halign (GTK_WIDGET(vbox), GTK_ALIGN_FILL);
1212     gtk_widget_set_hexpand (GTK_WIDGET(vbox), TRUE);
1213 
1214     gtk_widget_set_margin_end (GTK_WIDGET(vbox), 12);
1215     gtk_widget_set_margin_bottom (GTK_WIDGET(vbox), 12);
1216 
1217     /* Iterate over the three options and create a radio button for each one */
1218     for (i = 0; i < num_values; i++)
1219     {
1220         char *label;
1221         char *tip = NULL;
1222         GtkWidget *table = NULL;
1223 
1224         label = gnc_option_permissible_value_name (option, i);
1225 
1226         widget =
1227             gtk_radio_button_new_with_label_from_widget (widget ?
1228                     GTK_RADIO_BUTTON(widget) :
1229                     NULL,
1230                     label && *label ? _(label) : "");
1231         g_object_set_data (G_OBJECT(widget), "gnc_radiobutton_index",
1232                            GINT_TO_POINTER(i));
1233         switch (i)
1234         {
1235         case 0:
1236             book_currency_data->gnc_currency_radiobutton_0 = widget;
1237             break;
1238 
1239         case 1:
1240             book_currency_data->gnc_currency_radiobutton_1 = widget;
1241             break;
1242 
1243         case 2:
1244             book_currency_data->gnc_currency_radiobutton_2 = widget;
1245             break;
1246 
1247         default:
1248             break;
1249         }
1250         if (g_strcmp0 (gnc_option_permissible_value_name (option, i),
1251                                                     "Use a Book Currency") == 0)
1252         {
1253             GtkWidget *widget_label,
1254                       *policy_table = gtk_grid_new ();
1255 
1256             book_currency_data->book_currency_widget = gnc_currency_edit_new ();
1257             book_currency_data->default_cost_policy_widget =
1258                                     gnc_cost_policy_select_new ();
1259             book_currency_data->default_gain_loss_account_widget = NULL;
1260             book_currency_data->gain_loss_account_del_button = NULL;
1261             book_currency_data->default_gain_loss_account_text = NULL;
1262             book_currency_data->prior_gain_loss_account = NULL;
1263 
1264             book_currency_data->book_currency_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1265             gtk_box_set_homogeneous (GTK_BOX(book_currency_data->book_currency_vbox), FALSE);
1266 
1267             table = gtk_grid_new ();
1268             gtk_grid_attach (GTK_GRID(table), widget, 0, 0, 2, 1);
1269             g_signal_connect (G_OBJECT(widget), "toggled",
1270                               G_CALLBACK(gnc_option_currency_accounting_book_cb),
1271                               book_currency_data);
1272 
1273             book_currency_data->book_currency_table = gtk_grid_new ();
1274             gtk_grid_set_row_spacing (GTK_GRID(book_currency_data->book_currency_table), 6);
1275             gtk_grid_set_column_spacing (GTK_GRID(book_currency_data->book_currency_table), 6);
1276 
1277             tip = gnc_currency_accounting_option_currency_documentation (option);
1278             widget_label = gtk_label_new ( _("Book currency") );
1279             gtk_widget_set_tooltip_text (book_currency_data->book_currency_table,
1280                                          tip && *tip ? _(tip) : "");
1281 
1282             gtk_widget_set_halign (GTK_WIDGET(widget_label), GTK_ALIGN_START);
1283             gtk_widget_set_hexpand (GTK_WIDGET(widget_label), TRUE);
1284 
1285             gtk_grid_attach (GTK_GRID(book_currency_data->book_currency_table), widget_label, 0, 0, 1, 1);
1286 
1287             g_signal_connect (G_OBJECT(book_currency_data->book_currency_widget),
1288                               "changed",
1289                               G_CALLBACK(gnc_option_changed_book_currency_widget_cb),
1290                               NULL);
1291 
1292             gtk_grid_attach (GTK_GRID(book_currency_data->book_currency_table),
1293                                       book_currency_data->book_currency_widget, 1, 0, 1, 1);
1294 
1295             gtk_box_pack_start (GTK_BOX(book_currency_data->book_currency_vbox),
1296                                 book_currency_data->book_currency_table,
1297                                 TRUE, TRUE, 0);
1298             gtk_widget_set_margin_start (GTK_WIDGET(book_currency_data->book_currency_table), 12);
1299             gtk_grid_set_row_spacing (GTK_GRID(policy_table), 6);
1300             gtk_grid_set_column_spacing (GTK_GRID(policy_table), 6);
1301 
1302             tip = gnc_currency_accounting_option_policy_documentation (option);
1303             widget_label = gtk_label_new ( _("Default lot tracking policy") );
1304             gtk_widget_set_tooltip_text (policy_table, tip && *tip ? _(tip) : "");
1305 
1306             gtk_widget_set_halign (GTK_WIDGET(widget_label), GTK_ALIGN_START);
1307             gtk_widget_set_hexpand (GTK_WIDGET(widget_label), TRUE);
1308 
1309             gtk_grid_attach (GTK_GRID(policy_table), widget_label, 0, 1, 1, 1);
1310 
1311             g_signal_connect (G_OBJECT(book_currency_data->default_cost_policy_widget),
1312                               "changed",
1313                               G_CALLBACK(gnc_option_multichoice_cb), option);
1314 
1315             gtk_grid_attach (GTK_GRID(policy_table),
1316                              book_currency_data->default_cost_policy_widget, 1, 1, 1, 1);
1317 
1318             gtk_box_pack_start (GTK_BOX(book_currency_data->book_currency_vbox),
1319                                 policy_table, TRUE, TRUE, 0);
1320             gtk_widget_set_margin_start (GTK_WIDGET(policy_table), 12);
1321             book_currency_data->gain_loss_account_table = gtk_grid_new ();
1322             gtk_grid_set_row_spacing (GTK_GRID(book_currency_data->gain_loss_account_table), 6);
1323             gtk_grid_set_column_spacing (GTK_GRID(book_currency_data->gain_loss_account_table), 6);
1324 
1325             tip = gnc_currency_accounting_option_gain_loss_account_documentation (option);
1326             widget_label = gtk_label_new ( _("Default gain/loss account") );
1327             gnc_label_set_alignment (GTK_WIDGET(widget_label), 0.0, 0.5);
1328 
1329             gtk_widget_set_tooltip_text (book_currency_data->gain_loss_account_table,
1330                                          tip && *tip ? _(tip) : "");
1331 
1332             gtk_grid_attach (GTK_GRID(book_currency_data->gain_loss_account_table),
1333                              widget_label, 0, 0, 1, 1);
1334 
1335             widget_label = NULL;
1336             gtk_box_pack_start (GTK_BOX (book_currency_data->book_currency_vbox),
1337                                 book_currency_data->gain_loss_account_table,
1338                                 TRUE, TRUE, 0);
1339             gtk_widget_set_margin_start (GTK_WIDGET(book_currency_data->gain_loss_account_table), 12);
1340             gtk_grid_attach (GTK_GRID(table), book_currency_data->book_currency_vbox, 1, 2, 1, 1);
1341         }
1342         else /* trading or neither */
1343         {
1344             table = gtk_grid_new ();
1345             gtk_grid_attach (GTK_GRID(table), widget, 0, 1, 1, 1);
1346 
1347             g_signal_connect (G_OBJECT(widget), "toggled",
1348                               G_CALLBACK(gnc_option_currency_accounting_non_book_cb),
1349                               book_currency_data);
1350         }
1351         gtk_box_pack_start (GTK_BOX(vbox), table, TRUE, TRUE, 0);
1352 
1353         if (label)
1354             free (label);
1355         if (tip)
1356             free (tip);
1357     }
1358     return frame;
1359 }
1360 
1361 static void
gnc_option_account_cb(GtkTreeSelection * selection,gpointer data)1362 gnc_option_account_cb (GtkTreeSelection *selection, gpointer data)
1363 {
1364     GNCOption *option = data;
1365     GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
1366     gnc_option_changed_widget_cb (GTK_WIDGET(tree_view), option);
1367 }
1368 
1369 static void
gnc_option_account_select_all_cb(GtkWidget * widget,gpointer data)1370 gnc_option_account_select_all_cb (GtkWidget *widget, gpointer data)
1371 {
1372     GNCOption *option = data;
1373     GncTreeViewAccount *tree_view;
1374     GtkTreeSelection *selection;
1375 
1376     tree_view = GNC_TREE_VIEW_ACCOUNT(gnc_option_get_gtk_widget (option));
1377     gtk_tree_view_expand_all (GTK_TREE_VIEW(tree_view));
1378     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree_view));
1379     gtk_tree_selection_select_all (selection);
1380     gnc_option_changed_widget_cb (widget, option);
1381 }
1382 
1383 static void
gnc_option_account_clear_all_cb(GtkWidget * widget,gpointer data)1384 gnc_option_account_clear_all_cb (GtkWidget *widget, gpointer data)
1385 {
1386     GNCOption *option = data;
1387     GncTreeViewAccount *tree_view;
1388     GtkTreeSelection *selection;
1389 
1390     tree_view = GNC_TREE_VIEW_ACCOUNT(gnc_option_get_gtk_widget (option));
1391     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree_view));
1392     gtk_tree_selection_unselect_all (selection);
1393     gnc_option_changed_widget_cb (widget, option);
1394 }
1395 
1396 static void
gnc_option_account_select_children_cb(GtkWidget * widget,gpointer data)1397 gnc_option_account_select_children_cb (GtkWidget *widget, gpointer data)
1398 {
1399     GNCOption *option = data;
1400     GncTreeViewAccount *tree_view;
1401     GList *acct_list = NULL, *acct_iter = NULL;
1402 
1403     tree_view = GNC_TREE_VIEW_ACCOUNT(gnc_option_get_gtk_widget (option));
1404     acct_list = gnc_tree_view_account_get_selected_accounts (tree_view);
1405 
1406     for (acct_iter = acct_list; acct_iter; acct_iter = acct_iter->next)
1407         gnc_tree_view_account_select_subaccounts (tree_view, acct_iter->data);
1408 
1409     g_list_free (acct_list);
1410 }
1411 
1412 static GtkWidget *
gnc_option_create_account_widget(GNCOption * option,char * name)1413 gnc_option_create_account_widget (GNCOption *option, char *name)
1414 {
1415     gboolean multiple_selection;
1416     GtkWidget *scroll_win;
1417     GtkWidget *button;
1418     GtkWidget *frame;
1419     GtkWidget *tree;
1420     GtkWidget *vbox;
1421     GtkWidget *bbox;
1422     GList *acct_type_list;
1423     GtkTreeSelection *selection;
1424 
1425     multiple_selection = gnc_option_multiple_selection (option);
1426     acct_type_list = gnc_option_get_account_type_list (option);
1427 
1428     frame = gtk_frame_new (name);
1429 
1430     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1431     gtk_box_set_homogeneous (GTK_BOX(vbox), FALSE);
1432 
1433     gtk_container_add (GTK_CONTAINER(frame), vbox);
1434 
1435     tree = GTK_WIDGET(gnc_tree_view_account_new (FALSE));
1436     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tree), FALSE);
1437     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(tree));
1438     if (multiple_selection)
1439         gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1440     else
1441         gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
1442 
1443     if (acct_type_list)
1444     {
1445         GList *node;
1446         AccountViewInfo avi;
1447         int i;
1448 
1449         gnc_tree_view_account_get_view_info (GNC_TREE_VIEW_ACCOUNT(tree), &avi);
1450 
1451         for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
1452             avi.include_type[i] = FALSE;
1453         avi.show_hidden = FALSE;
1454 
1455         for (node = acct_type_list; node; node = node->next)
1456         {
1457             GNCAccountType type = GPOINTER_TO_INT(node->data);
1458             avi.include_type[type] = TRUE;
1459         }
1460 
1461         gnc_tree_view_account_set_view_info (GNC_TREE_VIEW_ACCOUNT(tree), &avi);
1462         g_list_free (acct_type_list);
1463     }
1464     else
1465     {
1466         AccountViewInfo avi;
1467         int i;
1468 
1469         gnc_tree_view_account_get_view_info (GNC_TREE_VIEW_ACCOUNT(tree), &avi);
1470 
1471         for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
1472             avi.include_type[i] = TRUE;
1473         avi.show_hidden = FALSE;
1474         gnc_tree_view_account_set_view_info (GNC_TREE_VIEW_ACCOUNT(tree), &avi);
1475     }
1476 
1477     scroll_win = gtk_scrolled_window_new (NULL, NULL);
1478     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll_win),
1479                                     GTK_POLICY_AUTOMATIC,
1480                                     GTK_POLICY_AUTOMATIC);
1481 
1482     gtk_box_pack_start (GTK_BOX(vbox), scroll_win, TRUE, TRUE, 0);
1483     gtk_container_set_border_width (GTK_CONTAINER(scroll_win), 5);
1484     gtk_container_add (GTK_CONTAINER(scroll_win), tree);
1485 
1486     bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1487     gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
1488     gtk_box_pack_start (GTK_BOX(vbox), bbox, FALSE, FALSE, 10);
1489 
1490     if (multiple_selection)
1491     {
1492         button = gtk_button_new_with_label (_("Select All"));
1493         gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1494         gtk_widget_set_tooltip_text (button, _("Select all accounts."));
1495 
1496         g_signal_connect (G_OBJECT(button), "clicked",
1497                           G_CALLBACK(gnc_option_account_select_all_cb), option);
1498 
1499         button = gtk_button_new_with_label (_("Clear All"));
1500         gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1501         gtk_widget_set_tooltip_text (button, _("Clear the selection and unselect all accounts."));
1502 
1503         g_signal_connect (G_OBJECT(button), "clicked",
1504                           G_CALLBACK(gnc_option_account_clear_all_cb), option);
1505 
1506         button = gtk_button_new_with_label (_("Select Children"));
1507         gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1508         gtk_widget_set_tooltip_text (button, _("Select all descendents of selected account."));
1509 
1510         g_signal_connect (G_OBJECT(button), "clicked",
1511                           G_CALLBACK(gnc_option_account_select_children_cb), option);
1512     }
1513 
1514     button = gtk_button_new_with_label (_("Select Default"));
1515     gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1516     gtk_widget_set_tooltip_text (button, _("Select the default account selection."));
1517 
1518     g_signal_connect (G_OBJECT(button), "clicked",
1519                       G_CALLBACK(gnc_option_default_cb), option);
1520 
1521     gtk_widget_set_margin_start (GTK_WIDGET(bbox), 6);
1522     gtk_widget_set_margin_end (GTK_WIDGET(bbox), 6);
1523 
1524     if (multiple_selection)
1525     {
1526         /* Put the "Show hidden" checkbox on a separate line since the 4 buttons make
1527            the dialog too wide. */
1528         bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1529         gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
1530         gtk_box_pack_start (GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1531     }
1532 
1533     button = gtk_check_button_new_with_label (_("Show Hidden Accounts"));
1534     gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1535     gtk_widget_set_tooltip_text (button, _("Show accounts that have been marked hidden."));
1536     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), FALSE);
1537     g_signal_connect (G_OBJECT(button), "toggled",
1538                       G_CALLBACK(gnc_option_show_hidden_toggled_cb), option);
1539 
1540     gnc_option_set_widget (option, tree);
1541 
1542     return frame;
1543 }
1544 
1545 static void
gnc_option_list_changed_cb(GtkTreeSelection * selection,GNCOption * option)1546 gnc_option_list_changed_cb (GtkTreeSelection *selection,
1547                             GNCOption *option)
1548 {
1549     GtkTreeView *view = gtk_tree_selection_get_tree_view (selection);
1550     gnc_option_changed_widget_cb (GTK_WIDGET(view), option);
1551 }
1552 
1553 static void
gnc_option_list_select_all_cb(GtkWidget * widget,gpointer data)1554 gnc_option_list_select_all_cb (GtkWidget *widget, gpointer data)
1555 {
1556     GNCOption *option = data;
1557     GtkTreeView *view;
1558     GtkTreeSelection *selection;
1559 
1560     view = GTK_TREE_VIEW(gnc_option_get_gtk_widget (option));
1561     selection = gtk_tree_view_get_selection (view);
1562     gtk_tree_selection_select_all (selection);
1563     gnc_option_changed_widget_cb (GTK_WIDGET(view), option);
1564 }
1565 
1566 static void
gnc_option_list_clear_all_cb(GtkWidget * widget,gpointer data)1567 gnc_option_list_clear_all_cb (GtkWidget *widget, gpointer data)
1568 {
1569     GNCOption *option = data;
1570     GtkTreeView *view;
1571     GtkTreeSelection *selection;
1572 
1573     view = GTK_TREE_VIEW(gnc_option_get_gtk_widget (option));
1574     selection = gtk_tree_view_get_selection (view);
1575     gtk_tree_selection_unselect_all (selection);
1576     gnc_option_changed_widget_cb (GTK_WIDGET(view), option);
1577 }
1578 
1579 static GtkWidget *
gnc_option_create_list_widget(GNCOption * option,char * name)1580 gnc_option_create_list_widget (GNCOption *option, char *name)
1581 {
1582     GtkListStore *store;
1583     GtkTreeView *view;
1584     GtkTreeIter iter;
1585     GtkTreeViewColumn *column;
1586     GtkCellRenderer *renderer;
1587     GtkTreeSelection *selection;
1588 
1589     GtkWidget *button;
1590     GtkWidget *frame;
1591     GtkWidget *hbox;
1592     GtkWidget *bbox;
1593     gint num_values;
1594     gint i;
1595 
1596     frame = gtk_frame_new (name);
1597     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1598     gtk_box_set_homogeneous (GTK_BOX(hbox), FALSE);
1599     gtk_container_add (GTK_CONTAINER(frame), hbox);
1600 
1601     store = gtk_list_store_new (1, G_TYPE_STRING);
1602     view = GTK_TREE_VIEW(gtk_tree_view_new_with_model (GTK_TREE_MODEL(store)));
1603     g_object_unref (store);
1604     renderer = gtk_cell_renderer_text_new ();
1605     column = gtk_tree_view_column_new_with_attributes ("", renderer,
1606                                                        "text", 0,
1607                                                        NULL);
1608     gtk_tree_view_append_column (view, column);
1609     gtk_tree_view_set_headers_visible (view, FALSE);
1610 
1611     num_values = gnc_option_num_permissible_values (option);
1612     for (i = 0; i < num_values; i++)
1613     {
1614         gchar *raw_string, *string;
1615 
1616         raw_string = gnc_option_permissible_value_name (option, i);
1617         string = (raw_string && *raw_string) ? _(raw_string) : "";
1618         gtk_list_store_append (store, &iter);
1619         gtk_list_store_set (store, &iter,
1620                             0, string ? string : "",
1621                             -1);
1622         g_free (raw_string);
1623     }
1624 
1625     gtk_box_pack_start (GTK_BOX(hbox), GTK_WIDGET(view), FALSE, FALSE, 0);
1626 
1627     selection = gtk_tree_view_get_selection (view);
1628     gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1629     g_signal_connect (selection, "changed",
1630                       G_CALLBACK(gnc_option_list_changed_cb), option);
1631 
1632     bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
1633     gtk_button_box_set_layout (GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_SPREAD);
1634     gtk_box_pack_end (GTK_BOX(hbox), bbox, FALSE, FALSE, 0);
1635 
1636     button = gtk_button_new_with_label (_("Select All"));
1637     gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1638     gtk_widget_set_tooltip_text (button, _("Select all entries."));
1639 
1640     g_signal_connect (G_OBJECT(button), "clicked",
1641                       G_CALLBACK(gnc_option_list_select_all_cb), option);
1642 
1643     button = gtk_button_new_with_label (_("Clear All"));
1644     gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1645     gtk_widget_set_tooltip_text (button, _("Clear the selection and unselect all entries."));
1646 
1647     g_signal_connect (G_OBJECT(button), "clicked",
1648                       G_CALLBACK(gnc_option_list_clear_all_cb), option);
1649 
1650     button = gtk_button_new_with_label (_("Select Default"));
1651     gtk_box_pack_start (GTK_BOX(bbox), button, FALSE, FALSE, 0);
1652     gtk_widget_set_tooltip_text (button, _("Select the default selection."));
1653 
1654     g_signal_connect (G_OBJECT(button), "clicked",
1655                       G_CALLBACK(gnc_option_default_cb), option);
1656 
1657     g_object_set (G_OBJECT(hbox), "margin", 3, NULL);
1658 
1659     gnc_option_set_widget (option, GTK_WIDGET(view));
1660 
1661     return frame;
1662 }
1663 
1664 static void
gnc_option_color_changed_cb(GtkColorButton * color_button,GNCOption * option)1665 gnc_option_color_changed_cb (GtkColorButton *color_button, GNCOption *option)
1666 {
1667     gnc_option_changed_widget_cb (GTK_WIDGET(color_button), option);
1668 }
1669 
1670 static void
gnc_option_font_changed_cb(GtkFontButton * font_button,GNCOption * option)1671 gnc_option_font_changed_cb (GtkFontButton *font_button, GNCOption *option)
1672 {
1673     gnc_option_changed_widget_cb (GTK_WIDGET(font_button), option);
1674 }
1675 
1676 static void
gnc_option_set_ui_widget(GNCOption * option,GtkGrid * page_box,gint grid_row)1677 gnc_option_set_ui_widget (GNCOption *option, GtkGrid *page_box, gint grid_row)
1678 {
1679     GtkWidget *enclosing = NULL;
1680     GtkWidget *value = NULL;
1681     gboolean packed = FALSE;
1682     char *raw_name, *raw_documentation;
1683     char *name, *documentation;
1684     char *type;
1685     GNCOptionDef_t *option_def;
1686     GtkLabel *name_label;
1687 
1688     ENTER("option %p(%s), box %p",
1689           option, gnc_option_name (option), page_box);
1690     type = gnc_option_type (option);
1691     if (type == NULL)
1692     {
1693         LEAVE("bad type");
1694         return;
1695     }
1696     else if (g_strcmp0 (type, "internal") == 0)
1697     {
1698         LEAVE("internal type");
1699         return;
1700     }
1701 
1702     raw_name = gnc_option_name (option);
1703     if (raw_name && *raw_name)
1704         name = _(raw_name);
1705     else
1706         name = NULL;
1707 
1708     raw_documentation = gnc_option_documentation (option);
1709     if (raw_documentation && *raw_documentation)
1710         documentation = _(raw_documentation);
1711     else
1712         documentation = NULL;
1713 
1714     name_label = GTK_LABEL(gtk_label_new (name));
1715 
1716     option_def = gnc_options_ui_get_option (type);
1717     if (option_def && option_def->set_widget)
1718     {
1719         value = option_def->set_widget (option, page_box,
1720                                         name_label, documentation,
1721                                         /* Return values */
1722                                         &enclosing, &packed);
1723     }
1724     else
1725     {
1726         PERR("Unknown option type. Ignoring option \"%s\".\n", name);
1727     }
1728 
1729     /* attach the name label to the first column of the grid and align to the end
1730      * if option is a check button, do not add a label as we are using the built
1731      * in one */
1732     if (!GTK_IS_CHECK_BUTTON(value))
1733         gtk_grid_attach (GTK_GRID(page_box), GTK_WIDGET(name_label),
1734                          0, grid_row, // left, top
1735                          1, 1);  // width, height
1736 
1737     gtk_widget_set_halign (GTK_WIDGET(name_label), GTK_ALIGN_END);
1738 
1739     if (!packed && (enclosing != NULL))
1740     {
1741         /* Pack option widget into an extra eventbox because otherwise the
1742            "documentation" tooltip is not displayed. */
1743         GtkWidget *eventbox = gtk_event_box_new ();
1744 
1745         gtk_container_add (GTK_CONTAINER(eventbox), enclosing);
1746 
1747         /* attach the option widget to the second column of the grid */
1748         gtk_grid_attach (GTK_GRID(page_box), eventbox,
1749                          1, grid_row, // left, top
1750                          1, 1);  // width, height
1751 
1752         gtk_widget_set_tooltip_text (eventbox, documentation);
1753     }
1754 
1755     if (value != NULL)
1756         gtk_widget_set_tooltip_text (value, documentation);
1757 
1758     if (raw_name != NULL)
1759         free (raw_name);
1760     if (raw_documentation != NULL)
1761         free (raw_documentation);
1762     free (type);
1763     LEAVE(" ");
1764 }
1765 
1766 static void
gnc_options_dialog_add_option(GtkWidget * page,GNCOption * option,gint row)1767 gnc_options_dialog_add_option (GtkWidget *page,
1768                                GNCOption *option, gint row)
1769 {
1770     g_object_set_data (G_OBJECT(page), "options-grid-row", GINT_TO_POINTER(row));
1771     gnc_option_set_ui_widget (option, GTK_GRID(page), row);
1772 }
1773 
1774 static gint
gnc_options_dialog_append_page(GNCOptionWin * propertybox,GNCOptionSection * section)1775 gnc_options_dialog_append_page (GNCOptionWin * propertybox,
1776                                 GNCOptionSection *section)
1777 {
1778     GNCOption *option;
1779     GtkWidget *page_label;
1780     GtkWidget *options_box;
1781     GtkWidget *page_content_box;
1782     GtkWidget* notebook_page;
1783     GtkWidget *reset_button;
1784     GtkWidget *listitem = NULL;
1785     GtkWidget *buttonbox;
1786     GtkWidget *options_scrolled_win;
1787     GtkTreeView *view;
1788     GtkListStore *list;
1789     GtkTreeIter iter;
1790     gint num_options;
1791     const char *name;
1792     gint i, page_count, name_offset;
1793     gboolean advanced;
1794 
1795     name = gnc_option_section_name (section);
1796     if (!name)
1797         return -1;
1798 
1799     if (strncmp (name, "__", 2) == 0)
1800         return -1;
1801     advanced = (strncmp (name, "_+", 2) == 0);
1802     name_offset = (advanced) ? 2 : 0;
1803     page_label = gtk_label_new (_(name + name_offset));
1804     PINFO("Page_label is %s", _(name + name_offset));
1805     gtk_widget_show (page_label);
1806 
1807     /* Build this options page */
1808     page_content_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
1809     gtk_widget_set_name (page_content_box, "page-content-box");
1810     gtk_box_set_homogeneous (GTK_BOX (page_content_box), FALSE);
1811 
1812     gtk_container_set_border_width (GTK_CONTAINER(page_content_box), 12);
1813 
1814     options_scrolled_win = gtk_scrolled_window_new (NULL, NULL);
1815     gtk_box_pack_start (GTK_BOX(page_content_box), options_scrolled_win, TRUE, TRUE, 0);
1816 
1817     /* Build space for the content - the options box */
1818     options_box = gtk_grid_new (); // this will have two columns
1819     gtk_widget_set_name (options_box, "options-box");
1820     gtk_grid_set_row_homogeneous (GTK_GRID(options_box), FALSE);
1821     gtk_grid_set_column_homogeneous (GTK_GRID(options_box), FALSE);
1822     gtk_grid_set_row_spacing (GTK_GRID(options_box), 6);
1823     gtk_grid_set_column_spacing (GTK_GRID(options_box), 6);
1824 
1825     gtk_container_set_border_width (GTK_CONTAINER(options_box), 0);
1826     gtk_container_add (GTK_CONTAINER(options_scrolled_win), GTK_WIDGET(options_box));
1827     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(options_scrolled_win),
1828                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1829 
1830     /* Create all the options */
1831     num_options = gnc_option_section_num_options (section);
1832     for (i = 0; i < num_options; i++)
1833     {
1834         option = gnc_get_option_section_option (section, i);
1835         gnc_options_dialog_add_option (options_box, option, i);
1836     }
1837 
1838     /* Add a button box at the bottom of the page */
1839     buttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
1840     gtk_button_box_set_layout (GTK_BUTTON_BOX (buttonbox),
1841                                GTK_BUTTONBOX_EDGE);
1842     gtk_container_set_border_width (GTK_CONTAINER(buttonbox), 5);
1843     gtk_box_pack_end (GTK_BOX(page_content_box), buttonbox, FALSE, FALSE, 0);
1844 
1845     /* The reset button on each option page */
1846     reset_button = gtk_button_new_with_label (_("Reset defaults"));
1847     gtk_widget_set_tooltip_text (reset_button,
1848                                  _("Reset all values to their defaults."));
1849 
1850     g_signal_connect (G_OBJECT(reset_button), "clicked",
1851                       G_CALLBACK(gnc_options_dialog_reset_cb), propertybox);
1852     g_object_set_data (G_OBJECT(reset_button), "section", section);
1853     gtk_box_pack_end (GTK_BOX(buttonbox), reset_button, FALSE, FALSE, 0);
1854     gtk_widget_show_all (page_content_box);
1855     gtk_notebook_append_page (GTK_NOTEBOOK(propertybox->notebook),
1856                               page_content_box, page_label);
1857 
1858     /* Switch to selection from a list if the page count threshold is reached */
1859     page_count = gtk_notebook_page_num (GTK_NOTEBOOK(propertybox->notebook),
1860                                         page_content_box);
1861 
1862     if (propertybox->page_list_view)
1863     {
1864         /* Build the matching list item for selecting from large page sets */
1865         view = GTK_TREE_VIEW(propertybox->page_list_view);
1866         list = GTK_LIST_STORE(gtk_tree_view_get_model (view));
1867 
1868         PINFO("Page name is %s and page_count is %d", name, page_count);
1869         gtk_list_store_append (list, &iter);
1870         gtk_list_store_set (list, &iter,
1871                             PAGE_NAME, _(name),
1872                             PAGE_INDEX, page_count,
1873                             -1);
1874 
1875         if (page_count > MAX_TAB_COUNT - 1)   /* Convert 1-based -> 0-based */
1876         {
1877             gtk_widget_show (propertybox->page_list);
1878             gtk_notebook_set_show_tabs (GTK_NOTEBOOK(propertybox->notebook), FALSE);
1879             gtk_notebook_set_show_border (GTK_NOTEBOOK(propertybox->notebook), FALSE);
1880         }
1881         else
1882             gtk_widget_hide (propertybox->page_list);
1883 
1884         /* Tweak "advanced" pages for later handling. */
1885         if (advanced)
1886         {
1887             notebook_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK(propertybox->notebook),
1888                                                        page_count);
1889 
1890             g_object_set_data (G_OBJECT(notebook_page), "listitem", listitem);
1891             g_object_set_data (G_OBJECT(notebook_page), "advanced",
1892                                GINT_TO_POINTER(advanced));
1893         }
1894     }
1895     return (page_count);
1896 }
1897 
1898 /********************************************************************\
1899  * gnc_options_dialog_build_contents                                *
1900  *   builds an options dialog given a property box and an options   *
1901  *   database and make the dialog visible                           *
1902  *                                                                  *
1903  * Args: propertybox - gnome property box to use                    *
1904  *       odb         - option database to use                       *
1905  * Return: nothing                                                  *
1906 \********************************************************************/
1907 void
gnc_options_dialog_build_contents(GNCOptionWin * propertybox,GNCOptionDB * odb)1908 gnc_options_dialog_build_contents (GNCOptionWin *propertybox,
1909                                    GNCOptionDB  *odb)
1910 {
1911     gnc_options_dialog_build_contents_full (propertybox, odb, TRUE);
1912 }
1913 
1914 /********************************************************************\
1915  * gnc_options_dialog_build_contents_full                           *
1916  *   builds an options dialog given a property box and an options   *
1917  *   database and make the dialog visible depending on the          *
1918  *   show_dialog flag                                               *
1919  *                                                                  *
1920  * Args: propertybox - gnome property box to use                    *
1921  *       odb         - option database to use                       *
1922  *       show_dialog - should dialog be made visible or not         *
1923  * Return: nothing                                                  *
1924 \********************************************************************/
1925 void
gnc_options_dialog_build_contents_full(GNCOptionWin * propertybox,GNCOptionDB * odb,gboolean show_dialog)1926 gnc_options_dialog_build_contents_full (GNCOptionWin *propertybox,
1927                                         GNCOptionDB  *odb, gboolean show_dialog)
1928 {
1929     GNCOptionSection *section;
1930     gchar *default_section_name;
1931     gint default_page = -1;
1932     gint num_sections;
1933     gint page;
1934     gint i;
1935     guint j;
1936 
1937     g_return_if_fail (propertybox != NULL);
1938     g_return_if_fail (odb != NULL);
1939 
1940     gnc_option_db_set_ui_callbacks (odb,
1941                                     gnc_option_get_ui_value_internal,
1942                                     gnc_option_set_ui_value_internal,
1943                                     gnc_option_set_selectable_internal);
1944 
1945     propertybox->option_db = odb;
1946 
1947     num_sections = gnc_option_db_num_sections (odb);
1948     default_section_name = gnc_option_db_get_default_section (odb);
1949 
1950     PINFO("Default Section name is %s", default_section_name);
1951 
1952     for (i = 0; i < num_sections; i++)
1953     {
1954         const char *section_name;
1955 
1956         section = gnc_option_db_get_section (odb, i);
1957         page = gnc_options_dialog_append_page (propertybox, section);
1958 
1959         section_name = gnc_option_section_name (section);
1960         if (g_strcmp0 (section_name, default_section_name) == 0)
1961             default_page = page;
1962     }
1963 
1964     if (default_section_name != NULL)
1965         free (default_section_name);
1966 
1967     /* call each option widget changed callbacks once at this point,
1968      * now that all options widgets exist.
1969      */
1970     for (i = 0; i < num_sections; i++)
1971     {
1972         section = gnc_option_db_get_section (odb, i);
1973 
1974         for (j = 0; j < gnc_option_section_num_options (section); j++)
1975         {
1976             // setting TRUE will clear the changed flag after proc
1977             gnc_option_call_option_widget_changed_proc (
1978                 gnc_get_option_section_option(section, j), TRUE);
1979         }
1980     }
1981 
1982     gtk_notebook_popup_enable (GTK_NOTEBOOK(propertybox->notebook));
1983     if (default_page >= 0)
1984     {
1985         /* Find the page list and set the selection to the default page */
1986         GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(propertybox->page_list_view));
1987         GtkTreeIter iter;
1988         GtkTreeModel *model;
1989 
1990         model = gtk_tree_view_get_model (GTK_TREE_VIEW(propertybox->page_list_view));
1991         gtk_tree_model_iter_nth_child (model, &iter, NULL, default_page);
1992         gtk_tree_selection_select_iter (selection, &iter);
1993         gtk_notebook_set_current_page (GTK_NOTEBOOK(propertybox->notebook), default_page);
1994     }
1995     gnc_options_dialog_changed_internal (propertybox->window, FALSE);
1996     if (show_dialog)
1997         gtk_widget_show (propertybox->window);
1998 }
1999 
2000 GtkWidget *
gnc_options_dialog_widget(GNCOptionWin * win)2001 gnc_options_dialog_widget (GNCOptionWin * win)
2002 {
2003     return win->window;
2004 }
2005 
2006 GtkWidget *
gnc_options_page_list(GNCOptionWin * win)2007 gnc_options_page_list (GNCOptionWin * win)
2008 {
2009     return win->page_list;
2010 }
2011 
2012 GtkWidget *
gnc_options_dialog_notebook(GNCOptionWin * win)2013 gnc_options_dialog_notebook (GNCOptionWin * win)
2014 {
2015     return win->notebook;
2016 }
2017 
2018 static void
gnc_options_dialog_help_button_cb(GtkWidget * widget,GNCOptionWin * win)2019 gnc_options_dialog_help_button_cb (GtkWidget * widget, GNCOptionWin *win)
2020 {
2021     if (win->help_cb)
2022         (win->help_cb)(win, win->help_cb_data);
2023 }
2024 
2025 static void
gnc_options_dialog_cancel_button_cb(GtkWidget * widget,GNCOptionWin * win)2026 gnc_options_dialog_cancel_button_cb (GtkWidget * widget, GNCOptionWin *win)
2027 {
2028     gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
2029 
2030     if (win->close_cb)
2031         (win->close_cb)(win, win->close_cb_data);
2032     else
2033         gtk_widget_hide (win->window);
2034 }
2035 
2036 static void
gnc_options_dialog_apply_button_cb(GtkWidget * widget,GNCOptionWin * win)2037 gnc_options_dialog_apply_button_cb (GtkWidget * widget, GNCOptionWin *win)
2038 {
2039     GNCOptionWinCallback close_cb = win->close_cb;
2040 
2041     win->close_cb = NULL;
2042     if (win->apply_cb)
2043         win->apply_cb (win, win->apply_cb_data);
2044     win->close_cb = close_cb;
2045     gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
2046     gnc_options_dialog_changed_internal (win->window, FALSE);
2047 }
2048 
2049 static void
gnc_options_dialog_ok_button_cb(GtkWidget * widget,GNCOptionWin * win)2050 gnc_options_dialog_ok_button_cb (GtkWidget * widget, GNCOptionWin *win)
2051 {
2052     GNCOptionWinCallback close_cb = win->close_cb;
2053 
2054     win->close_cb = NULL;
2055     if (win->apply_cb)
2056         win->apply_cb (win, win->apply_cb_data);
2057     win->close_cb = close_cb;
2058 
2059     gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
2060 
2061     if (win->close_cb)
2062         (win->close_cb)(win, win->close_cb_data);
2063     else
2064         gtk_widget_hide (win->window);
2065 }
2066 
2067 static void
gnc_options_dialog_destroy_cb(GtkWidget * object,GNCOptionWin * win)2068 gnc_options_dialog_destroy_cb (GtkWidget *object, GNCOptionWin *win)
2069 {
2070     if (!win) return;
2071 
2072     if (win->destroyed == FALSE)
2073     {
2074         if (win->close_cb)
2075             (win->close_cb)(win, win->close_cb_data);
2076     }
2077 }
2078 
2079 static gboolean
gnc_options_dialog_window_key_press_cb(GtkWidget * widget,GdkEventKey * event,gpointer data)2080 gnc_options_dialog_window_key_press_cb (GtkWidget *widget,
2081                                         GdkEventKey *event,
2082                                         gpointer data)
2083 {
2084     GNCOptionWin *win = data;
2085 
2086     if (event->keyval == GDK_KEY_Escape)
2087     {
2088         component_close_handler (win);
2089         return TRUE;
2090     }
2091     else
2092         return FALSE;
2093 }
2094 
2095 static void
gnc_options_dialog_reset_cb(GtkWidget * w,gpointer data)2096 gnc_options_dialog_reset_cb (GtkWidget * w, gpointer data)
2097 {
2098     GNCOptionWin *win = data;
2099     GNCOptionSection *section;
2100     gpointer val;
2101 
2102     val = g_object_get_data (G_OBJECT(w), "section");
2103     g_return_if_fail (val);
2104     g_return_if_fail (win);
2105 
2106     section = (GNCOptionSection*)val;
2107 
2108     gnc_option_db_section_reset_widgets (section);
2109 
2110     if (gnc_option_db_get_changed (win->option_db))
2111         gnc_options_dialog_changed_internal (win->window, TRUE);
2112 }
2113 
2114 void
gnc_options_dialog_list_select_cb(GtkTreeSelection * selection,gpointer data)2115 gnc_options_dialog_list_select_cb (GtkTreeSelection *selection,
2116                                    gpointer data)
2117 {
2118     GNCOptionWin * win = data;
2119     GtkTreeModel *list;
2120     GtkTreeIter iter;
2121     gint index = 0;
2122 
2123     if (!gtk_tree_selection_get_selected (selection, &list, &iter))
2124         return;
2125     gtk_tree_model_get (list, &iter,
2126                         PAGE_INDEX, &index,
2127                         -1);
2128     PINFO("Index is %d", index);
2129     gtk_notebook_set_current_page (GTK_NOTEBOOK(win->notebook), index);
2130 }
2131 
2132 void
gnc_options_register_stocks(void)2133 gnc_options_register_stocks (void)
2134 {
2135 #if 0
2136     static gboolean done = FALSE;
2137 
2138     GtkStockItem items[] =
2139     {
2140         { GTK_STOCK_APPLY       , "gnc_option_apply_button",    0, 0, NULL },
2141         { GTK_STOCK_HELP        , "gnc_options_dialog_help",    0, 0, NULL },
2142         { GTK_STOCK_OK          , "gnc_options_dialog_ok",      0, 0, NULL },
2143         { GTK_STOCK_CANCEL      , "gnc_options_dialog_cancel",  0, 0, NULL },
2144     };
2145 
2146     if (done)
2147     {
2148         return;
2149     }
2150     done = TRUE;
2151 
2152     gtk_stock_add (items, G_N_ELEMENTS (items));
2153 #endif
2154 }
2155 
2156 static void
component_close_handler(gpointer data)2157 component_close_handler (gpointer data)
2158 {
2159     GNCOptionWin *win = data;
2160     gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(win->window));
2161     gnc_options_dialog_cancel_button_cb (NULL, win);
2162 }
2163 
2164 static void
refresh_handler(GHashTable * changes,gpointer user_data)2165 refresh_handler (GHashTable *changes, gpointer user_data)
2166 {
2167     gnc_commodity *commodity = NULL;
2168     GtkTreeIter iter;
2169 
2170     /* The default_gain_loss_account_widget needs to be refreshed if any
2171        changes have been made via account maintenance, if it exists and
2172        if the book currency widget has a selection */
2173 /*    if (book_currency_data->default_gain_loss_account_widget &&
2174         gtk_combo_box_get_active_iter(
2175             GTK_COMBO_BOX(book_currency_data->book_currency_widget), &iter))
2176     {
2177         commodity = gnc_currency_edit_get_currency(
2178                                 GNC_CURRENCY_EDIT(
2179                                     book_currency_data->book_currency_widget));
2180         gnc_set_default_gain_loss_account_widget(commodity);
2181         gtk_widget_show_all(book_currency_data->book_currency_vbox);
2182     } */
2183 }
2184 
2185 /* gnc_options_dialog_new:
2186  *
2187  *   - Opens the dialog-options glade file
2188  *   - Connects signals specified in the builder file
2189  *   - Sets the window's title
2190  *   - Initializes a new GtkNotebook, and adds it to the window
2191  *
2192  */
2193 GNCOptionWin *
gnc_options_dialog_new(gchar * title,GtkWindow * parent)2194 gnc_options_dialog_new (gchar *title, GtkWindow *parent)
2195 {
2196     return gnc_options_dialog_new_modal (FALSE, title, NULL, parent);
2197 }
2198 
2199 /* gnc_options_dialog_new_modal:
2200  *
2201  *   - Opens the dialog-options glade file
2202  *   - Connects signals specified in the builder file
2203  *   - Sets the window's title
2204  *   - Initializes a new GtkNotebook, and adds it to the window
2205  *   - If modal TRUE, hides 'apply' button
2206  *   - If component_class is provided, it is used, otherwise,
2207  *     DIALOG_OPTIONS_CM_CLASS is used; this is used to distinguish the
2208  *     book-option dialog from report dialogs. The book-option dialog is a
2209  *     singleton, so if a dialog already exists it will be raised to the top of
2210  *     the window stack instead of creating a new dialog.
2211  */
2212 GNCOptionWin *
gnc_options_dialog_new_modal(gboolean modal,gchar * title,const char * component_class,GtkWindow * parent)2213 gnc_options_dialog_new_modal (gboolean modal, gchar *title,
2214                               const char *component_class,
2215                               GtkWindow *parent)
2216 {
2217     GNCOptionWin *retval;
2218     GtkBuilder   *builder;
2219     GtkWidget    *hbox;
2220     gint component_id;
2221     GtkWidget    *button;
2222 
2223     retval = g_new0 (GNCOptionWin, 1);
2224     builder = gtk_builder_new ();
2225     gnc_builder_add_from_file (builder, "dialog-options.glade", "gnucash_options_window");
2226     retval->window = GTK_WIDGET(gtk_builder_get_object (builder, "gnucash_options_window"));
2227     retval->page_list = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_scroll"));
2228 
2229     // Set the name for this dialog so it can be easily manipulated with css
2230     gtk_widget_set_name (GTK_WIDGET(retval->window), "gnc-id-options");
2231 
2232     /* Page List */
2233     {
2234         GtkTreeView *view;
2235         GtkListStore *store;
2236         GtkTreeSelection *selection;
2237         GtkCellRenderer *renderer;
2238         GtkTreeViewColumn *column;
2239 
2240         retval->page_list_view = GTK_WIDGET(gtk_builder_get_object (builder, "page_list_treeview"));
2241 
2242         view = GTK_TREE_VIEW(retval->page_list_view);
2243 
2244         store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING);
2245         gtk_tree_view_set_model (view, GTK_TREE_MODEL(store));
2246         g_object_unref (store);
2247 
2248         renderer = gtk_cell_renderer_text_new ();
2249         column = gtk_tree_view_column_new_with_attributes (_("Page"), renderer,
2250                                                            "text", PAGE_NAME,
2251                                                             NULL);
2252         gtk_tree_view_append_column (view, column);
2253 
2254         gtk_tree_view_column_set_alignment (column, 0.5);
2255 
2256         selection = gtk_tree_view_get_selection (view);
2257         gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
2258         g_signal_connect (selection, "changed",
2259                           G_CALLBACK (gnc_options_dialog_list_select_cb), retval);
2260     }
2261 
2262     button = GTK_WIDGET(gtk_builder_get_object (builder, "helpbutton"));
2263         g_signal_connect (button, "clicked", G_CALLBACK(gnc_options_dialog_help_button_cb), retval);
2264     button = GTK_WIDGET(gtk_builder_get_object (builder, "cancelbutton"));
2265         g_signal_connect (button, "clicked", G_CALLBACK(gnc_options_dialog_cancel_button_cb), retval);
2266     button = GTK_WIDGET(gtk_builder_get_object (builder, "applybutton"));
2267         g_signal_connect (button, "clicked", G_CALLBACK(gnc_options_dialog_apply_button_cb), retval);
2268     button = GTK_WIDGET(gtk_builder_get_object (builder, "okbutton"));
2269         g_signal_connect (button, "clicked", G_CALLBACK(gnc_options_dialog_ok_button_cb), retval);
2270 
2271     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, retval);
2272 
2273     if (parent) // when added to a page of the hierarchy assistant there will be no parent
2274         gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(retval->window), parent);
2275 
2276     if (title)
2277         gtk_window_set_title (GTK_WINDOW(retval->window), title);
2278 
2279     /* modal */
2280     if (modal == TRUE)
2281     {
2282         GtkWidget *apply_button;
2283 
2284         apply_button = GTK_WIDGET(gtk_builder_get_object (builder, "applybutton"));
2285         gtk_widget_hide (apply_button);
2286     }
2287 
2288     /* glade doesn't support a notebook with zero pages */
2289     hbox = GTK_WIDGET(gtk_builder_get_object (builder, "notebook_placeholder"));
2290     retval->notebook = gtk_notebook_new ();
2291 
2292     gtk_widget_set_vexpand (retval->notebook, TRUE);
2293 
2294     gtk_widget_show (retval->notebook);
2295     gtk_box_pack_start (GTK_BOX(hbox), retval->notebook, TRUE, TRUE, 5);
2296 
2297     retval->component_class =
2298                 (component_class ? component_class : DIALOG_OPTIONS_CM_CLASS);
2299     component_id = gnc_register_gui_component (retval->component_class,
2300                     refresh_handler, component_close_handler,
2301                     retval);
2302     gnc_gui_component_set_session (component_id, gnc_get_current_session());
2303 
2304     /* Watch account maintenance events only if book option dialog */
2305     if (g_strcmp0 (retval->component_class, DIALOG_BOOK_OPTIONS_CM_CLASS) == 0)
2306     {
2307         gnc_gui_component_watch_entity_type (component_id,
2308                                              GNC_ID_ACCOUNT,
2309                                              QOF_EVENT_MODIFY | QOF_EVENT_DESTROY);
2310     }
2311 
2312     g_signal_connect (retval->window, "destroy",
2313                       G_CALLBACK(gnc_options_dialog_destroy_cb), retval);
2314 
2315     g_signal_connect (retval->window, "key_press_event",
2316                       G_CALLBACK(gnc_options_dialog_window_key_press_cb), retval);
2317 
2318     g_object_unref (G_OBJECT(builder));
2319 
2320     retval->destroyed = FALSE;
2321     return retval;
2322 }
2323 
2324 /* Creates a new GNCOptionWin structure, but assumes you have your own
2325    dialog widget you want to plugin */
2326 GNCOptionWin *
gnc_options_dialog_new_w_dialog(gchar * title,GtkWidget * window)2327 gnc_options_dialog_new_w_dialog (gchar *title, GtkWidget *window)
2328 {
2329     GNCOptionWin * retval;
2330 
2331     retval = g_new0 (GNCOptionWin, 1);
2332     retval->window = window;
2333     return retval;
2334 }
2335 
2336 void
gnc_options_dialog_set_apply_cb(GNCOptionWin * win,GNCOptionWinCallback cb,gpointer data)2337 gnc_options_dialog_set_apply_cb (GNCOptionWin * win, GNCOptionWinCallback cb,
2338                                  gpointer data)
2339 {
2340     win->apply_cb = cb;
2341     win->apply_cb_data = data;
2342 }
2343 
2344 void
gnc_options_dialog_set_help_cb(GNCOptionWin * win,GNCOptionWinCallback cb,gpointer data)2345 gnc_options_dialog_set_help_cb (GNCOptionWin * win, GNCOptionWinCallback cb,
2346                                 gpointer data)
2347 {
2348     win->help_cb = cb;
2349     win->help_cb_data = data;
2350 }
2351 
2352 void
gnc_options_dialog_set_close_cb(GNCOptionWin * win,GNCOptionWinCallback cb,gpointer data)2353 gnc_options_dialog_set_close_cb (GNCOptionWin * win, GNCOptionWinCallback cb,
2354                                  gpointer data)
2355 {
2356     win->close_cb = cb;
2357     win->close_cb_data = data;
2358 }
2359 
2360 void
gnc_options_dialog_set_global_help_cb(GNCOptionWinCallback thunk,gpointer cb_data)2361 gnc_options_dialog_set_global_help_cb (GNCOptionWinCallback thunk,
2362                                        gpointer cb_data)
2363 {
2364     global_help_cb = thunk;
2365     global_help_cb_data = cb_data;
2366 }
2367 
2368 /* This is for global program preferences. */
2369 void
gnc_options_dialog_destroy(GNCOptionWin * win)2370 gnc_options_dialog_destroy (GNCOptionWin * win)
2371 {
2372     if (!win) return;
2373 
2374     gnc_unregister_gui_component_by_data (win->component_class, win);
2375 
2376     win->destroyed = TRUE;
2377     gtk_widget_destroy (win->window);
2378 
2379     win->window = NULL;
2380     win->notebook = NULL;
2381     win->apply_cb = NULL;
2382     win->help_cb = NULL;
2383     win->component_class = NULL;
2384 
2385     g_free (win);
2386 }
2387 
2388 /*****************************************************************/
2389 /* Option Registration                                           */
2390 
2391 /*************************
2392  *       SET WIDGET      *
2393  *************************
2394  *
2395  * gnc_option_set_ui_widget_<type>():
2396  *
2397  * You should create the widget representation for the option type,
2398  * and set the top-level container widget for your control in
2399  * *enclosing.  If you want to pack the widget into the page yourself,
2400  * then you may -- just set *packed to TRUE.  Otherwise, the widget
2401  * you return in *enclosing will be packed for you.  (*packed is
2402  * initialized to FALSE, so if you're not setting it to TRUE, you
2403  * don't have to touch it at all.)
2404  *
2405  * If you need to initialize the state of your control or to connect
2406  * any signals to you widgets, then you should do so in this function.
2407  * If you want to create a label for the widget you should use 'name'
2408  * for the label text.
2409  *
2410  * Somewhere in this function, you should also call
2411  * gnc_option_set_widget(option, value); where 'value' is the
2412  * GtkWidget you will actually store the value in.
2413  *
2414  * Also call gnc_option_set_ui_value(option, FALSE);
2415  *
2416  * You probably want to end with something like:
2417  *   gtk_widget_show_all(*enclosing);
2418  *
2419  * If you can detect state changes for your widget's value, you should also
2420  * gnc_option_changed_widget_cb() upon changes.
2421  *
2422  * The widget you return from this function should be the widget in
2423  * which you're storing the option value.
2424  */
2425 
2426 static void
gnc_option_set_ui_label_alignment(GtkLabel * name_label)2427 gnc_option_set_ui_label_alignment (GtkLabel *name_label)
2428 {
2429     /* some option widgets have a large vertical foot print so align
2430        the label name to the top and add a small top margin */
2431     gtk_widget_set_valign (GTK_WIDGET(name_label), GTK_ALIGN_START);
2432     gtk_widget_set_margin_top (GTK_WIDGET(name_label), 6);
2433 }
2434 
2435 static GtkWidget *
gnc_option_set_ui_widget_boolean(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2436 gnc_option_set_ui_widget_boolean (GNCOption *option, GtkGrid *page_box,
2437                                   GtkLabel *name_label, char *documentation,
2438                                   /* Return values */
2439                                   GtkWidget **enclosing, gboolean *packed)
2440 {
2441     GtkWidget *value;
2442 
2443     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2444     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2445     value = gtk_check_button_new_with_label (gtk_label_get_text (name_label));
2446 
2447     gnc_option_set_widget (option, value);
2448     gnc_option_set_ui_value (option, FALSE);
2449 
2450     g_signal_connect (G_OBJECT(value), "toggled",
2451                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2452 
2453     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2454     gtk_widget_show_all (*enclosing);
2455 
2456     return value;
2457 }
2458 
2459 static GtkWidget *
gnc_option_set_ui_widget_string(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2460 gnc_option_set_ui_widget_string (GNCOption *option, GtkGrid *page_box,
2461                                  GtkLabel *name_label, char *documentation,
2462                                  /* Return values */
2463                                  GtkWidget **enclosing, gboolean *packed)
2464 {
2465     GtkWidget *value;
2466 
2467     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2468     gtk_widget_set_hexpand (GTK_WIDGET(*enclosing), TRUE);
2469     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2470     value = gtk_entry_new ();
2471 
2472     gnc_option_set_widget (option, value);
2473     gnc_option_set_ui_value (option, FALSE);
2474 
2475     if (gtk_widget_get_direction (GTK_WIDGET(value)) == GTK_TEXT_DIR_RTL)
2476         gtk_entry_set_alignment (GTK_ENTRY(value), 1.0);
2477 
2478     g_signal_connect (G_OBJECT(value), "changed",
2479                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2480 
2481     gtk_box_pack_start (GTK_BOX(*enclosing), value, TRUE, TRUE, 0);
2482     gtk_widget_show_all (*enclosing);
2483     return value;
2484 }
2485 
2486 static GtkWidget *
gnc_option_set_ui_widget_text(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2487 gnc_option_set_ui_widget_text (GNCOption *option, GtkGrid *page_box,
2488                                GtkLabel *name_label, char *documentation,
2489                                /* Return values */
2490                                GtkWidget **enclosing, gboolean *packed)
2491 {
2492     GtkWidget *value;
2493     GtkWidget *frame;
2494     GtkWidget *scroll;
2495     GtkTextBuffer* text_buffer;
2496 
2497     frame = gtk_frame_new(NULL);
2498 
2499     gnc_option_set_ui_label_alignment (name_label);
2500 
2501     scroll = gtk_scrolled_window_new (NULL, NULL);
2502     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scroll),
2503                                     GTK_POLICY_NEVER,
2504                                     GTK_POLICY_AUTOMATIC);
2505     gtk_container_set_border_width (GTK_CONTAINER(scroll), 2);
2506 
2507     gtk_container_add (GTK_CONTAINER(frame), scroll);
2508 
2509     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
2510     gtk_widget_set_vexpand (GTK_WIDGET(*enclosing), TRUE);
2511     gtk_widget_set_hexpand (GTK_WIDGET(*enclosing), TRUE);
2512     gtk_box_set_homogeneous (GTK_BOX (*enclosing), FALSE);
2513     value = gtk_text_view_new ();
2514     gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW(value), GTK_WRAP_WORD);
2515     gtk_text_view_set_editable (GTK_TEXT_VIEW(value), TRUE);
2516     gtk_text_view_set_accepts_tab (GTK_TEXT_VIEW(value), FALSE);
2517     gtk_container_add (GTK_CONTAINER(scroll), value);
2518 
2519     gnc_option_set_widget (option, value);
2520     gnc_option_set_ui_value (option, FALSE);
2521 
2522     text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(value));
2523     g_signal_connect (G_OBJECT(text_buffer), "changed",
2524                       G_CALLBACK(gnc_option_changed_option_cb), option);
2525 
2526     gtk_box_pack_start (GTK_BOX(*enclosing), frame, TRUE, TRUE, 0);
2527     gtk_widget_show_all (*enclosing);
2528     return value;
2529 }
2530 
2531 static GtkWidget *
gnc_option_set_ui_widget_currency(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2532 gnc_option_set_ui_widget_currency (GNCOption *option, GtkGrid *page_box,
2533                                    GtkLabel *name_label, char *documentation,
2534                                    /* Return values */
2535                                    GtkWidget **enclosing, gboolean *packed)
2536 {
2537     GtkWidget *value;
2538 
2539     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2540     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2541     value = gnc_currency_edit_new ();
2542 
2543     gnc_option_set_widget (option, value);
2544     gnc_option_set_ui_value (option, FALSE);
2545 
2546     g_signal_connect (G_OBJECT(value), "changed",
2547                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2548 
2549     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2550     gtk_widget_show_all (*enclosing);
2551     return value;
2552 }
2553 
2554 static GtkWidget *
gnc_option_set_ui_widget_commodity(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2555 gnc_option_set_ui_widget_commodity (GNCOption *option, GtkGrid *page_box,
2556                                     GtkLabel *name_label, char *documentation,
2557                                     /* Return values */
2558                                     GtkWidget **enclosing, gboolean *packed)
2559 {
2560     GtkWidget *value;
2561 
2562     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2563     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2564     value = gnc_general_select_new (GNC_GENERAL_SELECT_TYPE_SELECT,
2565                                     gnc_commodity_edit_get_string,
2566                                     gnc_commodity_edit_new_select,
2567                                     NULL);
2568 
2569     gnc_option_set_widget (option, value);
2570     gnc_option_set_ui_value (option, FALSE);
2571 
2572     if (documentation != NULL)
2573         gtk_widget_set_tooltip_text (GNC_GENERAL_SELECT(value)->entry,
2574                                      documentation);
2575 
2576     g_signal_connect (G_OBJECT(GNC_GENERAL_SELECT(value)->entry), "changed",
2577                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2578 
2579     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2580     gtk_widget_show_all (*enclosing);
2581     return value;
2582 }
2583 
2584 static GtkWidget *
gnc_option_set_ui_widget_multichoice(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2585 gnc_option_set_ui_widget_multichoice (GNCOption *option, GtkGrid *page_box,
2586                                       GtkLabel *name_label, char *documentation,
2587                                       /* Return values */
2588                                       GtkWidget **enclosing, gboolean *packed)
2589 {
2590     GtkWidget *value;
2591 
2592     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2593     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2594 
2595     value = gnc_option_create_multichoice_widget (option);
2596     gnc_option_set_widget (option, value);
2597 
2598     gnc_option_set_ui_value (option, FALSE);
2599     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2600     gtk_widget_show_all (*enclosing);
2601     return value;
2602 }
2603 
2604 static GtkWidget *
gnc_option_set_ui_widget_date(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2605 gnc_option_set_ui_widget_date (GNCOption *option, GtkGrid *page_box,
2606                                GtkLabel *name_label, char *documentation,
2607                                /* Return values */
2608                                GtkWidget **enclosing, gboolean *packed)
2609 {
2610     GtkWidget *value;
2611     gchar *colon_name;
2612     GtkWidget *eventbox;
2613     gchar *type = gnc_option_date_option_get_subtype (option);
2614 
2615 
2616     gint  grid_row = GPOINTER_TO_INT(g_object_get_data
2617                                     (G_OBJECT(page_box), "options-grid-row"));
2618 
2619     value = gnc_option_create_date_widget (option);
2620 
2621     gnc_option_set_widget (option, value);
2622 
2623     if (g_strcmp0 (type, "relative") == 0)
2624     {
2625         *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2626         gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2627 
2628         gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2629     }
2630     else
2631     {
2632         *enclosing = gtk_frame_new (NULL);
2633         g_object_set (G_OBJECT(value), "margin", 3, NULL);
2634 
2635         gtk_container_add (GTK_CONTAINER(*enclosing), value);
2636     }
2637     g_free (type);
2638 
2639     gtk_widget_set_halign (GTK_WIDGET(*enclosing), GTK_ALIGN_START);
2640 
2641     /* Pack option widget into an extra eventbox because otherwise the
2642        "documentation" tooltip is not displayed. */
2643     eventbox = gtk_event_box_new ();
2644     gtk_container_add (GTK_CONTAINER(eventbox), *enclosing);
2645 
2646     gtk_grid_attach (GTK_GRID(page_box), eventbox, 1, grid_row, 1, 1);
2647     *packed = TRUE;
2648 
2649     gtk_widget_set_tooltip_text (eventbox, documentation);
2650 
2651     gnc_option_set_ui_value (option, FALSE);
2652     gtk_widget_show_all (*enclosing);
2653     return value;
2654 }
2655 
2656 static GtkWidget *
gnc_option_set_ui_widget_account_list(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2657 gnc_option_set_ui_widget_account_list (GNCOption *option, GtkGrid *page_box,
2658                                        GtkLabel *name_label, char *documentation,
2659                                        /* Return values */
2660                                        GtkWidget **enclosing, gboolean *packed)
2661 {
2662     GtkWidget *value;
2663     GtkTreeSelection *selection;
2664     gint  grid_row = GPOINTER_TO_INT(g_object_get_data
2665                                     (G_OBJECT(page_box), "options-grid-row"));
2666 
2667     gnc_option_set_ui_label_alignment (name_label);
2668 
2669     *enclosing = gnc_option_create_account_widget (option, NULL);
2670     gtk_widget_set_vexpand (GTK_WIDGET(*enclosing), TRUE);
2671     gtk_widget_set_hexpand (GTK_WIDGET(*enclosing), TRUE);
2672     value = gnc_option_get_gtk_widget (option);
2673 
2674     gtk_widget_set_tooltip_text (*enclosing, documentation);
2675 
2676     gtk_grid_attach (GTK_GRID(page_box), *enclosing, 1, grid_row, 1, 1);
2677     *packed = TRUE;
2678 
2679     //gtk_widget_realize(value);
2680 
2681     gnc_option_set_ui_value (option, FALSE);
2682 
2683     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(value));
2684     g_signal_connect (G_OBJECT(selection), "changed",
2685                       G_CALLBACK(gnc_option_account_cb), option);
2686 
2687     //  gtk_clist_set_row_height(GTK_CLIST(value), 0);
2688     //  gtk_widget_set_size_request(value, -1, GTK_CLIST(value)->row_height * 10);
2689     gtk_widget_show_all (*enclosing);
2690     return value;
2691 }
2692 
2693 static GtkWidget *
gnc_option_set_ui_widget_account_sel(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2694 gnc_option_set_ui_widget_account_sel (GNCOption *option, GtkGrid *page_box,
2695                                       GtkLabel *name_label, char *documentation,
2696                                       /* Return values */
2697                                       GtkWidget **enclosing, gboolean *packed)
2698 {
2699     GtkWidget *value = gnc_account_sel_new ();
2700     GList *acct_type_list = gnc_option_get_account_type_list (option);
2701 
2702     gnc_account_sel_set_acct_filters (GNC_ACCOUNT_SEL(value), acct_type_list, NULL);
2703 
2704     g_signal_connect (value, "account_sel_changed",
2705                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2706 
2707     gnc_option_set_widget (option, value);
2708 
2709     gnc_option_set_ui_value (option, FALSE);
2710 
2711     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2712     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2713     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2714     gtk_widget_show_all (*enclosing);
2715     return value;
2716 }
2717 
2718 static GtkWidget *
gnc_option_set_ui_widget_list(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2719 gnc_option_set_ui_widget_list (GNCOption *option, GtkGrid *page_box,
2720                                GtkLabel *name_label, char *documentation,
2721                                /* Return values */
2722                                GtkWidget **enclosing, gboolean *packed)
2723 {
2724     GtkWidget *value;
2725     GtkWidget *eventbox;
2726     gint       grid_row = GPOINTER_TO_INT(g_object_get_data
2727                                          (G_OBJECT(page_box), "options-grid-row"));
2728 
2729     *enclosing = gnc_option_create_list_widget (option, NULL);
2730     value = gnc_option_get_gtk_widget (option);
2731 
2732     gnc_option_set_ui_label_alignment (name_label);
2733 
2734     /* Pack option widget into an extra eventbox because otherwise the
2735        "documentation" tooltip is not displayed. */
2736     eventbox = gtk_event_box_new ();
2737     gtk_container_add (GTK_CONTAINER(eventbox), *enclosing);
2738 
2739     gtk_grid_attach (GTK_GRID(page_box), eventbox, 1, grid_row, 1, 1);
2740     *packed = TRUE;
2741 
2742     gtk_widget_set_tooltip_text (eventbox, documentation);
2743 
2744     gnc_option_set_ui_value (option, FALSE);
2745     gtk_widget_show (*enclosing);
2746     return value;
2747 }
2748 
2749 static GtkWidget *
gnc_option_set_ui_widget_number_range(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2750 gnc_option_set_ui_widget_number_range (GNCOption *option, GtkGrid *page_box,
2751                                        GtkLabel *name_label, char *documentation,
2752                                        /* Return values */
2753                                        GtkWidget **enclosing, gboolean *packed)
2754 {
2755     GtkWidget *value;
2756     GtkAdjustment *adj;
2757     gdouble lower_bound = G_MINDOUBLE;
2758     gdouble upper_bound = G_MAXDOUBLE;
2759     gdouble step_size = 1.0;
2760     int num_decimals = 0;
2761 
2762     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2763     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2764 
2765     gnc_option_get_range_info (option, &lower_bound, &upper_bound,
2766                                &num_decimals, &step_size);
2767     adj = GTK_ADJUSTMENT(gtk_adjustment_new (lower_bound, lower_bound,
2768                                              upper_bound, step_size,
2769                                              step_size * 5.0,
2770                                              0));
2771     value = gtk_spin_button_new (adj, step_size, num_decimals);
2772     gtk_spin_button_set_numeric (GTK_SPIN_BUTTON(value), TRUE);
2773 
2774     {
2775         gdouble biggest;
2776         gint num_digits;
2777 
2778         biggest = ABS(lower_bound);
2779         biggest = MAX(biggest, ABS(upper_bound));
2780 
2781         num_digits = 0;
2782         while (biggest >= 1)
2783         {
2784             num_digits++;
2785             biggest = biggest / 10;
2786         }
2787 
2788         if (num_digits == 0)
2789             num_digits = 1;
2790 
2791         num_digits += num_decimals;
2792 
2793         gtk_entry_set_width_chars (GTK_ENTRY(value), num_digits);
2794     }
2795 
2796     gnc_option_set_widget (option, value);
2797     gnc_option_set_ui_value (option, FALSE);
2798 
2799     g_signal_connect (G_OBJECT(value), "changed",
2800                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2801 
2802     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2803     gtk_widget_show_all (*enclosing);
2804     return value;
2805 }
2806 
2807 static GtkWidget *
gnc_option_set_ui_widget_color(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2808 gnc_option_set_ui_widget_color (GNCOption *option, GtkGrid *page_box,
2809                                 GtkLabel *name_label, char *documentation,
2810                                 /* Return values */
2811                                 GtkWidget **enclosing, gboolean *packed)
2812 {
2813     GtkWidget *value;
2814     gboolean use_alpha;
2815 
2816     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2817     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2818 
2819     use_alpha = gnc_option_use_alpha (option);
2820 
2821     value = gtk_color_button_new ();
2822     gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER(value), use_alpha);
2823 
2824     gnc_option_set_widget (option, value);
2825     gnc_option_set_ui_value (option, FALSE);
2826 
2827     g_signal_connect (G_OBJECT(value), "color-set",
2828                       G_CALLBACK(gnc_option_color_changed_cb), option);
2829 
2830     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2831     gtk_widget_show_all (*enclosing);
2832     return value;
2833 }
2834 
2835 static GtkWidget *
gnc_option_set_ui_widget_font(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2836 gnc_option_set_ui_widget_font (GNCOption *option, GtkGrid *page_box,
2837                                GtkLabel *name_label, char *documentation,
2838                                /* Return values */
2839                                GtkWidget **enclosing, gboolean *packed)
2840 {
2841     GtkWidget *value;
2842 
2843     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2844     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2845     value = gtk_font_button_new ();
2846     g_object_set (G_OBJECT(value),
2847                   "use-font", TRUE,
2848                   "show-style", TRUE,
2849                   "show-size", TRUE,
2850                   (char *)NULL);
2851 
2852     gnc_option_set_widget (option, value);
2853 
2854     gnc_option_set_ui_value (option, FALSE);
2855 
2856     g_signal_connect (G_OBJECT(value), "font-set",
2857                       G_CALLBACK(gnc_option_font_changed_cb), option);
2858 
2859     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2860     gtk_widget_show_all (*enclosing);
2861     return value;
2862 }
2863 
2864 static GtkWidget *
gnc_option_set_ui_widget_pixmap(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2865 gnc_option_set_ui_widget_pixmap (GNCOption *option, GtkGrid *page_box,
2866                                  GtkLabel *name_label, char *documentation,
2867                                  /* Return values */
2868                                  GtkWidget **enclosing, gboolean *packed)
2869 {
2870     GtkWidget *value;
2871     GtkWidget *button;
2872 
2873     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2874     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2875 
2876     button = gtk_button_new_with_label (_("Clear"));
2877     gtk_widget_set_tooltip_text (button, _("Clear any selected image file."));
2878 
2879     value = gtk_file_chooser_button_new (_("Select image"),
2880                                          GTK_FILE_CHOOSER_ACTION_OPEN);
2881     gtk_widget_set_tooltip_text (value, _("Select an image file."));
2882     g_object_set (G_OBJECT(value),
2883                   "width-chars", 30,
2884                   "preview-widget", gtk_image_new(),
2885                   (char *)NULL);
2886     g_signal_connect (G_OBJECT(value), "selection-changed",
2887                       G_CALLBACK(gnc_option_changed_widget_cb), option);
2888     g_signal_connect (G_OBJECT(value), "selection-changed",
2889                       G_CALLBACK(gnc_image_option_selection_changed_cb), option);
2890     g_signal_connect (G_OBJECT(value), "update-preview",
2891                       G_CALLBACK(gnc_image_option_update_preview_cb), option);
2892     g_signal_connect_swapped (G_OBJECT(button), "clicked",
2893                               G_CALLBACK(gtk_file_chooser_unselect_all), value);
2894 
2895     gnc_option_set_widget (option, value);
2896     gnc_option_set_ui_value (option, FALSE);
2897 
2898     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2899     gtk_box_pack_start (GTK_BOX(*enclosing), button, FALSE, FALSE, 0);
2900 
2901     gtk_widget_show (value);
2902     gtk_widget_show (*enclosing);
2903 
2904     return value;
2905 }
2906 
2907 static GtkWidget *
gnc_option_set_ui_widget_radiobutton(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2908 gnc_option_set_ui_widget_radiobutton (GNCOption *option, GtkGrid *page_box,
2909                                       GtkLabel *name_label, char *documentation,
2910                                       /* Return values */
2911                                       GtkWidget **enclosing, gboolean *packed)
2912 {
2913     GtkWidget *value;
2914 
2915     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
2916     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
2917 
2918     gnc_option_set_ui_label_alignment (name_label);
2919 
2920     value = gnc_option_create_radiobutton_widget (NULL, option);
2921     gnc_option_set_widget (option, value);
2922 
2923     gnc_option_set_ui_value (option, FALSE);
2924     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
2925     gtk_widget_show_all (*enclosing);
2926     return value;
2927 }
2928 
2929 static GtkWidget *
gnc_option_set_ui_widget_dateformat(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2930 gnc_option_set_ui_widget_dateformat (GNCOption *option, GtkGrid *page_box,
2931                                      GtkLabel *name_label, char *documentation,
2932                                      /* Return values */
2933                                      GtkWidget **enclosing, gboolean *packed)
2934 {
2935     *enclosing = gnc_date_format_new_without_label ();
2936     gnc_option_set_widget (option, *enclosing);
2937 
2938     gnc_option_set_ui_label_alignment (name_label);
2939 
2940     gnc_option_set_ui_value (option, FALSE);
2941     g_signal_connect (G_OBJECT(*enclosing), "format_changed",
2942                       G_CALLBACK(gnc_option_changed_option_cb), option);
2943     gtk_widget_show_all (*enclosing);
2944     return *enclosing;
2945 }
2946 
2947 static void
gnc_plot_size_option_set_select_method(GNCOption * option,gboolean set_buttons)2948 gnc_plot_size_option_set_select_method (GNCOption *option, gboolean set_buttons)
2949 {
2950     GList* widget_list;
2951     GtkWidget *px_widget, *p_widget;
2952     GtkWidget *widget;
2953 
2954     widget = gnc_option_get_gtk_widget (option);
2955 
2956     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
2957     // px_button item 0
2958     px_widget = g_list_nth_data (widget_list, 1);
2959     // p_button item 2
2960     p_widget = g_list_nth_data (widget_list, 3);
2961     g_list_free (widget_list);
2962 
2963     if (set_buttons)
2964     {
2965         gtk_widget_set_sensitive (px_widget, TRUE);
2966         gtk_widget_set_sensitive (p_widget, FALSE);
2967     }
2968     else
2969     {
2970         gtk_widget_set_sensitive (p_widget, TRUE);
2971         gtk_widget_set_sensitive (px_widget, FALSE);
2972     }
2973 }
2974 
2975 static void
gnc_rd_option_px_set_cb(GtkWidget * widget,gpointer * raw_option)2976 gnc_rd_option_px_set_cb (GtkWidget *widget, gpointer *raw_option)
2977 {
2978     GNCOption *option = (GNCOption *) raw_option;
2979     gnc_plot_size_option_set_select_method (option, TRUE);
2980     gnc_option_changed_option_cb (widget, option);
2981 }
2982 
2983 static void
gnc_rd_option_p_set_cb(GtkWidget * widget,gpointer * raw_option)2984 gnc_rd_option_p_set_cb (GtkWidget *widget, gpointer *raw_option)
2985 {
2986     GNCOption *option = (GNCOption *) raw_option;
2987     gnc_plot_size_option_set_select_method (option, FALSE);
2988     gnc_option_changed_option_cb (widget, option);
2989     return;
2990 }
2991 
2992 static GtkWidget *
gnc_option_set_ui_widget_plot_size(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)2993 gnc_option_set_ui_widget_plot_size (GNCOption *option, GtkGrid *page_box,
2994                                      GtkLabel *name_label, char *documentation,
2995                                      /* Return values */
2996                                      GtkWidget **enclosing, gboolean *packed)
2997 {
2998     GtkWidget *value_px, *value_percent;
2999     GtkWidget *px_butt, *p_butt;
3000     GtkWidget *hbox;
3001     GtkAdjustment *adj_px, *adj_percent;
3002     gdouble lower_bound = G_MINDOUBLE;
3003     gdouble upper_bound = G_MAXDOUBLE;
3004     gdouble step_size = 1.0;
3005     int num_decimals = 0;
3006 
3007     *enclosing = gtk_frame_new (NULL);
3008     gtk_widget_set_halign (GTK_WIDGET(*enclosing), GTK_ALIGN_START);
3009 
3010     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
3011     gtk_box_set_homogeneous (GTK_BOX(hbox), FALSE);
3012     g_object_set (G_OBJECT(hbox), "margin", 3, NULL);
3013 
3014     gtk_container_add (GTK_CONTAINER(*enclosing), hbox);
3015 
3016     gnc_option_get_range_info (option, &lower_bound, &upper_bound,
3017                                &num_decimals, &step_size);
3018     adj_px = GTK_ADJUSTMENT(gtk_adjustment_new (lower_bound, lower_bound,
3019                                                 upper_bound, step_size,
3020                                                 step_size * 5.0,
3021                                                 0));
3022 
3023     value_px = gtk_spin_button_new (adj_px, step_size, num_decimals);
3024     gtk_spin_button_set_numeric (GTK_SPIN_BUTTON(value_px), TRUE);
3025 
3026     {
3027         gdouble biggest;
3028         gint num_digits;
3029 
3030         biggest = ABS(lower_bound);
3031         biggest = MAX(biggest, ABS(upper_bound));
3032 
3033         num_digits = 0;
3034         while (biggest >= 1)
3035         {
3036             num_digits++;
3037             biggest = biggest / 10;
3038         }
3039 
3040         if (num_digits == 0)
3041             num_digits = 1;
3042 
3043         num_digits += num_decimals;
3044 
3045         gtk_entry_set_width_chars (GTK_ENTRY(value_px), num_digits);
3046     }
3047     gtk_spin_button_set_value (GTK_SPIN_BUTTON(value_px), (upper_bound / 2)); //default
3048     g_signal_connect (G_OBJECT(value_px), "changed",
3049                       G_CALLBACK(gnc_option_changed_widget_cb), option);
3050 
3051     adj_percent = GTK_ADJUSTMENT(gtk_adjustment_new (1, 10, 100, 1, 5.0, 0));
3052     value_percent = gtk_spin_button_new (adj_percent, 1, 0);
3053     gtk_spin_button_set_numeric (GTK_SPIN_BUTTON(value_percent), TRUE);
3054     gtk_spin_button_set_value (GTK_SPIN_BUTTON(value_percent), 100); //default
3055     gtk_entry_set_width_chars (GTK_ENTRY(value_percent), 3);
3056     gtk_widget_set_sensitive (value_percent, FALSE);
3057 
3058     g_signal_connect (G_OBJECT(value_percent), "changed",
3059                       G_CALLBACK(gnc_option_changed_widget_cb), option);
3060 
3061     px_butt = gtk_radio_button_new_with_label (NULL, _("Pixels"));
3062     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(px_butt), TRUE);
3063 
3064     g_signal_connect (G_OBJECT(px_butt), "toggled",
3065                       G_CALLBACK(gnc_rd_option_px_set_cb), option);
3066 
3067     p_butt = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(px_butt), _("Percent"));
3068     g_signal_connect (G_OBJECT(p_butt), "toggled",
3069                       G_CALLBACK(gnc_rd_option_p_set_cb), option);
3070 
3071     gtk_box_pack_start (GTK_BOX(hbox), px_butt, FALSE, FALSE, 0);
3072     gtk_box_pack_start (GTK_BOX(hbox), value_px, FALSE, FALSE, 0);
3073     gtk_box_pack_start (GTK_BOX(hbox), p_butt, FALSE, FALSE, 0);
3074     gtk_box_pack_start (GTK_BOX(hbox), value_percent, FALSE, FALSE, 0);
3075 
3076     gnc_option_set_widget (option, hbox);
3077     gnc_option_set_ui_value (option, FALSE);
3078 
3079     gtk_widget_show_all (*enclosing);
3080     return hbox;
3081 }
3082 
3083 static GtkWidget *
gnc_option_set_ui_widget_budget(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)3084 gnc_option_set_ui_widget_budget (GNCOption *option, GtkGrid *page_box,
3085                                  GtkLabel *name_label, char *documentation,
3086                                  /* Return values */
3087                                  GtkWidget **enclosing, gboolean *packed)
3088 {
3089     GtkWidget *value;
3090 
3091 
3092     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
3093     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
3094 
3095     value = gnc_option_create_budget_widget (option);
3096 
3097     gnc_option_set_widget (option, value);
3098     gnc_option_set_ui_value (option, FALSE);
3099 
3100     /* Maybe connect destroy handler for tree model here? */
3101     g_signal_connect (G_OBJECT(value), "changed",
3102                       G_CALLBACK(gnc_option_changed_widget_cb), option);
3103 
3104     gtk_box_pack_start (GTK_BOX(*enclosing), value, FALSE, FALSE, 0);
3105     gtk_widget_show_all (*enclosing);
3106     return value;
3107 }
3108 
3109 static GtkWidget *
gnc_option_set_ui_widget_currency_accounting(GNCOption * option,GtkGrid * page_box,GtkLabel * name_label,char * documentation,GtkWidget ** enclosing,gboolean * packed)3110 gnc_option_set_ui_widget_currency_accounting (GNCOption *option,
3111                                               GtkGrid *page_box,
3112                                               GtkLabel *name_label, char *documentation,
3113                                               /* Return values */
3114                                               GtkWidget **enclosing,
3115                                               gboolean *packed)
3116 {
3117     GtkWidget *value;
3118 
3119     *enclosing = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
3120     gtk_box_set_homogeneous (GTK_BOX(*enclosing), FALSE);
3121 
3122     value = gnc_option_create_currency_accounting_widget (NULL, option);
3123     gnc_option_set_widget (option, value);
3124 
3125     gnc_option_set_ui_value (option, FALSE);
3126     gtk_box_pack_start (GTK_BOX(*enclosing), value, TRUE, TRUE, 0);
3127     gtk_widget_show_all (*enclosing);
3128     return value;
3129 }
3130 
3131 /*************************
3132  *       SET VALUE       *
3133  *************************
3134  *
3135  * gnc_option_set_ui_value_<type>():
3136  *
3137  *   In this function you should set the state of the gui widget to
3138  * correspond to the value provided in 'value'.  You should return
3139  * TRUE if there was an error, FALSE otherwise.
3140  *
3141  *
3142  */
3143 static gboolean
gnc_option_set_ui_value_boolean(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3144 gnc_option_set_ui_value_boolean (GNCOption *option, gboolean use_default,
3145                                  GtkWidget *widget, SCM value)
3146 {
3147     if (scm_is_bool (value))
3148     {
3149         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget),
3150                                       scm_is_true(value));
3151         return FALSE;
3152     }
3153     else
3154         return TRUE;
3155 }
3156 
3157 static gboolean
gnc_option_set_ui_value_string(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3158 gnc_option_set_ui_value_string (GNCOption *option, gboolean use_default,
3159                                 GtkWidget *widget, SCM value)
3160 {
3161     if (scm_is_string (value))
3162     {
3163         const gchar *string;
3164 
3165         string = gnc_scm_to_utf8_string (value);
3166         gtk_entry_set_text (GTK_ENTRY(widget), string);
3167         g_free ((gpointer *) string);
3168         return FALSE;
3169     }
3170     else
3171         return TRUE;
3172 }
3173 
3174 static gboolean
gnc_option_set_ui_value_text(GNCOption * option,gboolean use_default,GObject * object,SCM value)3175 gnc_option_set_ui_value_text (GNCOption *option, gboolean use_default,
3176                               GObject *object, SCM value)
3177 {
3178     GtkTextBuffer *buffer;
3179 
3180     if (GTK_IS_TEXT_BUFFER(object))
3181         buffer = GTK_TEXT_BUFFER(object);
3182     else
3183         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(object));
3184 
3185     if (scm_is_string (value))
3186     {
3187         const gchar *string;
3188 
3189         string = gnc_scm_to_utf8_string (value);
3190         gtk_text_buffer_set_text (buffer, string, -1);
3191         free ((void*) string);
3192         return FALSE;
3193     }
3194     else
3195         return TRUE;
3196 }
3197 
3198 static gboolean
gnc_option_set_ui_value_currency(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3199 gnc_option_set_ui_value_currency (GNCOption *option, gboolean use_default,
3200                                   GtkWidget *widget, SCM value)
3201 {
3202     gnc_commodity *commodity;
3203 
3204     commodity = gnc_scm_to_commodity (value);
3205     if (commodity)
3206     {
3207         gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(widget), commodity);
3208         return FALSE;
3209     }
3210     else
3211         return TRUE;
3212 }
3213 
3214 static gboolean
gnc_option_set_ui_value_commodity(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3215 gnc_option_set_ui_value_commodity (GNCOption *option, gboolean use_default,
3216                                    GtkWidget *widget, SCM value)
3217 {
3218     gnc_commodity *commodity;
3219 
3220     commodity = gnc_scm_to_commodity (value);
3221     if (commodity)
3222     {
3223         gnc_general_select_set_selected (GNC_GENERAL_SELECT(widget), commodity);
3224         return FALSE;
3225     }
3226     else
3227         return TRUE;
3228 }
3229 
3230 static gboolean
gnc_option_set_ui_value_multichoice(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3231 gnc_option_set_ui_value_multichoice (GNCOption *option, gboolean use_default,
3232                                      GtkWidget *widget, SCM value)
3233 {
3234     int index;
3235 
3236     index = gnc_option_permissible_value_index (option, value);
3237     if (index < 0)
3238         return TRUE;
3239     else
3240     {
3241         gtk_combo_box_set_active (GTK_COMBO_BOX(widget), index);
3242         return FALSE;
3243     }
3244 }
3245 
3246 static gboolean
gnc_option_set_ui_value_date(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3247 gnc_option_set_ui_value_date (GNCOption *option, gboolean use_default,
3248                               GtkWidget *widget, SCM value)
3249 {
3250     int index;
3251     char *date_option_type;
3252     char *symbol_str;
3253     gboolean bad_value = FALSE;
3254 
3255     date_option_type = gnc_option_date_option_get_subtype (option);
3256 
3257     if (scm_is_pair (value))
3258     {
3259         symbol_str = gnc_date_option_value_get_type (value);
3260         if (symbol_str)
3261         {
3262             if (g_strcmp0 (symbol_str, "relative") == 0)
3263             {
3264                 SCM relative = gnc_date_option_value_get_relative (value);
3265 
3266                 index = gnc_option_permissible_value_index (option, relative);
3267                 if (g_strcmp0 (date_option_type, "relative") == 0)
3268                 {
3269                     gtk_combo_box_set_active (GTK_COMBO_BOX(widget), index);
3270                 }
3271                 else if (g_strcmp0 (date_option_type, "both") == 0)
3272                 {
3273                     GList *widget_list;
3274                     GtkWidget *rel_date_widget;
3275 
3276                     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
3277                     rel_date_widget = g_list_nth_data (widget_list,
3278                                                        GNC_RD_WID_REL_WIDGET_POS);
3279                     g_list_free (widget_list);
3280                     gnc_date_option_set_select_method (option, FALSE, TRUE);
3281                     gtk_combo_box_set_active (GTK_COMBO_BOX(rel_date_widget), index);
3282                 }
3283                 else
3284                     bad_value = TRUE;
3285             }
3286             else if (g_strcmp0 (symbol_str, "absolute") == 0)
3287             {
3288                 time64 time;
3289 
3290                 time = gnc_date_option_value_get_absolute (value);
3291 
3292                 if (g_strcmp0 (date_option_type, "absolute") == 0)
3293                 {
3294                     gnc_date_edit_set_time (GNC_DATE_EDIT(widget), time);
3295                 }
3296                 else if (g_strcmp0 (date_option_type, "both") == 0)
3297                 {
3298                     GList *widget_list;
3299                     GtkWidget *ab_widget;
3300 
3301                     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
3302                     ab_widget = g_list_nth_data (widget_list,
3303                                                  GNC_RD_WID_AB_WIDGET_POS);
3304                     g_list_free (widget_list);
3305                     gnc_date_option_set_select_method (option, TRUE, TRUE);
3306                     gnc_date_edit_set_time (GNC_DATE_EDIT(ab_widget), time);
3307                 }
3308                 else
3309                     bad_value = TRUE;
3310             }
3311             else
3312                 bad_value = TRUE;
3313 
3314             if (symbol_str)
3315                 free (symbol_str);
3316         }
3317     }
3318     else
3319         bad_value = TRUE;
3320 
3321     if (date_option_type)
3322         free (date_option_type);
3323 
3324     return bad_value;
3325 }
3326 
3327 static gboolean
gnc_option_set_ui_value_account_list(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3328 gnc_option_set_ui_value_account_list (GNCOption *option, gboolean use_default,
3329                                       GtkWidget *widget, SCM value)
3330 {
3331     GList *list;
3332 
3333     list = gnc_scm_list_to_glist (value);
3334 
3335     gnc_tree_view_account_set_selected_accounts (GNC_TREE_VIEW_ACCOUNT(widget),
3336                                                  list, TRUE);
3337     g_list_free (list);
3338     return FALSE;
3339 }
3340 
3341 static gboolean
gnc_option_set_ui_value_account_sel(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3342 gnc_option_set_ui_value_account_sel (GNCOption *option, gboolean use_default,
3343                                      GtkWidget *widget, SCM value)
3344 {
3345     Account *acc = NULL;
3346 
3347     if (value != SCM_BOOL_F)
3348     {
3349         if (!SWIG_IsPointer (value))
3350             scm_misc_error ("gnc_option_set_ui_value_account_sel",
3351                             "Option Value not a wcp.", value);
3352 
3353         acc = SWIG_MustGetPtr (value, SWIG_TypeQuery ("_p_Account"), 4, 0);
3354     }
3355 
3356     //doesn't default because this function is called to set a specific account
3357     gnc_account_sel_set_account (GNC_ACCOUNT_SEL(widget), acc, FALSE);
3358 
3359     return FALSE;
3360 }
3361 
3362 static gboolean
gnc_option_set_ui_value_list(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3363 gnc_option_set_ui_value_list (GNCOption *option, gboolean use_default,
3364                               GtkWidget *widget, SCM value)
3365 {
3366     GtkTreeSelection *selection;
3367     GtkTreePath *path;
3368     gint row;
3369 
3370     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(widget));
3371     gtk_tree_selection_unselect_all (selection);
3372 
3373     while (scm_is_list (value) && !scm_is_null (value))
3374     {
3375         SCM item;
3376 
3377         item = SCM_CAR(value);
3378         value = SCM_CDR(value);
3379 
3380         row = gnc_option_permissible_value_index (option, item);
3381         if (row < 0)
3382         {
3383             return TRUE;
3384         }
3385 
3386         path = gtk_tree_path_new_from_indices (row, -1);
3387         gtk_tree_selection_select_path (selection, path);
3388         gtk_tree_path_free (path);
3389     }
3390 
3391     if (!scm_is_list (value) || !scm_is_null (value))
3392         return TRUE;
3393 
3394     return FALSE;
3395 }
3396 
3397 static gboolean
gnc_option_set_ui_value_number_range(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3398 gnc_option_set_ui_value_number_range (GNCOption *option, gboolean use_default,
3399                                       GtkWidget *widget, SCM value)
3400 {
3401     GtkSpinButton *spinner;
3402     gdouble d_value;
3403 
3404     spinner = GTK_SPIN_BUTTON(widget);
3405 
3406     if (scm_is_number (value))
3407     {
3408         d_value = scm_to_double (value);
3409         gtk_spin_button_set_value (spinner, d_value);
3410         return FALSE;
3411     }
3412     else
3413         return TRUE;
3414 }
3415 
3416 static gboolean
gnc_option_set_ui_value_color(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3417 gnc_option_set_ui_value_color (GNCOption *option, gboolean use_default,
3418                                GtkWidget *widget, SCM value)
3419 {
3420 
3421     GdkRGBA color;
3422     if (gnc_option_get_color_info (option, use_default,
3423                                    &color.red, &color.green,
3424                                    &color.blue, &color.alpha))
3425     {
3426         GtkColorChooser *color_button;
3427 
3428         DEBUG("red %f, green %f, blue %f, alpha %f",
3429               color.red, color.green, color.blue, color.alpha);
3430         color_button = GTK_COLOR_CHOOSER(widget);
3431 
3432         gtk_color_chooser_set_rgba (color_button, &color);
3433         return FALSE;
3434     }
3435 
3436     LEAVE("TRUE");
3437     return TRUE;
3438 }
3439 
3440 static gboolean
gnc_option_set_ui_value_font(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3441 gnc_option_set_ui_value_font (GNCOption *option, gboolean use_default,
3442                               GtkWidget *widget, SCM value)
3443 {
3444     if (scm_is_string (value))
3445     {
3446         const gchar *string;
3447 
3448         string = gnc_scm_to_utf8_string (value);
3449         if ((string != NULL) && (*string != '\0'))
3450         {
3451             GtkFontButton *font_button = GTK_FONT_BUTTON(widget);
3452             gtk_font_button_set_font_name (font_button, string);
3453         }
3454         g_free ((gpointer *) string);
3455         return FALSE;
3456     }
3457     else
3458         return TRUE;
3459 }
3460 
3461 static gboolean
gnc_option_set_ui_value_pixmap(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3462 gnc_option_set_ui_value_pixmap (GNCOption *option, gboolean use_default,
3463                                 GtkWidget *widget, SCM value)
3464 {
3465     ENTER("option %p(%s)", option, gnc_option_name (option));
3466     if (scm_is_string (value))
3467     {
3468         const gchar *string;
3469 
3470         string = gnc_scm_to_locale_string (value);
3471         if (string && *string)
3472         {
3473             gchar *test;
3474             DEBUG("string = %s", string);
3475             gtk_file_chooser_select_filename (GTK_FILE_CHOOSER(widget), string);
3476             test = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(widget));
3477             g_object_set_data_full (G_OBJECT(widget), LAST_SELECTION,
3478                                     g_strdup (string), g_free);
3479             DEBUG("Set %s, retrieved %s", string, test ? test : "(null)");
3480             gnc_image_option_update_preview_cb (GTK_FILE_CHOOSER(widget), option);
3481         }
3482         LEAVE("FALSE");
3483         g_free ((gpointer *) string);
3484         return FALSE;
3485     }
3486 
3487     LEAVE("TRUE");
3488     return TRUE;
3489 }
3490 
gnc_option_set_ui_value_budget(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3491 static gboolean gnc_option_set_ui_value_budget (GNCOption *option,
3492                                                 gboolean use_default,
3493                                                 GtkWidget *widget,
3494                                                 SCM value)
3495 {
3496     GncBudget *bgt;
3497 
3498 //    if (!scm_is_null(value)) {
3499     if (value != SCM_BOOL_F)
3500     {
3501         if (!SWIG_IsPointer (value))
3502             scm_misc_error ("gnc_option_set_ui_value_budget",
3503                             "Option Value not a wcp.", value);
3504 
3505         bgt = SWIG_MustGetPtr (value, SWIG_TypeQuery ("GncBudget *"), 4, 0);
3506         if (bgt)
3507         {
3508             GtkComboBox *cb = GTK_COMBO_BOX(widget);
3509             GtkTreeModel *tm = gtk_combo_box_get_model (cb);
3510             GtkTreeIter iter;
3511             if (gnc_tree_model_budget_get_iter_for_budget (tm, &iter, bgt))
3512                 gtk_combo_box_set_active_iter (cb, &iter);
3513         }
3514     }
3515     //FIXME: Unimplemented.
3516     return FALSE;
3517 }
3518 
3519 static gboolean
gnc_option_set_ui_value_radiobutton(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3520 gnc_option_set_ui_value_radiobutton (GNCOption *option, gboolean use_default,
3521                                      GtkWidget *widget, SCM value)
3522 {
3523     int index;
3524 
3525     index = gnc_option_permissible_value_index (option, value);
3526     if (index < 0)
3527         return TRUE;
3528     else
3529     {
3530         GtkWidget *box, *button;
3531         GList *list;
3532         int i;
3533         gpointer val;
3534 
3535         list = gtk_container_get_children (GTK_CONTAINER(widget));
3536         box = list->data;
3537         g_list_free(list);
3538 
3539         list = gtk_container_get_children (GTK_CONTAINER(box));
3540         button = g_list_nth_data (list, index);
3541         g_list_free (list);
3542         g_return_val_if_fail (button, TRUE);
3543         val = g_object_get_data (G_OBJECT(button), "gnc_radiobutton_index");
3544         g_return_val_if_fail (GPOINTER_TO_INT(val) == index, TRUE);
3545 
3546         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE);
3547         //    g_object_set_data(G_OBJECT(widget), "gnc_radiobutton_index",
3548         //          GINT_TO_POINTER(index));
3549         return FALSE;
3550     }
3551 }
3552 
3553 static gboolean
gnc_option_set_ui_value_dateformat(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3554 gnc_option_set_ui_value_dateformat (GNCOption *option, gboolean use_default,
3555                                     GtkWidget *widget, SCM value)
3556 {
3557     GNCDateFormat * gdf = GNC_DATE_FORMAT(widget);
3558     QofDateFormat format;
3559     GNCDateMonthFormat months;
3560     gboolean years;
3561     char *custom;
3562 
3563     if (gnc_dateformat_option_value_parse (value, &format, &months, &years, &custom))
3564         return TRUE;
3565 
3566     gnc_date_format_set_format (gdf, format);
3567     gnc_date_format_set_months (gdf, months);
3568     gnc_date_format_set_years (gdf, years);
3569     gnc_date_format_set_custom (gdf, custom);
3570     gnc_date_format_refresh (gdf);
3571 
3572     if (custom)
3573         free (custom);
3574 
3575     return FALSE;
3576 }
3577 
3578 static gboolean
gnc_option_set_ui_value_plot_size(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3579 gnc_option_set_ui_value_plot_size (GNCOption *option, gboolean use_default,
3580                                    GtkWidget *widget, SCM value)
3581 {
3582     GList* widget_list;
3583     GtkWidget *px_button, *p_button, *px_widget, *p_widget;
3584     char *symbol_str;
3585     gdouble d_value;
3586 
3587     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
3588     px_button = g_list_nth_data (widget_list, 0);
3589     px_widget = g_list_nth_data (widget_list, 1);
3590     p_button = g_list_nth_data (widget_list, 2);
3591     p_widget = g_list_nth_data (widget_list, 3);
3592     g_list_free (widget_list);
3593 
3594     if (scm_is_pair (value))
3595     {
3596         symbol_str = gnc_plot_size_option_value_get_type (value);
3597         d_value = gnc_plot_size_option_value_get_value (value);
3598 
3599         if (symbol_str)
3600         {
3601             if (g_strcmp0 (symbol_str, "pixels") == 0) // pixel values
3602             {
3603                 gtk_spin_button_set_value (GTK_SPIN_BUTTON(px_widget), d_value);
3604                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(px_button), TRUE);
3605             }
3606             else // percent values
3607             {
3608                 gtk_spin_button_set_value (GTK_SPIN_BUTTON(p_widget), (d_value));
3609                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(p_button), TRUE);
3610             }
3611             return FALSE;
3612         }
3613     }
3614     return TRUE;
3615 }
3616 
3617 static gboolean
gnc_option_set_ui_value_currency_accounting(GNCOption * option,gboolean use_default,GtkWidget * widget,SCM value)3618 gnc_option_set_ui_value_currency_accounting (GNCOption *option,
3619                                              gboolean use_default,
3620                                              GtkWidget *widget, SCM value)
3621 {
3622     if (scm_is_pair (value))
3623     {
3624         SCM rb_symbol;
3625 
3626         rb_symbol = gnc_currency_accounting_option_value_get_method (value);
3627 
3628         if (rb_symbol)
3629         {
3630             int index;
3631 
3632             index = gnc_option_permissible_value_index (option, rb_symbol);
3633             if (index < 0)
3634                 return TRUE;
3635             else
3636             {
3637                 GtkWidget *button = NULL;
3638                 gpointer val;
3639 
3640                 switch (index)
3641                 {
3642                     case 0:
3643                         button = book_currency_data->gnc_currency_radiobutton_0;
3644                         break;
3645                     case 1:
3646                         button = book_currency_data->gnc_currency_radiobutton_1;
3647                         break;
3648                     case 2:
3649                         button = book_currency_data->gnc_currency_radiobutton_2;
3650                         break;
3651                     default:
3652                         return TRUE;
3653                 }
3654 
3655                 val = g_object_get_data (G_OBJECT(button),
3656                                             "gnc_radiobutton_index");
3657                 g_return_val_if_fail (GPOINTER_TO_INT(val) == index, TRUE);
3658 
3659                 if (g_strcmp0 (gnc_option_permissible_value_name (option,
3660                                                                   index),
3661                                 "Use a Book Currency") == 0)
3662                 {
3663                     gnc_commodity *commodity = NULL;
3664                     SCM curr_scm =
3665                         gnc_currency_accounting_option_value_get_book_currency
3666                             (value);
3667                     SCM list_symbol =
3668                         gnc_currency_accounting_option_value_get_default_policy
3669                             (value);
3670                     SCM acct_guid_scm =
3671                         gnc_currency_accounting_option_value_get_default_account
3672                             (value);
3673 
3674                     commodity = gnc_scm_to_commodity (curr_scm);
3675                     if (commodity)
3676                     {
3677                         book_currency_data->retrieved_book_currency = commodity;
3678                     }
3679                     else
3680                     {
3681                         book_currency_data->retrieved_book_currency = NULL;
3682                     }
3683                     if (list_symbol)
3684                     {
3685                         book_currency_data->retrieved_policy_scm = list_symbol;
3686                     }
3687                     else
3688                     {
3689                         book_currency_data->retrieved_policy_scm = NULL;
3690                     }
3691                     if (acct_guid_scm)
3692                     {
3693                         book_currency_data->retrieved_gain_loss_acct_guid_scm =
3694                                                                 acct_guid_scm;
3695                     }
3696                     else
3697                     {
3698                         book_currency_data->retrieved_gain_loss_acct_guid_scm =
3699                                                                         NULL;
3700                     }
3701                 }
3702                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button), TRUE);
3703                 /* when an unselected button in a group is clicked the clicked
3704                    button receives the “toggled” signal, as does the
3705                    previously selected button; however, if the first button
3706                    is active when the currency-accounting dialog is created,
3707                    that is, it's read from the option, the "toggled" handler
3708                    is not called while it is if any other button is active.
3709                    To get desired result, that is, to set sensitivity to
3710                    FALSE, explicitly call the handler here if first button */
3711                 if (index == 0)
3712                 {
3713                     gnc_option_currency_accounting_non_book_cb (button,
3714                         (gpointer) book_currency_data);
3715                 }
3716                 return FALSE;
3717             }
3718         }
3719         return TRUE;
3720     }
3721     return TRUE;
3722 }
3723 
3724 /*************************
3725  *       GET VALUE       *
3726  *************************
3727  *
3728  * gnc_option_get_ui_value_<type>():
3729  *
3730  * 'widget' will be the widget returned from the
3731  * gnc_option_set_ui_widget_<type>() function.
3732  *
3733  * You should return a SCM value corresponding to the current state of the
3734  * gui widget.
3735  *
3736  */
3737 static SCM
gnc_option_get_ui_value_boolean(GNCOption * option,GtkWidget * widget)3738 gnc_option_get_ui_value_boolean (GNCOption *option, GtkWidget *widget)
3739 {
3740     gboolean active;
3741 
3742     active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
3743     return SCM_BOOL(active);
3744 }
3745 
3746 static SCM
gnc_option_get_ui_value_string(GNCOption * option,GtkWidget * widget)3747 gnc_option_get_ui_value_string (GNCOption *option, GtkWidget *widget)
3748 {
3749     char * string;
3750     SCM result;
3751 
3752     string = gtk_editable_get_chars (GTK_EDITABLE(widget), 0, -1);
3753     result = scm_from_utf8_string (string ? string : "");
3754     g_free (string);
3755     return result;
3756 }
3757 
3758 static SCM
gnc_option_get_ui_value_text(GNCOption * option,GtkWidget * widget)3759 gnc_option_get_ui_value_text (GNCOption *option, GtkWidget *widget)
3760 {
3761     char * string;
3762     SCM result;
3763 
3764     string = xxxgtk_textview_get_text (GTK_TEXT_VIEW(widget));
3765     result = scm_from_utf8_string (string ? string : "");
3766     g_free (string);
3767     return result;
3768 }
3769 
3770 static SCM
gnc_option_get_ui_value_currency(GNCOption * option,GtkWidget * widget)3771 gnc_option_get_ui_value_currency (GNCOption *option, GtkWidget *widget)
3772 {
3773     gnc_commodity *commodity;
3774 
3775     commodity =
3776         gnc_currency_edit_get_currency (GNC_CURRENCY_EDIT(widget));
3777 
3778     return (gnc_commodity_to_scm (commodity));
3779 }
3780 
3781 static SCM
gnc_option_get_ui_value_commodity(GNCOption * option,GtkWidget * widget)3782 gnc_option_get_ui_value_commodity (GNCOption *option, GtkWidget *widget)
3783 {
3784     gnc_commodity *commodity;
3785 
3786     commodity =
3787         gnc_general_select_get_selected (GNC_GENERAL_SELECT(widget));
3788 
3789     return (gnc_commodity_to_scm (commodity));
3790 }
3791 
3792 static SCM
gnc_option_get_ui_value_multichoice(GNCOption * option,GtkWidget * widget)3793 gnc_option_get_ui_value_multichoice (GNCOption *option, GtkWidget *widget)
3794 {
3795     int index = gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
3796     return (gnc_option_permissible_value (option, index));
3797 }
3798 
3799 static SCM
gnc_option_get_ui_value_date(GNCOption * option,GtkWidget * widget)3800 gnc_option_get_ui_value_date (GNCOption *option, GtkWidget *widget)
3801 {
3802     int index;
3803     SCM type, val, result = SCM_UNDEFINED;
3804     char *subtype = gnc_option_date_option_get_subtype (option);
3805 
3806     if (g_strcmp0 (subtype, "relative") == 0)
3807     {
3808         index = gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
3809 
3810         type = scm_from_locale_symbol ("relative");
3811         val = gnc_option_permissible_value (option, index);
3812         result = scm_cons (type, val);
3813     }
3814     else if (g_strcmp0 (subtype, "absolute") == 0)
3815     {
3816         time64 time;
3817         time = gnc_date_edit_get_date (GNC_DATE_EDIT(widget));
3818         result = scm_cons (scm_from_locale_symbol ("absolute"), scm_from_int64 (time));
3819     }
3820     else if (g_strcmp0 (subtype, "both") == 0)
3821     {
3822         time64 time;
3823         int index;
3824         SCM val;
3825         GList *widget_list;
3826         GtkWidget *ab_button, *rel_widget, *ab_widget;
3827 
3828         widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
3829         ab_button = g_list_nth_data (widget_list,  GNC_RD_WID_AB_BUTTON_POS);
3830         ab_widget = g_list_nth_data (widget_list,  GNC_RD_WID_AB_WIDGET_POS);
3831         rel_widget = g_list_nth_data (widget_list, GNC_RD_WID_REL_WIDGET_POS);
3832         g_list_free (widget_list);
3833 
3834         /* if it's an absolute date */
3835         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(ab_button)))
3836         {
3837             time = gnc_date_edit_get_date (GNC_DATE_EDIT(ab_widget));
3838             result = scm_cons (scm_from_locale_symbol ("absolute"), scm_from_int64 (time));
3839         }
3840         else
3841         {
3842             index = gtk_combo_box_get_active (GTK_COMBO_BOX(rel_widget));
3843 
3844             val = gnc_option_permissible_value (option, index);
3845             result = scm_cons (scm_from_locale_symbol ("relative"), val);
3846         }
3847     }
3848     g_free (subtype);
3849     return result;
3850 }
3851 
3852 static SCM
gnc_option_get_ui_value_account_list(GNCOption * option,GtkWidget * widget)3853 gnc_option_get_ui_value_account_list (GNCOption *option, GtkWidget *widget)
3854 {
3855     GncTreeViewAccount *tree;
3856     GList *list;
3857     SCM result;
3858 
3859     tree = GNC_TREE_VIEW_ACCOUNT(widget);
3860     list = gnc_tree_view_account_get_selected_accounts (tree);
3861 
3862     /* handover list */
3863     result = gnc_glist_to_scm_list (list, "_p_Account");
3864     g_list_free (list);
3865     return result;
3866 }
3867 
3868 static SCM
gnc_option_get_ui_value_account_sel(GNCOption * option,GtkWidget * widget)3869 gnc_option_get_ui_value_account_sel (GNCOption *option, GtkWidget *widget)
3870 {
3871     GNCAccountSel *gas;
3872     Account* acc;
3873 
3874     gas = GNC_ACCOUNT_SEL(widget);
3875     acc = gnc_account_sel_get_account (gas);
3876 
3877     if (!acc)
3878         return SCM_BOOL_F;
3879 
3880     return SWIG_NewPointerObj (acc, SWIG_TypeQuery ("_p_Account"), 0);
3881 }
3882 
3883 static SCM
gnc_option_get_ui_value_budget(GNCOption * option,GtkWidget * widget)3884 gnc_option_get_ui_value_budget (GNCOption *option, GtkWidget *widget)
3885 {
3886     GncBudget *bgt;
3887     GtkComboBox *cb;
3888     GtkTreeModel *tm;
3889     GtkTreeIter iter;
3890 
3891     cb = GTK_COMBO_BOX(widget);
3892     gtk_combo_box_get_active_iter (cb, &iter);
3893     tm = gtk_combo_box_get_model (cb);
3894     bgt = gnc_tree_model_budget_get_budget (tm, &iter);
3895 
3896     if (!bgt)
3897         return SCM_BOOL_F;
3898 
3899     return SWIG_NewPointerObj (bgt, SWIG_TypeQuery ("_p_budget_s"), 0);
3900 }
3901 
3902 static SCM
gnc_option_get_ui_value_list(GNCOption * option,GtkWidget * widget)3903 gnc_option_get_ui_value_list (GNCOption *option, GtkWidget *widget)
3904 {
3905     GtkTreeSelection *selection;
3906     GtkTreePath *path;
3907     SCM result;
3908     gboolean selected;
3909     gint num_rows;
3910     gint row;
3911 
3912     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(widget));
3913     num_rows = gnc_option_num_permissible_values (option);
3914     result = scm_c_eval_string ("'()");
3915 
3916     for (row = 0; row < num_rows; row++)
3917     {
3918         path = gtk_tree_path_new_from_indices (row, -1);
3919         selected = gtk_tree_selection_path_is_selected (selection, path);
3920         gtk_tree_path_free (path);
3921         if (selected)
3922             result = scm_cons (gnc_option_permissible_value (option, row), result);
3923     }
3924     return (scm_reverse (result));
3925 }
3926 
3927 static SCM
gnc_option_get_ui_value_number_range(GNCOption * option,GtkWidget * widget)3928 gnc_option_get_ui_value_number_range (GNCOption *option, GtkWidget *widget)
3929 {
3930     GtkSpinButton *spinner;
3931     gdouble value;
3932 
3933     spinner = GTK_SPIN_BUTTON(widget);
3934 
3935     value = gtk_spin_button_get_value (spinner);
3936 
3937     return (scm_from_double (value));
3938 }
3939 
3940 static SCM
gnc_option_get_ui_value_color(GNCOption * option,GtkWidget * widget)3941 gnc_option_get_ui_value_color (GNCOption *option, GtkWidget *widget)
3942 {
3943     SCM result;
3944     GtkColorChooser *color_button;
3945     GdkRGBA color;
3946     gdouble scale;
3947 
3948     ENTER("option %p(%s), widget %p",
3949           option, gnc_option_name (option), widget);
3950 
3951     color_button = GTK_COLOR_CHOOSER(widget);
3952     gtk_color_chooser_get_rgba (color_button, &color);
3953 
3954     scale = gnc_option_color_range (option);
3955 
3956     result = SCM_EOL;
3957     result = scm_cons (scm_from_double (color.alpha * scale), result);
3958     result = scm_cons (scm_from_double (color.blue * scale), result);
3959     result = scm_cons (scm_from_double (color.green * scale), result);
3960     result = scm_cons (scm_from_double (color.red * scale), result);
3961     return result;
3962 }
3963 
3964 static SCM
gnc_option_get_ui_value_font(GNCOption * option,GtkWidget * widget)3965 gnc_option_get_ui_value_font (GNCOption *option, GtkWidget *widget)
3966 {
3967     GtkFontButton *font_button = GTK_FONT_BUTTON(widget);
3968     const gchar * string;
3969 
3970     string = gtk_font_button_get_font_name (font_button);
3971     return (string ? scm_from_utf8_string (string) : SCM_BOOL_F);
3972 }
3973 
3974 static SCM
gnc_option_get_ui_value_pixmap(GNCOption * option,GtkWidget * widget)3975 gnc_option_get_ui_value_pixmap (GNCOption *option, GtkWidget *widget)
3976 {
3977     gchar *string;
3978     SCM result;
3979 
3980     string = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(widget));
3981     DEBUG("filename %s", string ? string : "(null)");
3982     result = scm_from_utf8_string (string ? string : "");
3983     g_free (string);
3984     return result;
3985 }
3986 
3987 static SCM
gnc_option_get_ui_value_radiobutton(GNCOption * option,GtkWidget * widget)3988 gnc_option_get_ui_value_radiobutton (GNCOption *option, GtkWidget *widget)
3989 {
3990     gpointer _index;
3991     int index;
3992 
3993     _index = g_object_get_data (G_OBJECT(widget), "gnc_radiobutton_index");
3994     index = GPOINTER_TO_INT(_index);
3995 
3996     return (gnc_option_permissible_value (option, index));
3997 }
3998 
3999 static SCM
gnc_option_get_ui_value_dateformat(GNCOption * option,GtkWidget * widget)4000 gnc_option_get_ui_value_dateformat (GNCOption *option, GtkWidget *widget)
4001 {
4002     GNCDateFormat *gdf = GNC_DATE_FORMAT(widget);
4003     QofDateFormat format;
4004     GNCDateMonthFormat months;
4005     gboolean years;
4006     const char* custom;
4007 
4008     format = gnc_date_format_get_format (gdf);
4009     months = gnc_date_format_get_months (gdf);
4010     years = gnc_date_format_get_years (gdf);
4011     custom = gnc_date_format_get_custom (gdf);
4012 
4013     return (gnc_dateformat_option_set_value (format, months, years, custom));
4014 }
4015 
4016 static SCM
gnc_option_get_ui_value_plot_size(GNCOption * option,GtkWidget * widget)4017 gnc_option_get_ui_value_plot_size (GNCOption *option, GtkWidget *widget)
4018 {
4019     GList* widget_list;
4020     GtkWidget *px_button, *px_widget, *p_widget;
4021     gdouble d_value;
4022     SCM type, val;
4023 
4024     widget_list = gtk_container_get_children (GTK_CONTAINER(widget));
4025     px_button = g_list_nth_data (widget_list, 0);
4026     px_widget = g_list_nth_data (widget_list, 1);
4027     // p_button item 2
4028     p_widget = g_list_nth_data (widget_list, 3);
4029     g_list_free (widget_list);
4030 
4031     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(px_button)))
4032     {
4033         type = scm_from_locale_symbol ("pixels");
4034         d_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(px_widget));
4035     }
4036     else
4037     {
4038         type = scm_from_locale_symbol ("percent");
4039         d_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(p_widget));
4040     }
4041     val = scm_from_double (d_value);
4042     return scm_cons (type, val);
4043 }
4044 
4045 static SCM
gnc_option_get_ui_value_currency_accounting(GNCOption * option,GtkWidget * widget)4046 gnc_option_get_ui_value_currency_accounting (GNCOption *option,
4047                                              GtkWidget *widget)
4048 {
4049     gpointer _index;
4050     int index;
4051     SCM value = SCM_EOL;
4052 
4053     _index = g_object_get_data (G_OBJECT(widget), "gnc_radiobutton_index");
4054     index = GPOINTER_TO_INT(_index);
4055 
4056     /* build the return list in reverse order */
4057     if (g_strcmp0 (gnc_option_permissible_value_name (option, index),
4058                    "Use a Book Currency") == 0)
4059     {
4060         gnc_commodity *commodity = NULL;
4061         int policy_index;
4062         SCM val;
4063         GList *list_of_policies = NULL;
4064         const char *str = NULL;
4065 
4066         if (book_currency_data->default_gain_loss_account_widget)
4067         {
4068             /* get account from widget, if one selected */
4069             Account *gain_loss_account = NULL;
4070 
4071             gain_loss_account =
4072                 gnc_tree_view_account_get_selected_account
4073                     (GNC_TREE_VIEW_ACCOUNT(
4074                         book_currency_data->default_gain_loss_account_widget));
4075 
4076             if (gain_loss_account == NULL)
4077             {
4078                 val = SCM_BOOL_F;
4079             }
4080             else
4081             {
4082                 gchar *gain_loss_account_guid = guid_to_string (
4083                                         xaccAccountGetGUID (gain_loss_account));
4084 
4085                 val = scm_from_utf8_string (gain_loss_account_guid);
4086                 g_free (gain_loss_account_guid);
4087             }
4088         }
4089         else
4090         {
4091             val = SCM_BOOL_F;
4092         }
4093         value = scm_cons (val, value);
4094 
4095         list_of_policies = gnc_get_valid_policy_list ();
4096         if (list_of_policies && book_currency_data->default_cost_policy_widget)
4097         {
4098             GList *l = NULL;
4099             gint i = 0;
4100 
4101             policy_index =
4102                 gtk_combo_box_get_active (GTK_COMBO_BOX(
4103                              book_currency_data->default_cost_policy_widget));
4104             for (l = list_of_policies; l != NULL; l = l->next)
4105             {
4106                 GNCPolicy *pcy = l->data;
4107                 if(i == policy_index)
4108                     str = PolicyGetName (pcy);
4109                 i++;
4110             }
4111             g_list_free (list_of_policies);
4112         }
4113         if (str)
4114         {
4115             val = scm_from_locale_symbol (str);
4116         }
4117         else
4118         {
4119             val = SCM_BOOL_F;
4120         }
4121         value = scm_cons (val, value);
4122 
4123         if (gtk_combo_box_get_active (GTK_COMBO_BOX(book_currency_data->book_currency_widget)) != -1)
4124         {
4125             commodity =
4126                 gnc_currency_edit_get_currency (
4127                     GNC_CURRENCY_EDIT(
4128                         book_currency_data->book_currency_widget));
4129             if (commodity)
4130             {
4131                 val = gnc_commodity_to_scm (commodity);
4132             }
4133             else
4134             {
4135                 val = SCM_BOOL_F;
4136             }
4137         }
4138         else
4139         {
4140             val = SCM_BOOL_F;
4141         }
4142         value = scm_cons (val, value);
4143     }
4144 
4145     return (scm_cons (gnc_option_permissible_value (option, index), value));
4146 }
4147 
4148 /************************************/
4149 /*          INITIALIZATION          */
4150 /************************************/
gnc_options_initialize_options(void)4151 static void gnc_options_initialize_options (void)
4152 {
4153     static GNCOptionDef_t options[] =
4154     {
4155         {
4156             "boolean", gnc_option_set_ui_widget_boolean,
4157             gnc_option_set_ui_value_boolean, gnc_option_get_ui_value_boolean
4158         },
4159         {
4160             "string", gnc_option_set_ui_widget_string,
4161             gnc_option_set_ui_value_string, gnc_option_get_ui_value_string
4162         },
4163         {
4164             "text", gnc_option_set_ui_widget_text,
4165             (GNCOptionUISetValue)gnc_option_set_ui_value_text,
4166             gnc_option_get_ui_value_text
4167         },
4168         {
4169             "currency", gnc_option_set_ui_widget_currency,
4170             gnc_option_set_ui_value_currency, gnc_option_get_ui_value_currency
4171         },
4172         {
4173             "commodity", gnc_option_set_ui_widget_commodity,
4174             gnc_option_set_ui_value_commodity, gnc_option_get_ui_value_commodity
4175         },
4176         {
4177             "multichoice", gnc_option_set_ui_widget_multichoice,
4178             gnc_option_set_ui_value_multichoice, gnc_option_get_ui_value_multichoice
4179         },
4180         {
4181             "date", gnc_option_set_ui_widget_date,
4182             gnc_option_set_ui_value_date, gnc_option_get_ui_value_date
4183         },
4184         {
4185             "account-list", gnc_option_set_ui_widget_account_list,
4186             gnc_option_set_ui_value_account_list, gnc_option_get_ui_value_account_list
4187         },
4188         {
4189             "account-sel", gnc_option_set_ui_widget_account_sel,
4190             gnc_option_set_ui_value_account_sel, gnc_option_get_ui_value_account_sel
4191         },
4192         {
4193             "list", gnc_option_set_ui_widget_list,
4194             gnc_option_set_ui_value_list, gnc_option_get_ui_value_list
4195         },
4196         {
4197             "number-range", gnc_option_set_ui_widget_number_range,
4198             gnc_option_set_ui_value_number_range, gnc_option_get_ui_value_number_range
4199         },
4200         {
4201             "color", gnc_option_set_ui_widget_color,
4202             gnc_option_set_ui_value_color, gnc_option_get_ui_value_color
4203         },
4204         {
4205             "font", gnc_option_set_ui_widget_font,
4206             gnc_option_set_ui_value_font, gnc_option_get_ui_value_font
4207         },
4208         {
4209             "pixmap", gnc_option_set_ui_widget_pixmap,
4210             gnc_option_set_ui_value_pixmap, gnc_option_get_ui_value_pixmap
4211         },
4212         {
4213             "radiobutton", gnc_option_set_ui_widget_radiobutton,
4214             gnc_option_set_ui_value_radiobutton, gnc_option_get_ui_value_radiobutton
4215         },
4216         {
4217             "dateformat", gnc_option_set_ui_widget_dateformat,
4218             gnc_option_set_ui_value_dateformat, gnc_option_get_ui_value_dateformat
4219         },
4220         {
4221             "plot-size", gnc_option_set_ui_widget_plot_size,
4222             gnc_option_set_ui_value_plot_size, gnc_option_get_ui_value_plot_size
4223         },
4224         {
4225             "budget", gnc_option_set_ui_widget_budget,
4226             gnc_option_set_ui_value_budget, gnc_option_get_ui_value_budget
4227         },
4228         {
4229             "currency-accounting",
4230             gnc_option_set_ui_widget_currency_accounting,
4231             gnc_option_set_ui_value_currency_accounting,
4232             gnc_option_get_ui_value_currency_accounting
4233         },
4234         { NULL, NULL, NULL, NULL }
4235     };
4236     int i;
4237 
4238     for (i = 0; options[i].option_name; i++)
4239         gnc_options_ui_register_option (&(options[i]));
4240 }
4241 
4242 /* Register a new option type in the UI */
gnc_options_ui_register_option(GNCOptionDef_t * option)4243 void gnc_options_ui_register_option (GNCOptionDef_t *option)
4244 {
4245     g_return_if_fail (optionTable);
4246     g_return_if_fail (option);
4247 
4248     /* FIXME: should protect against repeat insertion. */
4249     g_hash_table_insert (optionTable, (gpointer)(option->option_name), option);
4250 }
4251 
gnc_options_ui_get_option(const char * option_name)4252 GNCOptionDef_t * gnc_options_ui_get_option (const char *option_name)
4253 {
4254     GNCOptionDef_t *retval;
4255     g_return_val_if_fail (optionTable, NULL);
4256     g_return_val_if_fail (option_name, NULL);
4257 
4258     retval = g_hash_table_lookup (optionTable, option_name);
4259     if (!retval)
4260     {
4261         PERR("Option lookup for type '%s' failed!", option_name);
4262     }
4263     return retval;
4264 }
4265 
gnc_options_ui_initialize(void)4266 void gnc_options_ui_initialize (void)
4267 {
4268     SWIG_GetModule (NULL); /* Work-around for SWIG bug. */
4269     //  gnc_options_register_stocks ();
4270     g_return_if_fail (optionTable == NULL);
4271     optionTable = g_hash_table_new (g_str_hash, g_str_equal);
4272 
4273     /* add known types */
4274     gnc_options_initialize_options ();
4275 }
4276 
4277 struct scm_cb
4278 {
4279     SCM apply_cb;
4280     SCM close_cb;
4281 };
4282 
4283 static void
scm_apply_cb(GNCOptionWin * win,gpointer data)4284 scm_apply_cb (GNCOptionWin *win, gpointer data)
4285 {
4286     struct scm_cb *cbdata = data;
4287 
4288     if (gnc_option_db_get_changed (win->option_db))
4289     {
4290         GList *results = NULL, *iter;
4291         results = gnc_option_db_commit (win->option_db);
4292         for (iter = results; iter; iter = iter->next)
4293         {
4294             GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(gnc_options_dialog_widget (win)),
4295                                                         0,
4296                                                         GTK_MESSAGE_ERROR,
4297                                                         GTK_BUTTONS_OK,
4298                                                         "%s",
4299                                                         (char*)iter->data);
4300             gtk_dialog_run (GTK_DIALOG(dialog));
4301             gtk_widget_destroy (dialog);
4302             g_free (iter->data);
4303         }
4304         g_list_free (results);
4305 
4306         if (cbdata->apply_cb != SCM_BOOL_F)
4307         {
4308             scm_call_0 (cbdata->apply_cb);
4309         }
4310     }
4311 }
4312 
4313 static void
scm_close_cb(GNCOptionWin * win,gpointer data)4314 scm_close_cb (GNCOptionWin *win, gpointer data)
4315 {
4316     struct scm_cb *cbdata = data;
4317 
4318     if (cbdata->close_cb != SCM_BOOL_F)
4319     {
4320         scm_call_0 (cbdata->close_cb);
4321         scm_gc_unprotect_object (cbdata->close_cb);
4322     }
4323 
4324     if (cbdata->apply_cb != SCM_BOOL_F)
4325         scm_gc_unprotect_object (cbdata->apply_cb);
4326 
4327     g_free (cbdata);
4328 }
4329 
4330 /* Both apply_cb and close_cb should be scheme functions with 0 arguments.
4331  * References to these functions will be held until the close_cb is called
4332  */
4333 void
gnc_options_dialog_set_scm_callbacks(GNCOptionWin * win,SCM apply_cb,SCM close_cb)4334 gnc_options_dialog_set_scm_callbacks (GNCOptionWin *win, SCM apply_cb,
4335                                       SCM close_cb)
4336 {
4337     struct scm_cb *cbdata;
4338 
4339     cbdata = g_new0 (struct scm_cb, 1);
4340     cbdata->apply_cb = apply_cb;
4341     cbdata->close_cb = close_cb;
4342 
4343     if (apply_cb != SCM_BOOL_F)
4344         scm_gc_protect_object (cbdata->apply_cb);
4345 
4346     if (close_cb != SCM_BOOL_F)
4347         scm_gc_protect_object (cbdata->close_cb);
4348 
4349     gnc_options_dialog_set_apply_cb (win, scm_apply_cb, cbdata);
4350     gnc_options_dialog_set_close_cb (win, scm_close_cb, cbdata);
4351 }
4352