1 /********************************************************************\
2  * option-util.c -- GNOME<->guile option interface                  *
3  * Copyright (C) 2000 Dave Peticolas                                *
4  * Copyright (C) 2017 Aaron Laws                                    *
5  *                                                                  *
6  * This program is free software; you can redistribute it and/or    *
7  * modify it under the terms of the GNU General Public License as   *
8  * published by the Free Software Foundation; either version 2 of   *
9  * the License, or (at your option) any later version.              *
10  *                                                                  *
11  * This program is distributed in the hope that it will be useful,  *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
14  * GNU General Public License for more details.                     *
15  *                                                                  *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact:                        *
18  *                                                                  *
19  * Free Software Foundation           Voice:  +1-617-542-5942       *
20  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
21  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
22 \********************************************************************/
23 
24 #include <config.h>
25 
26 #include <glib/gi18n.h>
27 #include <time.h>
28 #include <string.h>
29 
30 #include "Account.h"
31 #include "option-util.h"
32 #include "gnc-guile-utils.h"
33 #include "qof.h"
34 #include "swig-runtime.h"
35 #include "guile-mappings.h"
36 
37 
38 /* TODO:
39 
40   - for make-date-option, there seems to be only support for getting,
41     not for setting.
42 */
43 
44 
45 /****** Structures *************************************************/
46 
47 struct gnc_option
48 {
49     /* Handle to the scheme-side option */
50     SCM guile_option;
51 
52     /* Flag to indicate change by the UI */
53     gboolean changed;
54 
55     /* The widget which is holding this option */
56     gpointer widget;
57 
58     /* The option db which holds this option */
59     GNCOptionDB *odb;
60 };
61 
62 struct gnc_option_section
63 {
64     char * section_name;
65 
66     GSList * options;
67 };
68 
69 struct gnc_option_db
70 {
71     SCM guile_options;
72 
73     GSList *option_sections;
74 
75     gboolean options_dirty;
76 
77     GNCOptionDBHandle handle;
78 
79     GNCOptionGetUIValue get_ui_value;
80     GNCOptionSetUIValue set_ui_value;
81     GNCOptionSetSelectable set_selectable;
82 };
83 
84 typedef struct _Getters Getters;
85 struct _Getters
86 {
87     SCM section;
88     SCM name;
89     SCM type;
90     SCM sort_tag;
91     SCM documentation;
92     SCM getter;
93     SCM setter;
94     SCM default_getter;
95     SCM value_validator;
96     SCM option_data;
97     SCM index_to_name;
98     SCM index_to_value;
99     SCM value_to_index;
100     SCM number_of_indices;
101     SCM option_widget_changed_cb;
102     SCM date_option_subtype;
103     SCM date_option_show_time;
104     SCM date_option_value_type;
105     SCM date_option_value_absolute;
106     SCM date_option_value_relative;
107     SCM plot_size_option_value_type;
108     SCM plot_size_option_value;
109     SCM currency_accounting_option_currency_doc_string;
110     SCM currency_accounting_option_default_currency;
111     SCM currency_accounting_option_policy_doc_string;
112     SCM currency_accounting_option_default_policy;
113     SCM currency_accounting_option_gain_loss_account_doc_string;
114     SCM currency_accounting_option_method;
115     SCM currency_accounting_option_book_currency;
116     SCM currency_accounting_option_selected_default_policy;
117     SCM currency_accounting_option_selected_default_gain_loss_account;
118 };
119 
120 
121 /****** Globals ****************************************************/
122 
123 static Getters getters = {0, 0, 0, 0, 0, 0, 0, 0, 0,
124                           0, 0, 0, 0, 0, 0, 0, 0, 0
125                          };
126 
127 /* This static indicates the debugging module this .o belongs to.  */
128 static QofLogModule log_module = GNC_MOD_GUI;
129 
130 static GHashTable *option_dbs = NULL;
131 static int last_db_handle = 0;
132 
133 
134 /*******************************************************************/
135 void
gnc_option_set_changed(GNCOption * option,gboolean changed)136 gnc_option_set_changed (GNCOption *option, gboolean changed)
137 {
138     g_return_if_fail (option != NULL);
139     option->changed = changed;
140 }
141 
142 gpointer
gnc_option_get_widget(GNCOption * option)143 gnc_option_get_widget (GNCOption *option)
144 {
145     if (!option) return NULL;
146     return option->widget;
147 }
148 
149 void
gnc_option_set_widget(GNCOption * option,gpointer widget)150 gnc_option_set_widget (GNCOption *option, gpointer widget)
151 {
152     g_return_if_fail (option != NULL);
153     option->widget = widget;
154 }
155 
156 SCM
gnc_option_get_ui_value(GNCOption * option)157 gnc_option_get_ui_value (GNCOption *option)
158 {
159     g_return_val_if_fail (option != NULL, SCM_UNDEFINED);
160     g_return_val_if_fail (option->odb != NULL, SCM_UNDEFINED);
161     g_return_val_if_fail (option->odb->get_ui_value != NULL, SCM_UNDEFINED);
162 
163     return option->odb->get_ui_value (option);
164 }
165 
166 void
gnc_option_set_ui_value(GNCOption * option,gboolean use_default)167 gnc_option_set_ui_value (GNCOption *option, gboolean use_default)
168 {
169     g_return_if_fail (option != NULL);
170     g_return_if_fail (option->odb != NULL);
171 
172     if (!option->odb->set_ui_value)
173         return;
174 
175     option->odb->set_ui_value (option, use_default);
176 }
177 
178 void
gnc_option_set_selectable(GNCOption * option,gboolean selectable)179 gnc_option_set_selectable (GNCOption *option, gboolean selectable)
180 {
181     g_return_if_fail (option != NULL);
182     g_return_if_fail (option->odb != NULL);
183     g_return_if_fail (option->odb->set_selectable != NULL);
184 
185     option->odb->set_selectable (option, selectable);
186 }
187 
188 /********************************************************************\
189  * gnc_option_db_init                                               *
190  *   initialize the options structures from the guile side          *
191  *                                                                  *
192  * Args: odb     - the option database to initialize                *
193  * Returns: nothing                                                 *
194 \********************************************************************/
195 static void
gnc_option_db_init(GNCOptionDB * odb)196 gnc_option_db_init (GNCOptionDB *odb)
197 {
198     SCM func = scm_c_eval_string ("gnc:send-options");
199 
200     scm_call_2 (func, scm_from_int (odb->handle), odb->guile_options);
201 }
202 
203 /********************************************************************\
204  * gnc_option_db_new                                                *
205  *   allocate a new option database and initialize its values       *
206  *                                                                  *
207  * Args: guile_options - SCM handle to options                      *
208  * Returns: a new option database                                   *
209 \********************************************************************/
210 GNCOptionDB *
gnc_option_db_new(SCM guile_options)211 gnc_option_db_new (SCM guile_options)
212 {
213     GNCOptionDB *odb;
214     GNCOptionDB *lookup;
215 
216     odb = g_new0 (GNCOptionDB, 1);
217 
218     odb->guile_options = guile_options;
219     scm_gc_protect_object (guile_options);
220 
221     odb->option_sections = NULL;
222     odb->options_dirty = FALSE;
223 
224     if (option_dbs == NULL)
225         option_dbs = g_hash_table_new (g_int_hash, g_int_equal);
226 
227     do
228     {
229         odb->handle = last_db_handle++;
230         lookup = g_hash_table_lookup (option_dbs, &odb->handle);
231     }
232     while (lookup != NULL);
233 
234     g_hash_table_insert (option_dbs, &odb->handle, odb);
235 
236     gnc_option_db_init (odb);
237 
238     return odb;
239 }
240 
241 /* Create an option DB for a particular data type */
242 /* For now, this is global, just like when it was in guile.
243    But, it should be make per-book. */
244 static GHashTable *kvp_registry = NULL;
245 
246 static void
init_table(void)247 init_table(void)
248 {
249     if (!kvp_registry)
250         kvp_registry = g_hash_table_new (g_str_hash, g_str_equal);
251 }
252 
253 
254 /*  create a new options object for the requested type */
255 static SCM
gnc_make_kvp_options(QofIdType id_type)256 gnc_make_kvp_options (QofIdType id_type)
257 {
258     GList *list, *p;
259     SCM gnc_new_options = SCM_UNDEFINED;
260     SCM options = SCM_UNDEFINED;
261 
262     init_table();
263     list = g_hash_table_lookup (kvp_registry, id_type);
264     gnc_new_options = scm_c_eval_string ("gnc:new-options");
265     options = scm_call_0 (gnc_new_options);
266 
267     for (p = list; p; p = p->next)
268     {
269         SCM generator = p->data;
270         scm_call_1 (generator, options);
271     }
272     return options;
273 }
274 
275 GNCOptionDB *
gnc_option_db_new_for_type(QofIdType id_type)276 gnc_option_db_new_for_type (QofIdType id_type)
277 {
278     SCM options;
279 
280     if (!id_type) return NULL;
281     options = gnc_make_kvp_options (id_type);
282     return gnc_option_db_new (options);
283 }
284 
285 void
gnc_option_db_load(GNCOptionDB * odb,QofBook * book)286 gnc_option_db_load (GNCOptionDB* odb, QofBook *book)
287 {
288     static SCM kvp_to_scm = SCM_UNDEFINED;
289     SCM scm_book;
290 
291     if (!odb || !book) return;
292 
293     if (kvp_to_scm == SCM_UNDEFINED)
294     {
295         kvp_to_scm = scm_c_eval_string ("gnc:options-kvp->scm");
296         if (!scm_is_procedure (kvp_to_scm))
297         {
298             PERR ("not a procedure\n");
299             kvp_to_scm = SCM_UNDEFINED;
300             return;
301         }
302     }
303 
304     scm_book = SWIG_NewPointerObj (book, SWIG_TypeQuery ("_p_QofBook"), 0);
305 
306     scm_call_2 (kvp_to_scm, odb->guile_options, scm_book);
307 }
308 
309 void
gnc_option_db_save(GNCOptionDB * odb,QofBook * book,gboolean clear_all)310 gnc_option_db_save (GNCOptionDB* odb, QofBook *book, gboolean clear_all)
311 {
312     static SCM scm_to_kvp = SCM_UNDEFINED;
313     SCM scm_book;
314     SCM scm_clear_all;
315 
316     if (!odb || !book) return;
317 
318     if (scm_to_kvp == SCM_UNDEFINED)
319     {
320         scm_to_kvp = scm_c_eval_string ("gnc:options-scm->kvp");
321         if (!scm_is_procedure (scm_to_kvp))
322         {
323             PERR ("not a procedure\n");
324             scm_to_kvp = SCM_UNDEFINED;
325             return;
326         }
327     }
328 
329     scm_book = SWIG_NewPointerObj (book, SWIG_TypeQuery ("_p_QofBook"), 0);
330     scm_clear_all = scm_from_bool (clear_all);
331 
332     scm_call_3 (scm_to_kvp, odb->guile_options, scm_book, scm_clear_all);
333 }
334 
335 /********************************************************************\
336  * gnc_option_db_destroy                                            *
337  *   unregister the scheme options and free all the memory          *
338  *   associated with an option database, including the database     *
339  *   itself                                                         *
340  *                                                                  *
341  * Args: options database to destroy                                *
342  * Returns: nothing                                                 *
343 \********************************************************************/
344 void
gnc_option_db_destroy(GNCOptionDB * odb)345 gnc_option_db_destroy (GNCOptionDB *odb)
346 {
347     GSList *snode;
348 
349     if (odb == NULL)
350         return;
351 
352     for (snode = odb->option_sections; snode; snode = snode->next)
353     {
354         GNCOptionSection *section = snode->data;
355         GSList *onode;
356 
357         for (onode = section->options; onode; onode = onode->next)
358         {
359             GNCOption *option = onode->data;
360 
361             scm_gc_unprotect_object (option->guile_option);
362             g_free (option);
363         }
364 
365         /* Free the option list */
366         g_slist_free (section->options);
367         section->options = NULL;
368 
369         if (section->section_name != NULL)
370             free (section->section_name);
371         section->section_name = NULL;
372 
373         g_free (section);
374     }
375 
376     g_slist_free (odb->option_sections);
377 
378     odb->option_sections = NULL;
379     odb->options_dirty = FALSE;
380 
381     g_hash_table_remove (option_dbs, &odb->handle);
382 
383     if (g_hash_table_size (option_dbs) == 0)
384     {
385         g_hash_table_destroy (option_dbs);
386         option_dbs = NULL;
387     }
388 
389     scm_gc_unprotect_object (odb->guile_options);
390     odb->guile_options = SCM_UNDEFINED;
391 
392     g_free(odb);
393 }
394 
395 void
gnc_option_db_set_ui_callbacks(GNCOptionDB * odb,GNCOptionGetUIValue get_ui_value,GNCOptionSetUIValue set_ui_value,GNCOptionSetSelectable set_selectable)396 gnc_option_db_set_ui_callbacks (GNCOptionDB *odb,
397                                 GNCOptionGetUIValue get_ui_value,
398                                 GNCOptionSetUIValue set_ui_value,
399                                 GNCOptionSetSelectable set_selectable)
400 {
401     g_return_if_fail (odb != NULL);
402 
403     odb->get_ui_value = get_ui_value;
404     odb->set_ui_value = set_ui_value;
405     odb->set_selectable = set_selectable;
406 }
407 
408 /********************************************************************\
409  * gnc_option_db_register_change_callback                           *
410  *   register a callback to be called whenever an option changes    *
411  *                                                                  *
412  * Args: odb       - the option database to register with           *
413  *       callback  - the callback function to register              *
414  *       user_data - the user data for the callback                 *
415  *       section   - the section to get callbacks for.              *
416  *                   If NULL, get callbacks for any section changes.*
417  *       name      - the option name to get callbacks for.          *
418  *                   If NULL, get callbacks for any option in the   *
419  *                   section. Only used if section is non-NULL.     *
420  * Returns: SCM handle for unregistering                            *
421 \********************************************************************/
422 SCM
gnc_option_db_register_change_callback(GNCOptionDB * odb,GNCOptionChangeCallback callback,gpointer data,const char * section,const char * name)423 gnc_option_db_register_change_callback (GNCOptionDB *odb,
424                                         GNCOptionChangeCallback callback,
425                                         gpointer data,
426                                         const char *section,
427                                         const char *name)
428 {
429     SCM register_proc;
430     SCM arg;
431     SCM args;
432 
433     if (!odb || !callback)
434         return SCM_UNDEFINED;
435 
436     /* Get the register procedure */
437     register_proc = scm_c_eval_string ("gnc:options-register-c-callback");
438     if (!scm_is_procedure (register_proc))
439     {
440         PERR("not a procedure\n");
441         return SCM_UNDEFINED;
442     }
443 
444     /* Now build the args list for apply */
445     args = SCM_EOL;
446 
447     /* first the guile options database */
448     args = scm_cons (odb->guile_options, args);
449 
450     /* next the data */
451     arg = SWIG_NewPointerObj (data, SWIG_TypeQuery ("_p_void"), 0);
452     args = scm_cons (arg, args);
453 
454     /* next the callback */
455     arg = SWIG_NewPointerObj (
456               callback, SWIG_TypeQuery ("GNCOptionChangeCallback"), 0);
457     args = scm_cons (arg, args);
458 
459     /* next the name */
460     if (name == NULL)
461     {
462         arg = SCM_BOOL_F;
463     }
464     else
465     {
466         arg = scm_from_utf8_string (name);
467     }
468     args = scm_cons (arg, args);
469 
470     /* next the section */
471     if (section == NULL)
472     {
473         arg = SCM_BOOL_F;
474     }
475     else
476     {
477         arg = scm_from_utf8_string (section);
478     }
479     args = scm_cons (arg, args);
480 
481     /* now apply the procedure */
482     return scm_apply (register_proc, args, SCM_EOL);
483 }
484 
485 /********************************************************************\
486  * gnc_option_db_unregister_change_callback_id                      *
487  *   unregister the change callback associated with the given id    *
488  *                                                                  *
489  * Args: odb      - the option database to register with            *
490  *       callback - the callback function to register               *
491  * Returns: nothing                                                 *
492 \********************************************************************/
493 void
gnc_option_db_unregister_change_callback_id(GNCOptionDB * odb,SCM callback_id)494 gnc_option_db_unregister_change_callback_id (GNCOptionDB *odb, SCM callback_id)
495 {
496     SCM proc;
497 
498     if (callback_id == SCM_UNDEFINED)
499         return;
500 
501     proc = scm_c_eval_string ("gnc:options-unregister-callback-id");
502     if (!scm_is_procedure (proc))
503     {
504         PERR("not a procedure\n");
505         return;
506     }
507 
508     scm_call_2 (proc, callback_id, odb->guile_options);
509 }
510 
511 void
gncp_option_invoke_callback(GNCOptionChangeCallback callback,void * data)512 gncp_option_invoke_callback (GNCOptionChangeCallback callback, void *data)
513 {
514     callback (data);
515 }
516 
517 static void
gnc_call_option_change_callbacks(GNCOptionDB * odb)518 gnc_call_option_change_callbacks (GNCOptionDB *odb)
519 {
520     SCM proc;
521 
522     proc = scm_c_eval_string ("gnc:options-run-callbacks");
523     if (!scm_is_procedure (proc))
524     {
525         PERR("not a procedure\n");
526         return;
527     }
528 
529     scm_call_1 (proc, odb->guile_options);
530 }
531 
532 static void
initialize_getters(void)533 initialize_getters(void)
534 {
535     static gboolean getters_initialized = FALSE;
536 
537     if (getters_initialized)
538         return;
539 
540     getters.section = scm_c_eval_string ("gnc:option-section");
541     getters.name = scm_c_eval_string ("gnc:option-name");
542     getters.type = scm_c_eval_string ("gnc:option-type");
543     getters.sort_tag = scm_c_eval_string ("gnc:option-sort-tag");
544     getters.documentation =
545         scm_c_eval_string ("gnc:option-documentation");
546     getters.getter = scm_c_eval_string ("gnc:option-getter");
547     getters.setter = scm_c_eval_string ("gnc:option-setter");
548     getters.default_getter =
549         scm_c_eval_string ("gnc:option-default-getter");
550     getters.value_validator =
551         scm_c_eval_string ("gnc:option-value-validator");
552     getters.option_data = scm_c_eval_string ("gnc:option-data");
553     getters.index_to_name = scm_c_eval_string ("gnc:option-index-get-name");
554     getters.number_of_indices = scm_c_eval_string ("gnc:option-number-of-indices");
555     getters.index_to_value = scm_c_eval_string ("gnc:option-index-get-value");
556     getters.value_to_index = scm_c_eval_string ("gnc:option-value-get-index");
557     getters.option_widget_changed_cb =
558         scm_c_eval_string ("gnc:option-widget-changed-proc");
559     getters.date_option_subtype = scm_c_eval_string ("gnc:date-option-get-subtype");
560     getters.date_option_show_time = scm_c_eval_string ("gnc:date-option-show-time?");
561     getters.date_option_value_type = scm_c_eval_string ("gnc:date-option-value-type");
562     getters.date_option_value_absolute =
563         scm_c_eval_string ("gnc:date-option-absolute-time");
564     getters.date_option_value_relative =
565         scm_c_eval_string ("gnc:date-option-relative-time");
566     getters.plot_size_option_value_type = scm_c_eval_string ("gnc:plot-size-option-value-type");
567     getters.plot_size_option_value = scm_c_eval_string ("gnc:plot-size-option-value");
568     getters.currency_accounting_option_currency_doc_string =
569         scm_c_eval_string ("gnc:currency-accounting-option-get-curr-doc-string");
570     getters.currency_accounting_option_default_currency =
571         scm_c_eval_string ("gnc:currency-accounting-option-get-default-curr");
572     getters.currency_accounting_option_policy_doc_string =
573         scm_c_eval_string ("gnc:currency-accounting-option-get-policy-doc-string");
574     getters.currency_accounting_option_default_policy =
575         scm_c_eval_string ("gnc:currency-accounting-option-get-default-policy");
576     getters.currency_accounting_option_gain_loss_account_doc_string =
577         scm_c_eval_string ("gnc:currency-accounting-option-get-gain-loss-account-doc-string");
578     getters.currency_accounting_option_method =
579         scm_c_eval_string ("gnc:currency-accounting-option-selected-method");
580     getters.currency_accounting_option_book_currency =
581         scm_c_eval_string ("gnc:currency-accounting-option-selected-currency");
582     getters.currency_accounting_option_selected_default_policy =
583         scm_c_eval_string ("gnc:currency-accounting-option-selected-policy");
584     getters.currency_accounting_option_selected_default_gain_loss_account =
585         scm_c_eval_string ("gnc:currency-accounting-option-selected-gain-loss-account");
586 
587     getters_initialized = TRUE;
588 }
589 
590 /********************************************************************\
591  * gnc_option_section                                               *
592  *   returns the malloc'ed section name of the option, or NULL      *
593  *   if it can't be retrieved.                                      *
594  *                                                                  *
595  * Args: option - the GNCOption                                     *
596  * Returns: malloc'ed char * or NULL                                *
597 \********************************************************************/
598 char *
gnc_option_section(GNCOption * option)599 gnc_option_section (GNCOption *option)
600 {
601     initialize_getters ();
602 
603     return gnc_scm_call_1_to_string (getters.section, option->guile_option);
604 }
605 
606 /********************************************************************\
607  * gnc_option_name                                                  *
608  *   returns the malloc'ed name of the option, or NULL              *
609  *   if it can't be retrieved.                                      *
610  *                                                                  *
611  * Args: option - the GNCOption                                     *
612  * Returns: malloc'ed char * or NULL                                *
613 \********************************************************************/
614 char *
gnc_option_name(GNCOption * option)615 gnc_option_name (GNCOption *option)
616 {
617     initialize_getters ();
618 
619     return gnc_scm_call_1_to_string (getters.name, option->guile_option);
620 }
621 
622 /********************************************************************\
623  * gnc_option_type                                                  *
624  *   returns the malloc'ed type of the option, or NULL              *
625  *   if it can't be retrieved.                                      *
626  *                                                                  *
627  * Args: option - the GNCOption                                     *
628  * Returns: malloc'ed char * or NULL                                *
629 \********************************************************************/
630 char *
gnc_option_type(GNCOption * option)631 gnc_option_type (GNCOption *option)
632 {
633     initialize_getters ();
634 
635     return gnc_scm_call_1_symbol_to_string (getters.type,
636                                             option->guile_option);
637 }
638 
639 /********************************************************************\
640  * gnc_option_sort_tag                                              *
641  *   returns the malloc'ed sort tag of the option, or NULL          *
642  *   if it can't be retrieved.                                      *
643  *                                                                  *
644  * Args: option - the GNCOption                                     *
645  * Returns: malloc'ed char * or NULL                                *
646 \********************************************************************/
647 char *
gnc_option_sort_tag(GNCOption * option)648 gnc_option_sort_tag (GNCOption *option)
649 {
650     initialize_getters ();
651 
652     return gnc_scm_call_1_to_string (getters.sort_tag, option->guile_option);
653 }
654 
655 /********************************************************************\
656  * gnc_option_documentation                                         *
657  *   returns the malloc'ed documentation string of the option, or   *
658  *   NULL if it can't be retrieved.                                 *
659  *                                                                  *
660  * Args: option - the GNCOption                                     *
661  * Returns: malloc'ed char * or NULL                                *
662 \********************************************************************/
663 char *
gnc_option_documentation(GNCOption * option)664 gnc_option_documentation (GNCOption *option)
665 {
666     initialize_getters ();
667 
668     return gnc_scm_call_1_to_string (getters.documentation,
669                                      option->guile_option);
670 }
671 
672 /********************************************************************\
673  * gnc_option_getter                                                *
674  *   returns the SCM handle for the option getter function.         *
675  *   This value should be tested with scm_procedure_p before use.   *
676  *                                                                  *
677  * Args: option - the GNCOption                                     *
678  * Returns: SCM handle to function                                  *
679 \********************************************************************/
680 SCM
gnc_option_getter(GNCOption * option)681 gnc_option_getter (GNCOption *option)
682 {
683     initialize_getters ();
684 
685     return gnc_scm_call_1_to_procedure (getters.getter,
686                                         option->guile_option);
687 }
688 
689 /********************************************************************\
690  * gnc_option_setter                                                *
691  *   returns the SCM handle for the option setter function.         *
692  *   This value should be tested with scm_procedure_p before use.   *
693  *                                                                  *
694  * Args: option - the GNCOption                                     *
695  * Returns: SCM handle to function                                  *
696 \********************************************************************/
697 SCM
gnc_option_setter(GNCOption * option)698 gnc_option_setter (GNCOption *option)
699 {
700     initialize_getters ();
701 
702     return gnc_scm_call_1_to_procedure (getters.setter,
703                                         option->guile_option);
704 }
705 
706 /********************************************************************\
707  * gnc_option_default_getter                                        *
708  *   returns the SCM handle for the option default_getter function. *
709  *   This value should be tested with scm_procedure_p before use.   *
710  *                                                                  *
711  * Args: option - the GNCOption                                     *
712  * Returns: SCM handle to function                                  *
713 \********************************************************************/
714 SCM
gnc_option_default_getter(GNCOption * option)715 gnc_option_default_getter (GNCOption *option)
716 {
717     initialize_getters ();
718 
719     return gnc_scm_call_1_to_procedure (getters.default_getter,
720                                         option->guile_option);
721 }
722 
723 /********************************************************************\
724  * gnc_option_value_validator                                       *
725  *   returns the SCM handle for the option value validator function.*
726  *   This value should be tested with scm_procedure_p before use.   *
727  *                                                                  *
728  * Args: option - the GNCOption                                     *
729  * Returns: SCM handle to function                                  *
730 \********************************************************************/
731 SCM
gnc_option_value_validator(GNCOption * option)732 gnc_option_value_validator (GNCOption *option)
733 {
734     initialize_getters ();
735 
736     return gnc_scm_call_1_to_procedure (getters.value_validator,
737                                         option->guile_option);
738 }
739 
740 /********************************************************************\
741  * gnc_option_widget_changed_proc_getter                            *
742  *   returns the SCM handle for the function to be called if the    *
743  *   GUI widget representing the option is changed.                 *
744  *   This value should be tested with scm_procedure_p before use.   *
745  *   If no such function exists, returns SCM_UNDEFINED.             *
746  *                                                                  *
747  * Args: option - the GNCOption                                     *
748  * Returns: SCM handle to function                                  *
749  *          If no such function exists, returns SCM_UNDEFINED.      *
750 \********************************************************************/
751 SCM
gnc_option_widget_changed_proc_getter(GNCOption * option)752 gnc_option_widget_changed_proc_getter (GNCOption *option)
753 {
754     SCM cb;
755 
756     initialize_getters ();
757 
758     if (scm_is_procedure (getters.option_widget_changed_cb))
759     {
760         /* call the callback function getter to get the actual callback function */
761         cb = scm_call_1 (getters.option_widget_changed_cb, option->guile_option);
762 
763         if (scm_is_procedure (cb))  /* a callback exists */
764         {
765             return (cb);
766         }
767         /* else no callback exists -  this is a legal situation */
768     }
769     else  /* getters not set up correctly? */
770     {
771         PERR("getters.option_widget_changed_cb is not a valid procedure\n");
772     }
773 
774     return( SCM_UNDEFINED );
775 }
776 
777 /**********************************************************************\
778  * gnc_option_call_option_widget_changed_proc                         *
779  *   If there is an option_widget_changed_cb for this option, call    *
780  *   it with the SCM value of the option that is passed in.  If       *
781  *   there is no such callback function or value, do nothing.         *
782  *                                                                    *
783  * Args: option        - the GNCOption                                *
784  *       reset_changed - whether to reset the changed flag afterwards *
785  * Returns: void                                                      *
786 \**********************************************************************/
787 void
gnc_option_call_option_widget_changed_proc(GNCOption * option,gboolean reset_changed)788 gnc_option_call_option_widget_changed_proc (GNCOption *option,
789                                             gboolean reset_changed)
790 {
791     SCM cb, value;
792 
793     cb = gnc_option_widget_changed_proc_getter (option);
794 
795     if (cb != SCM_UNDEFINED)
796     {
797         value = gnc_option_get_ui_value (option);
798 
799         if (value != SCM_UNDEFINED)
800         {
801             scm_call_1 (cb, value);
802         }
803     }
804     if (reset_changed)
805         option->changed = FALSE;
806 }
807 
808 /********************************************************************\
809  * gnc_option_num_permissible_values                                *
810  *   returns the number of permissible values in the option, or     *
811  *   -1 if there are no values available.                           *
812  *                                                                  *
813  * Args: option - the GNCOption                                     *
814  * Returns: number of permissible options or -1                     *
815 \********************************************************************/
816 int
gnc_option_num_permissible_values(GNCOption * option)817 gnc_option_num_permissible_values (GNCOption *option)
818 {
819     SCM value;
820 
821     initialize_getters ();
822 
823     value = scm_call_1 (getters.number_of_indices, option->guile_option);
824 
825     if (scm_is_exact (value))
826     {
827         return scm_to_int (value);
828     }
829     else
830     {
831         return -1;
832     }
833 }
834 
835 /********************************************************************\
836  * gnc_option_permissible_value_index                               *
837  *   returns the index of the permissible value matching the        *
838  *   provided value, or -1 if it couldn't be found                  *
839  *                                                                  *
840  * Args: option - the GNCOption                                     *
841  *       value  - the SCM handle of the value                       *
842  * Returns: index of permissible value, or -1                       *
843 \********************************************************************/
844 int
gnc_option_permissible_value_index(GNCOption * option,SCM search_value)845 gnc_option_permissible_value_index (GNCOption *option, SCM search_value)
846 {
847     SCM value;
848     value = scm_call_2 (getters.value_to_index, option->guile_option, search_value);
849     if (value == SCM_BOOL_F)
850     {
851         return -1;
852     }
853     else
854     {
855         return scm_to_int (value);
856     }
857 }
858 
859 /********************************************************************\
860  * gnc_option_permissible_value                                     *
861  *   returns the SCM handle to the indexth permissible value in the *
862  *   option, or SCM_UNDEFINED if the index was out of range or      *
863  *   there was some other problem.                                  *
864  *                                                                  *
865  * Args: option - the GNCOption                                     *
866  *       index  - the index of the permissible value                *
867  * Returns: SCM handle to option value or SCM_UNDEFINED             *
868 \********************************************************************/
869 SCM
gnc_option_permissible_value(GNCOption * option,int index)870 gnc_option_permissible_value (GNCOption *option, int index)
871 {
872     SCM value;
873 
874     if (index < 0)
875         return SCM_UNDEFINED;
876 
877     initialize_getters ();
878 
879     value = scm_call_2 (getters.index_to_value, option->guile_option,
880                         scm_from_int (index));
881 
882     return value;
883 }
884 
885 /********************************************************************\
886  * gnc_option_permissible_value_name                                *
887  *   returns the malloc'd name of the indexth permissible value in  *
888  *   the option, or NULL if the index was out of range or there are *
889  *   no values available.                                           *
890  *                                                                  *
891  * Args: option - the GNCOption                                     *
892  *       index  - the index of the permissible value                *
893  * Returns: malloc'd name of permissible value or NULL              *
894 \********************************************************************/
895 char *
gnc_option_permissible_value_name(GNCOption * option,int index)896 gnc_option_permissible_value_name (GNCOption *option, int index)
897 {
898     SCM name;
899 
900     if (index < 0)
901         return NULL;
902 
903     initialize_getters ();
904 
905     name = scm_call_2 (getters.index_to_name, option->guile_option,
906                        scm_from_int (index));
907     if (name == SCM_UNDEFINED)
908         return NULL;
909     if (!scm_is_string (name))
910         return NULL;
911 
912     return gnc_scm_to_utf8_string (name);
913 }
914 
915 /********************************************************************\
916  * gnc_option_show_time                                             *
917  *   returns true if the gui should display the time as well as     *
918  *   the date for this option. Only use this for date options.      *
919  *                                                                  *
920  * Args: option - the GNCOption                                     *
921  * Returns: true if time should be shown                            *
922 \********************************************************************/
923 gboolean
gnc_option_show_time(GNCOption * option)924 gnc_option_show_time (GNCOption *option)
925 {
926     SCM value;
927 
928     initialize_getters ();
929 
930     value = scm_call_1 (getters.date_option_show_time, option->guile_option);
931 
932     return scm_is_true (value);
933 }
934 
935 /********************************************************************\
936  * gnc_option_get_option_data                                       *
937  *   returns the option data of this option                         *
938  *                                                                  *
939  * Args: option - the GNCOption                                     *
940  * Returns: the option data                                         *
941 \********************************************************************/
942 SCM
gnc_option_get_option_data(GNCOption * option)943 gnc_option_get_option_data (GNCOption *option)
944 {
945     initialize_getters ();
946 
947     return scm_call_1 (getters.option_data, option->guile_option);
948 }
949 
950 /********************************************************************\
951  * gnc_option_multiple_selection                                    *
952  *   returns true if the gui should allow multiple selection of     *
953  *   accounts. Only use this for account options.                   *
954  *                                                                  *
955  * Args: option - the GNCOption                                     *
956  * Returns: true if multiple selection allowed                      *
957 \********************************************************************/
958 gboolean
gnc_option_multiple_selection(GNCOption * option)959 gnc_option_multiple_selection (GNCOption *option)
960 {
961     SCM pair;
962 
963     initialize_getters ();
964 
965     pair = scm_call_1 (getters.option_data, option->guile_option);
966 
967     return !scm_is_true (scm_not (SCM_CAR(pair)));
968 }
969 
970 /********************************************************************\
971  * gnc_option_get_account_type_list                                 *
972  *   returns the list of account_types in the option (or NULL if    *
973  *   no special list is provided).  Only use this for account       *
974  *   options.                                                       *
975  *                                                                  *
976  * Args: option - the GNCOption                                     *
977  * Returns: GList of account types (must be freed by caller)        *
978 \********************************************************************/
979 GList *
gnc_option_get_account_type_list(GNCOption * option)980 gnc_option_get_account_type_list (GNCOption *option)
981 {
982     SCM pair;
983     SCM lst;
984     GList *type_list = NULL;
985 
986     initialize_getters ();
987 
988     pair = scm_call_1 (getters.option_data, option->guile_option);
989     lst = SCM_CDR(pair);
990 
991     while (!scm_is_null (lst))
992     {
993         GNCAccountType type;
994         SCM item;
995 
996         /* Compute this item and the rest of the list */
997         item = SCM_CAR(lst);
998         lst = SCM_CDR(lst);
999 
1000         if (scm_is_false (scm_integer_p (item)))
1001         {
1002             PERR("Invalid type");
1003         }
1004         else
1005         {
1006             type = scm_to_long (item);
1007             type_list = g_list_prepend (type_list, GINT_TO_POINTER (type));
1008         }
1009     }
1010 
1011     return g_list_reverse (type_list);
1012 }
1013 
1014 /********************************************************************\
1015  * gnc_option_get_range_info                                        *
1016  *   returns the range info for a number range option in the pointer*
1017  *   arguments. NULL arguments are ignored. Use only for number     *
1018  *   range options.                                                 *
1019  *                                                                  *
1020  * Args: option - the GNCOption                                     *
1021  * Returns: true if everything went ok :)                           *
1022 \********************************************************************/
gnc_option_get_range_info(GNCOption * option,double * lower_bound,double * upper_bound,int * num_decimals,double * step_size)1023 gboolean gnc_option_get_range_info (GNCOption *option,
1024                                     double *lower_bound,
1025                                     double *upper_bound,
1026                                     int    *num_decimals,
1027                                     double *step_size)
1028 {
1029     SCM list;
1030     SCM value;
1031 
1032     initialize_getters ();
1033 
1034     list = scm_call_1 (getters.option_data, option->guile_option);
1035 
1036     if (!scm_is_list (list) || scm_is_null (list))
1037         return FALSE;
1038 
1039     /* lower bound */
1040     value = SCM_CAR(list);
1041     list = SCM_CDR(list);
1042 
1043     if (!scm_is_number (value))
1044         return FALSE;
1045 
1046     if (lower_bound != NULL)
1047         *lower_bound = scm_to_double (value);
1048 
1049     if (!scm_is_list (list) || scm_is_null (list))
1050         return FALSE;
1051 
1052     /* upper bound */
1053     value = SCM_CAR(list);
1054     list = SCM_CDR(list);
1055 
1056     if (!scm_is_number (value))
1057         return FALSE;
1058 
1059     if (upper_bound != NULL)
1060         *upper_bound = scm_to_double (value);
1061 
1062     if (!scm_is_list (list) || scm_is_null (list))
1063         return FALSE;
1064 
1065     /* number of decimals */
1066     value = SCM_CAR(list);
1067     list = SCM_CDR(list);
1068 
1069     if (!scm_is_number (value))
1070         return FALSE;
1071 
1072     /* Guile-1.6 returns this as a double, so let's use that in all cases.
1073      * This is still safe for earlier guiles, too -- tested with 1.3.4.
1074      */
1075     if (num_decimals != NULL)
1076     {
1077         double decimals = scm_to_double (value);
1078         *num_decimals = (int)decimals;
1079     }
1080 
1081     if (!scm_is_list (list) || scm_is_null (list))
1082         return FALSE;
1083 
1084     /* step size */
1085     value = SCM_CAR(list);
1086 
1087     if (!scm_is_number (value))
1088         return FALSE;
1089 
1090     if (step_size != NULL)
1091         *step_size = scm_to_double (value);
1092 
1093     return TRUE;
1094 }
1095 
1096 /********************************************************************\
1097  * gnc_option_color_range                                           *
1098  *   returns the color range for rgba values.                       *
1099  *   Only use this for color options.                               *
1100  *                                                                  *
1101  * Args: option - the GNCOption                                     *
1102  * Returns: color range for the option                              *
1103 \********************************************************************/
1104 gdouble
gnc_option_color_range(GNCOption * option)1105 gnc_option_color_range (GNCOption *option)
1106 {
1107     SCM list;
1108     SCM value;
1109 
1110     initialize_getters ();
1111 
1112     list = scm_call_1 (getters.option_data, option->guile_option);
1113     if (!scm_is_list (list) || scm_is_null (list))
1114         return 0.0;
1115 
1116     value = SCM_CAR(list);
1117     if (!scm_is_number (value))
1118         return 0.0;
1119 
1120     return scm_to_double (value);
1121 }
1122 
1123 /********************************************************************\
1124  * gnc_option_use_alpha                                             *
1125  *   returns true if the color option should use alpha transparency *
1126  *   Only use this for color options.                               *
1127  *                                                                  *
1128  * Args: option - the GNCOption                                     *
1129  * Returns: true if alpha transparency should be used               *
1130 \********************************************************************/
1131 gdouble
gnc_option_use_alpha(GNCOption * option)1132 gnc_option_use_alpha (GNCOption *option)
1133 {
1134     SCM list;
1135     SCM value;
1136 
1137     initialize_getters ();
1138 
1139     list = scm_call_1 (getters.option_data, option->guile_option);
1140     if (!scm_is_list (list) || scm_is_null (list))
1141         return FALSE;
1142 
1143     list = SCM_CDR(list);
1144     if (!scm_is_list (list) || scm_is_null (list))
1145         return FALSE;
1146 
1147     value = SCM_CAR(list);
1148     if (!scm_is_bool (value))
1149         return FALSE;
1150 
1151     return scm_is_true (value);
1152 }
1153 
1154 /********************************************************************\
1155  * gnc_option_get_color_argb                                        *
1156  *   returns the argb value of a color option                       *
1157  *                                                                  *
1158  * Args: option - the GNCOption                                     *
1159  * Returns: argb value of option                                    *
1160 \********************************************************************/
1161 guint32
gnc_option_get_color_argb(GNCOption * option)1162 gnc_option_get_color_argb (GNCOption *option)
1163 {
1164     gdouble red, green, blue, alpha;
1165     guint32 color = 0;
1166 
1167     if (!gnc_option_get_color_info (option, FALSE, &red, &green, &blue, &alpha))
1168         return 0;
1169 
1170     color |= (guint32) (alpha * 255.0);
1171     color <<= 8;
1172 
1173     color |= (guint32) (red * 255.0);
1174     color <<= 8;
1175 
1176     color |= (guint32) (green * 255.0);
1177     color <<= 8;
1178 
1179     color |= (guint32) (blue * 255.0);
1180 
1181     return color;
1182 }
1183 
1184 /********************************************************************\
1185  * gnc_option_get_color_info                                        *
1186  *   gets the color information from a color option. rgba values    *
1187  *   returned are between 0.0 and 1.0.                              *
1188  *                                                                  *
1189  * Args: option      - option to get info from                      *
1190  *       use_default - use the default or current value             *
1191  *       red         - where to store the red value                 *
1192  *       blue        - where to store the blue value                *
1193  *       green       - where to store the green value               *
1194  *       alpha       - where to store the alpha value               *
1195  * Return: true if everything went ok                               *
1196 \********************************************************************/
1197 gboolean
gnc_option_get_color_info(GNCOption * option,gboolean use_default,gdouble * red,gdouble * green,gdouble * blue,gdouble * alpha)1198 gnc_option_get_color_info (GNCOption *option,
1199                            gboolean use_default,
1200                            gdouble *red,
1201                            gdouble *green,
1202                            gdouble *blue,
1203                            gdouble *alpha)
1204 {
1205     gdouble scale;
1206     gdouble rgba;
1207     SCM getter;
1208     SCM value;
1209 
1210     if (option == NULL)
1211         return FALSE;
1212 
1213     if (use_default)
1214         getter = gnc_option_default_getter (option);
1215     else
1216         getter = gnc_option_getter (option);
1217     if (getter == SCM_UNDEFINED)
1218         return FALSE;
1219 
1220     value = scm_call_0 (getter);
1221     if (!scm_is_list (value) || scm_is_null (value) || !scm_is_number (SCM_CAR(value)))
1222         return FALSE;
1223 
1224     scale = gnc_option_color_range (option);
1225     if (scale <= 0.0)
1226         return FALSE;
1227 
1228     scale = 1.0 / scale;
1229 
1230     rgba = scm_to_double (SCM_CAR(value));
1231     if (red != NULL)
1232         *red = MIN(1.0, rgba * scale);
1233 
1234     value = SCM_CDR(value);
1235     if (!scm_is_list (value) || scm_is_null (value) || !scm_is_number (SCM_CAR(value)))
1236         return FALSE;
1237 
1238     rgba = scm_to_double (SCM_CAR(value));
1239     if (green != NULL)
1240         *green = MIN(1.0, rgba * scale);
1241 
1242     value = SCM_CDR(value);
1243     if (!scm_is_list (value) || scm_is_null (value) || !scm_is_number (SCM_CAR(value)))
1244         return FALSE;
1245 
1246     rgba = scm_to_double (SCM_CAR(value));
1247     if (blue != NULL)
1248         *blue = MIN(1.0, rgba * scale);
1249 
1250     value = SCM_CDR(value);
1251     if (!scm_is_list (value) || scm_is_null (value) || !scm_is_number (SCM_CAR(value)))
1252         return FALSE;
1253 
1254     rgba = scm_to_double (SCM_CAR(value));
1255     if (alpha != NULL)
1256         *alpha = MIN(1.0, rgba * scale);
1257 
1258     return TRUE;
1259 }
1260 
1261 /********************************************************************\
1262  * gnc_option_set_default                                           *
1263  *   set the option to its default value                            *
1264  *                                                                  *
1265  * Args: option - the GNCOption                                     *
1266  * Returns: nothing                                                 *
1267 \********************************************************************/
1268 void
gnc_option_set_default(GNCOption * option)1269 gnc_option_set_default (GNCOption *option)
1270 {
1271     SCM default_getter;
1272     SCM setter;
1273     SCM value;
1274 
1275     if (option == NULL)
1276         return;
1277 
1278     default_getter = gnc_option_default_getter (option);
1279     if (default_getter == SCM_UNDEFINED)
1280         return;
1281 
1282     value = scm_call_0 (default_getter);
1283 
1284     setter = gnc_option_setter (option);
1285     if (setter == SCM_UNDEFINED)
1286         return;
1287 
1288     scm_call_1 (setter, value);
1289 }
1290 
1291 static gint
compare_sections(gconstpointer a,gconstpointer b)1292 compare_sections (gconstpointer a, gconstpointer b)
1293 {
1294     const GNCOptionSection *sa = a;
1295     const GNCOptionSection *sb = b;
1296 
1297     return g_strcmp0 (sa->section_name, sb->section_name);
1298 }
1299 
1300 static gint
compare_option_tags(gconstpointer a,gconstpointer b)1301 compare_option_tags (gconstpointer a, gconstpointer b)
1302 {
1303     GNCOption *oa = (GNCOption *) a;
1304     GNCOption *ob = (GNCOption *) b;
1305     char *tag_a = gnc_option_sort_tag (oa);
1306     char *tag_b = gnc_option_sort_tag (ob);
1307     gint result;
1308 
1309     result = g_strcmp0 (tag_a, tag_b);
1310 
1311     if (tag_a != NULL)
1312         free (tag_a);
1313 
1314     if (tag_b != NULL)
1315         free (tag_b);
1316 
1317     return result;
1318 }
1319 
1320 /********************************************************************\
1321  * gnc_option_db_dirty                                              *
1322  *   returns true if guile has registered more options into the     *
1323  *   database since the last time the database was cleaned.         *
1324  *                                                                  *
1325  * Returns: dirty flag                                              *
1326 \********************************************************************/
1327 gboolean
gnc_option_db_dirty(GNCOptionDB * odb)1328 gnc_option_db_dirty (GNCOptionDB *odb)
1329 {
1330     g_return_val_if_fail (odb, FALSE);
1331 
1332     return odb->options_dirty;
1333 }
1334 
1335 /********************************************************************\
1336  * gnc_option_db_clean                                              *
1337  *   resets the dirty flag of the option database                   *
1338  *                                                                  *
1339 \********************************************************************/
1340 void
gnc_option_db_clean(GNCOptionDB * odb)1341 gnc_option_db_clean (GNCOptionDB *odb)
1342 {
1343     g_return_if_fail (odb);
1344 
1345     odb->options_dirty = FALSE;
1346 }
1347 
1348 /********************************************************************\
1349  * _gnc_option_db_register_option                                   *
1350  *   registers an option with an option database. Intended to be    *
1351  *   called from guile.                                             *
1352  *                                                                  *
1353  * Args: odb    - the option database                               *
1354  *       option - the guile option                                  *
1355  * Returns: nothing                                                 *
1356 \********************************************************************/
1357 void
gnc_option_db_register_option(GNCOptionDBHandle handle,SCM guile_option)1358 gnc_option_db_register_option (GNCOptionDBHandle handle, SCM guile_option)
1359 {
1360     GNCOptionDB *odb;
1361     GNCOption *option;
1362     GNCOptionSection *section;
1363 
1364     odb = g_hash_table_lookup (option_dbs, &handle);
1365 
1366     g_return_if_fail (odb != NULL);
1367 
1368     odb->options_dirty = TRUE;
1369 
1370     /* Make the option structure */
1371     option = g_new0 (GNCOption, 1);
1372     option->guile_option = guile_option;
1373     option->changed = FALSE;
1374     option->widget = NULL;
1375     option->odb = odb;
1376 
1377     /* Prevent guile from garbage collecting the option */
1378     scm_gc_protect_object (guile_option);
1379 
1380     /* Make the section structure */
1381     section = g_new0 (GNCOptionSection, 1);
1382     section->section_name = gnc_option_section (option);
1383     section->options = NULL;
1384 
1385     /* See if the section is already there */
1386     {
1387         GSList *old;
1388 
1389         old = g_slist_find_custom (odb->option_sections, section, compare_sections);
1390 
1391         if (old != NULL)
1392         {
1393             if (section->section_name != NULL)
1394                 free (section->section_name);
1395             g_free (section);
1396             section = old->data;
1397         }
1398         else
1399             odb->option_sections = g_slist_insert_sorted (odb->option_sections,
1400                                                           section,
1401                                                           compare_sections);
1402     }
1403 
1404     section->options = g_slist_insert_sorted (section->options, option,
1405                                               compare_option_tags);
1406 }
1407 
1408 /********************************************************************\
1409  * gnc_option_db_num_sections                                       *
1410  *   returns the number of option sections registered so far in the *
1411  *   database                                                       *
1412  *                                                                  *
1413  * Args: odb - the database to count sections for                   *
1414  * Returns: number of option sections                               *
1415 \********************************************************************/
1416 guint
gnc_option_db_num_sections(GNCOptionDB * odb)1417 gnc_option_db_num_sections (GNCOptionDB *odb)
1418 {
1419     return g_slist_length (odb->option_sections);
1420 }
1421 
1422 /********************************************************************\
1423  * gnc_option_db_get_section                                        *
1424  *   returns the ith option section in the database, or NULL        *
1425  *                                                                  *
1426  * Args: odb - the option database                                  *
1427  *       i   - index of section                                     *
1428  * Returns: ith option sectioin                                     *
1429 \********************************************************************/
1430 GNCOptionSection *
gnc_option_db_get_section(GNCOptionDB * odb,gint i)1431 gnc_option_db_get_section (GNCOptionDB *odb, gint i)
1432 {
1433     return g_slist_nth_data (odb->option_sections, i);
1434 }
1435 
1436 /********************************************************************\
1437  * gnc_option_section_name                                          *
1438  *   returns the name of the options section                        *
1439  *                                                                  *
1440  * Args: section - section to get name of                           *
1441  * Returns: name of option section                                  *
1442 \********************************************************************/
1443 const char *
gnc_option_section_name(GNCOptionSection * section)1444 gnc_option_section_name (GNCOptionSection *section)
1445 {
1446     return section->section_name;
1447 }
1448 
1449 /********************************************************************\
1450  * gnc_option_section_num_options                                   *
1451  *   returns the number of options in a given section               *
1452  *                                                                  *
1453  * Args: section - section to count options for                     *
1454  * Returns: number of options in section                            *
1455 \********************************************************************/
1456 guint
gnc_option_section_num_options(GNCOptionSection * section)1457 gnc_option_section_num_options (GNCOptionSection *section)
1458 {
1459     return g_slist_length (section->options);
1460 }
1461 
1462 /********************************************************************\
1463  * gnc_get_option_section_option                                    *
1464  *   returns the ith option in a given section                      *
1465  *                                                                  *
1466  * Args: section - section to retrieve option for                   *
1467  *       i       - index of option                                  *
1468  * Returns: ith option in section                                   *
1469 \********************************************************************/
1470 GNCOption *
gnc_get_option_section_option(GNCOptionSection * section,int i)1471 gnc_get_option_section_option (GNCOptionSection *section, int i)
1472 {
1473     return g_slist_nth_data (section->options, i);
1474 }
1475 
1476 /********************************************************************\
1477  * gnc_option_db_get_option_by_name                                 *
1478  *   returns an option given section name and name                  *
1479  *                                                                  *
1480  * Args: odb          - option database to search in                *
1481  *       section_name - name of section to search for               *
1482  *       name         - name to search for                          *
1483  * Returns: given option, or NULL if none                           *
1484 \********************************************************************/
1485 GNCOption *
gnc_option_db_get_option_by_name(GNCOptionDB * odb,const char * section_name,const char * name)1486 gnc_option_db_get_option_by_name (GNCOptionDB *odb,
1487                                   const char *section_name,
1488                                   const char *name)
1489 {
1490     GSList *section_node;
1491     GSList *option_node;
1492     GNCOptionSection section_key;
1493     GNCOptionSection *section;
1494     GNCOption *option;
1495     gint result;
1496     char *node_name;
1497 
1498     if (odb == NULL)
1499         return NULL;
1500 
1501     section_key.section_name = (char *) section_name;
1502 
1503     section_node = g_slist_find_custom (odb->option_sections, &section_key,
1504                                         compare_sections);
1505 
1506     if (section_node == NULL)
1507         return NULL;
1508 
1509     section = section_node->data;
1510     option_node = section->options;
1511 
1512     while (option_node != NULL)
1513     {
1514         option = option_node->data;
1515 
1516         node_name = gnc_option_name (option);
1517         result = g_strcmp0 (name, node_name);
1518         free (node_name);
1519 
1520         if (result == 0)
1521             return option;
1522 
1523         option_node = option_node->next;
1524     }
1525     return NULL;
1526 }
1527 
1528 /********************************************************************\
1529  * gnc_option_db_get_option_by_SCM                                  *
1530  *   returns an option given SCM handle. Uses section and name.     *
1531  *                                                                  *
1532  * Args: odb          - option database to search in                *
1533  *       guile_option - SCM handle of option                        *
1534  * Returns: given option, or NULL if none                           *
1535 \********************************************************************/
1536 GNCOption *
gnc_option_db_get_option_by_SCM(GNCOptionDB * odb,SCM guile_option)1537 gnc_option_db_get_option_by_SCM (GNCOptionDB *odb, SCM guile_option)
1538 {
1539     GNCOption option_key;
1540     GNCOption *option;
1541     char *section_name;
1542     char *name;
1543 
1544     option_key.guile_option = guile_option;
1545 
1546     section_name = gnc_option_section (&option_key);
1547     name = gnc_option_name (&option_key);
1548 
1549     option = gnc_option_db_get_option_by_name (odb, section_name, name);
1550 
1551     if (section_name != NULL)
1552         free (section_name);
1553 
1554     if (name != NULL)
1555         free (name);
1556 
1557     return option;
1558 }
1559 
1560 static SCM
gnc_option_valid_value(GNCOption * option,SCM value)1561 gnc_option_valid_value (GNCOption *option, SCM value)
1562 {
1563     SCM validator;
1564     SCM result, ok;
1565 
1566     validator = gnc_option_value_validator (option);
1567 
1568     result = scm_call_1 (validator, value);
1569     if (!scm_is_list (result) || scm_is_null (result))
1570         return SCM_UNDEFINED;
1571 
1572     ok = SCM_CAR(result);
1573     if (!scm_is_bool (ok))
1574         return SCM_UNDEFINED;
1575 
1576     if (!scm_is_true (ok))
1577         return SCM_UNDEFINED;
1578 
1579     result = SCM_CDR(result);
1580     if (!scm_is_list (result) || scm_is_null (result))
1581         return SCM_UNDEFINED;
1582 
1583     return SCM_CAR(result);
1584 }
1585 
1586 static char*
gnc_commit_option(GNCOption * option)1587 gnc_commit_option (GNCOption *option)
1588 {
1589     SCM validator, setter, value;
1590     SCM result, ok;
1591     char* retval = NULL;
1592 
1593     /* Validate the ui's value */
1594     value = gnc_option_get_ui_value (option);
1595     if (value == SCM_UNDEFINED)
1596         return NULL;
1597 
1598     validator = gnc_option_value_validator (option);
1599 
1600     result = scm_call_1(validator, value);
1601     if (!scm_is_list (result) || scm_is_null (result))
1602     {
1603         PERR("bad validation result\n");
1604         return NULL;
1605     }
1606 
1607     /* First element determines validity */
1608     ok = SCM_CAR(result);
1609     if (!scm_is_bool (ok))
1610     {
1611         PERR("bad validation result\n");
1612         return NULL;
1613     }
1614 
1615     if (scm_is_true (ok))
1616     {
1617         /* Second element is value to use */
1618         value = SCM_CADR(result);
1619         setter = gnc_option_setter (option);
1620 
1621         scm_call_1 (setter, value);
1622 
1623         gnc_option_set_ui_value (option, FALSE);
1624     }
1625     else
1626     {
1627         SCM oops;
1628         char *section, *name;
1629         const char *message = NULL;
1630         const char *format = _("There is a problem with option %s:%s.\n%s");
1631         const char *bad_value = _("Invalid option value");
1632 
1633         name = gnc_option_name (option);
1634         section = gnc_option_section (option);
1635 
1636         /* Second element is error message */
1637         oops = SCM_CADR(result);
1638         if (!scm_is_string (oops))
1639         {
1640             PERR("bad validation result\n");
1641             retval = g_strdup_printf (format,
1642                                       section ? section : "(null)",
1643                                       name ? name : "(null)",
1644                                       bad_value);
1645         }
1646         else
1647         {
1648             message = gnc_scm_to_utf8_string (oops);
1649             retval = g_strdup_printf (format,
1650                                       section ? section : "(null)",
1651                                       name ? name : "(null)",
1652                                       message ? message : "(null)");
1653         }
1654         if (name != NULL)
1655             free (name);
1656         if (section != NULL)
1657             free (section);
1658         g_free ((gpointer *) message);
1659     }
1660     return retval;
1661 }
1662 
1663 /********************************************************************\
1664  * gnc_option_db_get_changed                                        *
1665  *   returns a boolean value, TRUE if any option has changed,       *
1666  *   FALSE is none of the options have changed                      *
1667  *                                                                  *
1668  * Args: odb - option database to check                             *
1669  * Return: boolean                                                  *
1670 \********************************************************************/
1671 gboolean
gnc_option_db_get_changed(GNCOptionDB * odb)1672 gnc_option_db_get_changed (GNCOptionDB *odb)
1673 {
1674     GSList *section_node;
1675     GSList *option_node;
1676     GNCOptionSection *section;
1677     GNCOption *option;
1678 
1679     g_return_val_if_fail (odb, FALSE);
1680 
1681     for (section_node = odb->option_sections; section_node;
1682             section_node = section_node->next)
1683     {
1684         section = section_node->data;
1685 
1686         for (option_node = section->options; option_node;
1687                 option_node = option_node->next)
1688         {
1689             option = option_node->data;
1690 
1691             if (option->changed)
1692                 return TRUE;
1693         }
1694     }
1695     return FALSE;
1696 }
1697 
1698 /********************************************************************\
1699  * gnc_option_db_commit                                             *
1700  *   commits the options which have changed, and which are valid    *
1701  *   for those which are not valid, error dialogs are shown.        *
1702  *                                                                  *
1703  * Args: odb - option database to commit                            *
1704  * Return: nothing                                                  *
1705 \********************************************************************/
1706 GList*
gnc_option_db_commit(GNCOptionDB * odb)1707 gnc_option_db_commit (GNCOptionDB *odb)
1708 {
1709     GSList *section_node;
1710     GSList *option_node;
1711     GNCOptionSection *section;
1712     GNCOption *option;
1713     gboolean changed_something = FALSE;
1714     GList *commit_errors = NULL;
1715 
1716     g_return_val_if_fail (odb, NULL);
1717 
1718     section_node = odb->option_sections;
1719     while (section_node != NULL)
1720     {
1721         section = section_node->data;
1722 
1723         option_node = section->options;
1724         while (option_node != NULL)
1725         {
1726             option = option_node->data;
1727 
1728             if (option->changed)
1729             {
1730                 char *result = NULL;
1731                 result = gnc_commit_option (option_node->data);
1732                 if (result)
1733                     commit_errors = g_list_append (commit_errors, result);
1734                 changed_something = TRUE;
1735                 option->changed = FALSE;
1736             }
1737             option_node = option_node->next;
1738         }
1739         section_node = section_node->next;
1740     }
1741     if (changed_something)
1742         gnc_call_option_change_callbacks (odb);
1743 
1744     return commit_errors;
1745 }
1746 
1747 /********************************************************************\
1748  * gnc_option_db_section_reset_widgets                              *
1749  *   reset all option widgets in one section to their default.      *
1750  *   values                                                         *
1751  *                                                                  *
1752  * Args: odb - option database to reset                             *
1753  * Return: nothing                                                  *
1754 \********************************************************************/
1755 void
gnc_option_db_section_reset_widgets(GNCOptionSection * section)1756 gnc_option_db_section_reset_widgets (GNCOptionSection *section)
1757 {
1758     GSList *option_node;
1759     GNCOption *option;
1760 
1761     g_return_if_fail (section);
1762 
1763     /* Don't reset "invisible" options.
1764      * If the section name begins "__" we should not reset
1765      */
1766     if (section->section_name == NULL ||
1767             strncmp (section->section_name, "__", 2) == 0)
1768         return;
1769 
1770     for (option_node = section->options;
1771             option_node != NULL;
1772             option_node = option_node->next)
1773     {
1774         option = option_node->data;
1775         gnc_option_set_ui_value (option, TRUE);
1776     }
1777 }
1778 
1779 /********************************************************************\
1780  * gnc_option_db_reset_widgets                                      *
1781  *   reset all option widgets to their default values.              *
1782  *                                                                  *
1783  * Args: odb - option database to reset                             *
1784  * Return: nothing                                                  *
1785 \********************************************************************/
1786 void
gnc_option_db_reset_widgets(GNCOptionDB * odb)1787 gnc_option_db_reset_widgets (GNCOptionDB *odb)
1788 {
1789     GSList *section_node;
1790     GNCOptionSection *section;
1791 
1792     g_return_if_fail (odb);
1793 
1794     for (section_node = odb->option_sections;
1795             section_node != NULL;
1796             section_node = section_node->next)
1797     {
1798         section = section_node->data;
1799         gnc_option_db_section_reset_widgets (section);
1800     }
1801 }
1802 
1803 /********************************************************************\
1804  * gnc_option_db_get_default_section                                *
1805  *   returns the malloc'd section name of the default section,      *
1806  *   or NULL if there is none.                                      *
1807  *                                                                  *
1808  * Args: odb - option database to get default page for              *
1809  * Return: g_malloc'd default section name                          *
1810 \********************************************************************/
1811 char *
gnc_option_db_get_default_section(GNCOptionDB * odb)1812 gnc_option_db_get_default_section (GNCOptionDB *odb)
1813 {
1814     SCM getter;
1815     SCM value;
1816 
1817     if (odb == NULL)
1818         return NULL;
1819 
1820     getter = scm_c_eval_string ("gnc:options-get-default-section");
1821     if (!scm_is_procedure (getter))
1822         return NULL;
1823 
1824     value = scm_call_1 (getter, odb->guile_options);
1825     if (!scm_is_string (value))
1826         return NULL;
1827 
1828     return gnc_scm_to_utf8_string (value);
1829 }
1830 
1831 /********************************************************************\
1832  * gnc_option_db_lookup_option                                      *
1833  *   looks up an option. If present, returns its SCM value,         *
1834  *   otherwise returns the default.                                 *
1835  *                                                                  *
1836  * Args: odb     - option database to search in                     *
1837  *       section - section name of option                           *
1838  *       name    - name of option                                   *
1839  *       default - default value if not found                       *
1840  * Return: option value                                             *
1841 \********************************************************************/
1842 SCM
gnc_option_db_lookup_option(GNCOptionDB * odb,const char * section,const char * name,SCM default_value)1843 gnc_option_db_lookup_option (GNCOptionDB *odb,
1844                              const char *section,
1845                              const char *name,
1846                              SCM default_value)
1847 {
1848     GNCOption *option;
1849     SCM getter;
1850 
1851     option = gnc_option_db_get_option_by_name (odb, section, name);
1852 
1853     if (option == NULL)
1854         return default_value;
1855 
1856     getter = gnc_option_getter (option);
1857     if (getter == SCM_UNDEFINED)
1858         return default_value;
1859 
1860     return scm_call_0 (getter);
1861 }
1862 
1863 /********************************************************************\
1864  * gnc_option_db_lookup_boolean_option                              *
1865  *   looks up a boolean option. If present, returns its value,      *
1866  *   otherwise returns the default.                                 *
1867  *                                                                  *
1868  * Args: odb     - option database to search in                     *
1869  *       section - section name of option                           *
1870  *       name    - name of option                                   *
1871  *       default - default value if not found                       *
1872  * Return: gboolean option value                                    *
1873 \********************************************************************/
1874 gboolean
gnc_option_db_lookup_boolean_option(GNCOptionDB * odb,const char * section,const char * name,gboolean default_value)1875 gnc_option_db_lookup_boolean_option (GNCOptionDB *odb,
1876                                      const char *section,
1877                                      const char *name,
1878                                      gboolean default_value)
1879 {
1880     GNCOption *option;
1881     SCM getter;
1882     SCM value;
1883 
1884     option = gnc_option_db_get_option_by_name (odb, section, name);
1885 
1886     if (option == NULL)
1887         return default_value;
1888 
1889     getter = gnc_option_getter (option);
1890     if (getter == SCM_UNDEFINED)
1891         return default_value;
1892 
1893     value = scm_call_0 (getter);
1894 
1895     if (scm_is_bool (value))
1896         return scm_is_true (value);
1897     else
1898         return default_value;
1899 }
1900 
1901 /********************************************************************\
1902  * gnc_option_db_lookup_string_option                               *
1903  *   looks up a string option. If present, returns its malloc'ed    *
1904  *   value, otherwise returns the strdup'ed default, or NULL if     *
1905  *   default was NULL.                                              *
1906  *                                                                  *
1907  * Args: odb     - option database to search in                     *
1908  *       section - section name of option                           *
1909  *       name    - name of option                                   *
1910  *       default - default value if not found                       *
1911  * Return: char * option value                                      *
1912 \********************************************************************/
1913 char *
gnc_option_db_lookup_string_option(GNCOptionDB * odb,const char * section,const char * name,const char * default_value)1914 gnc_option_db_lookup_string_option (GNCOptionDB *odb,
1915                                     const char *section,
1916                                     const char *name,
1917                                     const char *default_value)
1918 {
1919     GNCOption *option;
1920     SCM getter;
1921     SCM value;
1922 
1923     option = gnc_option_db_get_option_by_name (odb, section, name);
1924 
1925     if (option != NULL)
1926     {
1927         getter = gnc_option_getter (option);
1928         if (getter != SCM_UNDEFINED)
1929         {
1930             value = scm_call_0 (getter);
1931             if (scm_is_string (value))
1932                 return gnc_scm_to_utf8_string (value);
1933         }
1934     }
1935 
1936     if (default_value == NULL)
1937         return NULL;
1938 
1939     return strdup (default_value);
1940 }
1941 
1942 /********************************************************************\
1943  * gnc_option_db_lookup_font_option                                 *
1944  *   looks up a font option. If present, returns its malloc'ed      *
1945  *   string value, otherwise returns the strdup'ed default, or NULL *
1946  *   if default was NULL.                                           *
1947  *                                                                  *
1948  * Args: odb     - option database to search in                     *
1949  *       section - section name of option                           *
1950  *       name    - name of option                                   *
1951  *       default - default value if not found                       *
1952  * Return: char * option value                                      *
1953 \********************************************************************/
1954 char *
gnc_option_db_lookup_font_option(GNCOptionDB * odb,const char * section,const char * name,const char * default_value)1955 gnc_option_db_lookup_font_option (GNCOptionDB *odb,
1956                                   const char *section,
1957                                   const char *name,
1958                                   const char *default_value)
1959 {
1960     return gnc_option_db_lookup_string_option (odb, section, name, default_value);
1961 }
1962 
1963 /********************************************************************\
1964  * gnc_option_db_lookup_multichoice_option                          *
1965  *   looks up a multichoice option. If present, returns its         *
1966  *   name as a malloc'ed string                                     *
1967  *   value, otherwise returns the strdup'ed default, or NULL if     *
1968  *   default was NULL.                                              *
1969  *                                                                  *
1970  * Args: odb     - option database to search in                     *
1971  *       section - section name of option                           *
1972  *       name    - name of option                                   *
1973  *       default - default value if not found                       *
1974  * Return: char * option value                                      *
1975 \********************************************************************/
1976 char *
gnc_option_db_lookup_multichoice_option(GNCOptionDB * odb,const char * section,const char * name,const char * default_value)1977 gnc_option_db_lookup_multichoice_option (GNCOptionDB *odb,
1978                                          const char *section,
1979                                          const char *name,
1980                                          const char *default_value)
1981 {
1982     GNCOption *option;
1983     SCM getter;
1984     SCM value;
1985 
1986     option = gnc_option_db_get_option_by_name (odb, section, name);
1987 
1988     if (option != NULL)
1989     {
1990         getter = gnc_option_getter (option);
1991         if (getter != SCM_UNDEFINED)
1992         {
1993             value = scm_call_0 (getter);
1994             if (scm_is_symbol (value))
1995                 return gnc_scm_symbol_to_locale_string (value);
1996         }
1997     }
1998 
1999     if (default_value == NULL)
2000         return NULL;
2001 
2002     return strdup (default_value);
2003 }
2004 
2005 /********************************************************************\
2006  * gnc_option_db_lookup_number_option                               *
2007  *   looks up a number option. If present, returns its value        *
2008  *   as a gdouble, otherwise returns the default_value.             *
2009  *                                                                  *
2010  * Args: odb       - option database to search in                   *
2011  *       section   - section name of option                         *
2012  *       name      - name of option                                 *
2013  *       default   - default value if not found                     *
2014  * Return: gdouble representation of value                          *
2015 \********************************************************************/
2016 gdouble
gnc_option_db_lookup_number_option(GNCOptionDB * odb,const char * section,const char * name,gdouble default_value)2017 gnc_option_db_lookup_number_option (GNCOptionDB *odb,
2018                                     const char *section,
2019                                     const char *name,
2020                                     gdouble default_value)
2021 {
2022     GNCOption *option;
2023     SCM getter;
2024     SCM value;
2025 
2026     option = gnc_option_db_get_option_by_name (odb, section, name);
2027 
2028     if (option != NULL)
2029     {
2030         getter = gnc_option_getter (option);
2031         if (getter != SCM_UNDEFINED)
2032         {
2033             value = scm_call_0 (getter);
2034             if (scm_is_number (value))
2035                 return scm_to_double (value);
2036         }
2037     }
2038     return default_value;
2039 }
2040 
2041 /********************************************************************\
2042  * gnc_option_db_lookup_color_option                                *
2043  *   looks up a color option. If present, returns its value in the  *
2044  *   color variable, otherwise leaves the color variable alone.     *
2045  *                                                                  *
2046  * Args: odb       - option database to search in                   *
2047  *       section   - section name of option                         *
2048  *       name      - name of option                                 *
2049  *       red       - where to store the red value                   *
2050  *       blue      - where to store the blue value                  *
2051  *       green     - where to store the green value                 *
2052  *       alpha     - where to store the alpha value                 *
2053  * Return: true if option was found                                 *
2054 \********************************************************************/
gnc_option_db_lookup_color_option(GNCOptionDB * odb,const char * section,const char * name,gdouble * red,gdouble * green,gdouble * blue,gdouble * alpha)2055 gboolean gnc_option_db_lookup_color_option (GNCOptionDB *odb,
2056                                             const char *section,
2057                                             const char *name,
2058                                             gdouble *red,
2059                                             gdouble *green,
2060                                             gdouble *blue,
2061                                             gdouble *alpha)
2062 {
2063     GNCOption *option;
2064 
2065     option = gnc_option_db_get_option_by_name (odb, section, name);
2066 
2067     return gnc_option_get_color_info (option, FALSE, red, green, blue, alpha);
2068 }
2069 
2070 /********************************************************************\
2071  * gnc_option_db_lookup_color_option_argb                           *
2072  *   looks up a color option. If present, returns its argb value,   *
2073  *   otherwise returns the given default value.                     *
2074  *                                                                  *
2075  * Args: odb       - option database to search in                   *
2076  *       section   - section name of option                         *
2077  *       name      - name of option                                 *
2078  *       default_value - default value to return if problem         *
2079  * Return: argb value                                               *
2080 \********************************************************************/
gnc_option_db_lookup_color_option_argb(GNCOptionDB * odb,const char * section,const char * name,guint32 default_value)2081 guint32 gnc_option_db_lookup_color_option_argb (GNCOptionDB *odb,
2082                                                 const char *section,
2083                                                 const char *name,
2084                                                 guint32 default_value)
2085 {
2086     GNCOption *option;
2087 
2088     option = gnc_option_db_get_option_by_name (odb, section, name);
2089     if (option == NULL)
2090         return default_value;
2091 
2092     return gnc_option_get_color_argb (option);
2093 }
2094 
2095 /********************************************************************\
2096  * gnc_option_db_lookup_list_option                                 *
2097  *   looks up a list option. If present, returns its value as a     *
2098  *   list of strings representing the symbols.                      *
2099  *                                                                  *
2100  * Args: odb       - option database to search in                   *
2101  *       section   - section name of option                         *
2102  *       name      - name of option                                 *
2103  *       default_value - default value to return if problem         *
2104  * Return: list of values                                           *
2105 \********************************************************************/
2106 GSList *
gnc_option_db_lookup_list_option(GNCOptionDB * odb,const char * section,const char * name,GSList * default_value)2107 gnc_option_db_lookup_list_option (GNCOptionDB *odb,
2108                                   const char *section,
2109                                   const char *name,
2110                                   GSList *default_value)
2111 {
2112     GNCOption *option;
2113     GSList *list = NULL;
2114     SCM getter;
2115     SCM value;
2116     SCM item;
2117 
2118     option = gnc_option_db_get_option_by_name (odb, section, name);
2119     if (option == NULL)
2120         return default_value;
2121 
2122     getter = gnc_option_getter (option);
2123     if (getter == SCM_UNDEFINED)
2124         return default_value;
2125 
2126     value = scm_call_0 (getter);
2127     while (scm_is_list (value) && !scm_is_null (value))
2128     {
2129         item = SCM_CAR(value);
2130         value = SCM_CDR(value);
2131 
2132         if (!scm_is_symbol (item))
2133         {
2134             gnc_free_list_option_value (list);
2135 
2136             return default_value;
2137         }
2138 
2139         list = g_slist_prepend (list, gnc_scm_symbol_to_locale_string (item));
2140     }
2141 
2142     if (!scm_is_list (value) || !scm_is_null (value))
2143     {
2144         gnc_free_list_option_value (list);
2145 
2146         return default_value;
2147     }
2148     return list;
2149 }
2150 
2151 /********************************************************************\
2152  * gnc_option_db_lookup_currency_option                             *
2153  *   looks up a currency option. If present, returns its value as a *
2154  *   gnc_commodity object.                                          *
2155  *                                                                  *
2156  * Args: odb       - option database to search in                   *
2157  *       section   - section name of option                         *
2158  *       name      - name of option                                 *
2159  *       default_value - default value to return if problem         *
2160  * Return: commodity or NULL if no commodity found                  *
2161 \********************************************************************/
2162 gnc_commodity *
gnc_option_db_lookup_currency_option(GNCOptionDB * odb,const char * section,const char * name,gnc_commodity * default_value)2163 gnc_option_db_lookup_currency_option (GNCOptionDB *odb,
2164                                       const char *section,
2165                                       const char *name,
2166                                       gnc_commodity *default_value)
2167 {
2168     GNCOption *option;
2169     SCM getter;
2170     SCM value;
2171 
2172     option = gnc_option_db_get_option_by_name (odb, section, name);
2173     if (option == NULL)
2174         return default_value;
2175 
2176     getter = gnc_option_getter (option);
2177     if (getter == SCM_UNDEFINED)
2178         return default_value;
2179 
2180     value = scm_call_0 (getter);
2181 
2182     return gnc_scm_to_commodity (value);
2183 }
2184 
2185 static void
free_helper(gpointer string,gpointer not_used)2186 free_helper (gpointer string, gpointer not_used)
2187 {
2188     if (string)
2189         free (string);
2190 }
2191 
2192 void
gnc_free_list_option_value(GSList * list)2193 gnc_free_list_option_value (GSList *list)
2194 {
2195     g_slist_foreach (list, free_helper, NULL);
2196     g_slist_free (list);
2197 }
2198 
2199 /********************************************************************\
2200  * gnc_option_db_set_option_default                                 *
2201  *   set the option to its default value                            *
2202  *                                                                  *
2203  * Args: odb     - option database to search in                     *
2204  *       section - section name of option                           *
2205  *       name    - name of option                                   *
2206  * Returns: nothing                                                 *
2207 \********************************************************************/
2208 void
gnc_option_db_set_option_default(GNCOptionDB * odb,const char * section,const char * name)2209 gnc_option_db_set_option_default (GNCOptionDB *odb,
2210                                   const char *section,
2211                                   const char *name)
2212 {
2213     GNCOption *option;
2214 
2215     option = gnc_option_db_get_option_by_name (odb, section, name);
2216 
2217     gnc_option_set_default (option);
2218 }
2219 
2220 /********************************************************************\
2221  * gnc_option_db_set_option                                         *
2222  *   sets the option to the given value. If successful              *
2223  *   returns TRUE, otherwise FALSE.                                 *
2224  *                                                                  *
2225  * Args: odb       - option database to search in                   *
2226  *       section   - section name of option                         *
2227  *       name      - name of option                                 *
2228  *       value     - value to set to                                *
2229  * Return: success indicator                                        *
2230 \********************************************************************/
2231 gboolean
gnc_option_db_set_option(GNCOptionDB * odb,const char * section,const char * name,SCM value)2232 gnc_option_db_set_option (GNCOptionDB *odb,
2233                           const char *section,
2234                           const char *name,
2235                           SCM value)
2236 {
2237     GNCOption *option;
2238     SCM setter;
2239 
2240     option = gnc_option_db_get_option_by_name (odb, section, name);
2241     if (option == NULL)
2242         return FALSE;
2243 
2244     value = gnc_option_valid_value (option, value);
2245     if (value == SCM_UNDEFINED)
2246         return FALSE;
2247 
2248     setter = gnc_option_setter (option);
2249     if (setter == SCM_UNDEFINED)
2250         return FALSE;
2251 
2252     scm_call_1 (setter, value);
2253 
2254     return TRUE;
2255 }
2256 
2257 /********************************************************************\
2258  * gnc_option_db_set_number_option                                  *
2259  *   sets the number option to the given value. If successful       *
2260  *   returns TRUE, otherwise FALSE.                                 *
2261  *                                                                  *
2262  * Args: odb       - option database to search in                   *
2263  *       section   - section name of option                         *
2264  *       name      - name of option                                 *
2265  *       value     - value to set to                                *
2266  * Return: success indicator                                        *
2267 \********************************************************************/
2268 gboolean
gnc_option_db_set_number_option(GNCOptionDB * odb,const char * section,const char * name,gdouble value)2269 gnc_option_db_set_number_option (GNCOptionDB *odb,
2270                                  const char *section,
2271                                  const char *name,
2272                                  gdouble value)
2273 {
2274     GNCOption *option;
2275     SCM scm_value;
2276     SCM setter;
2277 
2278     option = gnc_option_db_get_option_by_name (odb, section, name);
2279     if (option == NULL)
2280         return FALSE;
2281 
2282     scm_value = scm_from_double (value);
2283 
2284     scm_value = gnc_option_valid_value (option, scm_value);
2285     if (scm_value == SCM_UNDEFINED)
2286         return FALSE;
2287 
2288     setter = gnc_option_setter (option);
2289     if (setter == SCM_UNDEFINED)
2290         return FALSE;
2291 
2292     scm_call_1 (setter, scm_value);
2293 
2294     return TRUE;
2295 }
2296 
2297 /********************************************************************\
2298  * gnc_option_db_set_boolean_option                                 *
2299  *   sets the boolean option to the given value. If successful      *
2300  *   returns TRUE, otherwise FALSE.                                 *
2301  *                                                                  *
2302  * Args: odb       - option database to search in                   *
2303  *       section   - section name of option                         *
2304  *       name      - name of option                                 *
2305  *       value     - value to set to                                *
2306  * Return: success indicator                                        *
2307 \********************************************************************/
2308 gboolean
gnc_option_db_set_boolean_option(GNCOptionDB * odb,const char * section,const char * name,gboolean value)2309 gnc_option_db_set_boolean_option (GNCOptionDB *odb,
2310                                   const char *section,
2311                                   const char *name,
2312                                   gboolean value)
2313 {
2314     GNCOption *option;
2315     SCM scm_value;
2316     SCM setter;
2317 
2318     option = gnc_option_db_get_option_by_name (odb, section, name);
2319     if (option == NULL)
2320         return FALSE;
2321 
2322     scm_value = SCM_BOOL(value);
2323 
2324     scm_value = gnc_option_valid_value (option, scm_value);
2325     if (scm_value == SCM_UNDEFINED)
2326         return FALSE;
2327 
2328     setter = gnc_option_setter (option);
2329     if (setter == SCM_UNDEFINED)
2330         return FALSE;
2331 
2332     scm_call_1 (setter, scm_value);
2333 
2334     return TRUE;
2335 }
2336 
2337 /********************************************************************\
2338  * gnc_option_db_set_string_option                                  *
2339  *   sets the string option to the given value. If successful       *
2340  *   returns TRUE, otherwise FALSE.                                 *
2341  *                                                                  *
2342  * Args: odb       - option database to search in                   *
2343  *       section   - section name of option                         *
2344  *       name      - name of option                                 *
2345  *       value     - value to set to                                *
2346  * Return: success indicator                                        *
2347 \********************************************************************/
2348 gboolean
gnc_option_db_set_string_option(GNCOptionDB * odb,const char * section,const char * name,const char * value)2349 gnc_option_db_set_string_option (GNCOptionDB *odb,
2350                                  const char *section,
2351                                  const char *name,
2352                                  const char *value)
2353 {
2354     GNCOption *option;
2355     SCM scm_value;
2356     SCM setter;
2357 
2358     option = gnc_option_db_get_option_by_name (odb, section, name);
2359     if (option == NULL)
2360         return FALSE;
2361 
2362     if (value)
2363         scm_value = scm_from_utf8_string (value);
2364     else
2365         scm_value = SCM_BOOL_F;
2366 
2367     scm_value = gnc_option_valid_value (option, scm_value);
2368     if (scm_value == SCM_UNDEFINED)
2369         return FALSE;
2370 
2371     setter = gnc_option_setter (option);
2372     if (setter == SCM_UNDEFINED)
2373         return FALSE;
2374 
2375     scm_call_1 (setter, scm_value);
2376 
2377     return TRUE;
2378 }
2379 
2380 /*******************************************************************\
2381  * gnc_option_date_option_get_subtype                              *
2382  *   find out whether a date option is a relative or absolute date *
2383  *                                                                 *
2384  * Args: option - option to get date subtype for                   *
2385  * Return: newly allocated subtype string or NULL                  *
2386 \*******************************************************************/
2387 char *
gnc_option_date_option_get_subtype(GNCOption * option)2388 gnc_option_date_option_get_subtype (GNCOption *option)
2389 {
2390     initialize_getters ();
2391 
2392     return gnc_scm_call_1_symbol_to_string (getters.date_option_subtype, option->guile_option);
2393 }
2394 
2395 /*******************************************************************\
2396  * gnc_date_option_value_get_type                                  *
2397  *   get the type of a date option value                           *
2398  *                                                                 *
2399  * Args: option_value - option value to get type of                *
2400  * Return: newly allocated type string or NULL                     *
2401 \*******************************************************************/
2402 char *
gnc_date_option_value_get_type(SCM option_value)2403 gnc_date_option_value_get_type (SCM option_value)
2404 {
2405     initialize_getters ();
2406 
2407     return gnc_scm_call_1_symbol_to_string (getters.date_option_value_type, option_value);
2408 }
2409 
2410 /*******************************************************************\
2411  * gnc_date_option_value_get_absolute                              *
2412  *   get the absolute time of a date option value                  *
2413  *                                                                 *
2414  * Args: option_value - option value to get absolute time of       *
2415  * Return: time64 value                                            *
2416 \*******************************************************************/
2417 time64
gnc_date_option_value_get_absolute(SCM option_value)2418 gnc_date_option_value_get_absolute (SCM option_value)
2419 {
2420     SCM value;
2421     initialize_getters ();
2422     value = scm_call_1 (getters.date_option_value_absolute, option_value);
2423     return scm_to_int64 (value);
2424 }
2425 
2426 /*******************************************************************\
2427  * gnc_date_option_value_get_relative                              *
2428  *   get the relative time of a date option value                  *
2429  *                                                                 *
2430  * Args: option_value - option value to get relative time of       *
2431  * Return: SCM value                                               *
2432 \*******************************************************************/
2433 SCM
gnc_date_option_value_get_relative(SCM option_value)2434 gnc_date_option_value_get_relative (SCM option_value)
2435 {
2436     initialize_getters ();
2437 
2438     return scm_call_1 (getters.date_option_value_relative, option_value);
2439 }
2440 
2441 /*******************************************************************\
2442  * gnc_plot_size_option_value_get_type                             *
2443  *   get the type of a plot size option value                      *
2444  *                                                                 *
2445  * Args: option_value - option value to get type of                *
2446  * Return: newly allocated type string or NULL                     *
2447 \*******************************************************************/
2448 char *
gnc_plot_size_option_value_get_type(SCM option_value)2449 gnc_plot_size_option_value_get_type (SCM option_value)
2450 {
2451     initialize_getters ();
2452 
2453     return gnc_scm_call_1_symbol_to_string (getters.plot_size_option_value_type, option_value);
2454 }
2455 
2456 /*******************************************************************\
2457  * gnc_plot_size_option_value_get_value                            *
2458  *   get the plot size option value                                *
2459  *                                                                 *
2460  * Args: option_value - option value to get the plot size of       *
2461  * Return: double value                                            *
2462 \*******************************************************************/
2463 gdouble
gnc_plot_size_option_value_get_value(SCM option_value)2464 gnc_plot_size_option_value_get_value (SCM option_value)
2465 {
2466     SCM value;
2467 
2468     initialize_getters ();
2469 
2470     value = scm_call_1 (getters.plot_size_option_value, option_value);
2471 
2472     if (scm_is_number (value))
2473         return scm_to_double (value);
2474     else
2475         return 1.0;
2476 }
2477 
2478 /********************************************************************\
2479  * gnc_currency_accounting_option_currency_documentation            *
2480  *   returns the malloc'ed documentation string for currency        *
2481  *   selector of the currency-accounting option, or NULL if it      *
2482  *   can't be retrieved.                                            *
2483  *                                                                  *
2484  * Args: option - the GNCOption                                     *
2485  * Returns: malloc'ed char * or NULL                                *
2486 \********************************************************************/
2487 char *
gnc_currency_accounting_option_currency_documentation(GNCOption * option)2488 gnc_currency_accounting_option_currency_documentation (GNCOption *option)
2489 {
2490     initialize_getters ();
2491 
2492     return gnc_scm_call_1_to_string
2493               (getters.currency_accounting_option_currency_doc_string,
2494                                      option->guile_option);
2495 }
2496 
2497 /********************************************************************\
2498  * gnc_currency_accounting_option_get_default_currency              *
2499  *   returns the SCM value for the currency-accounting option       *
2500  *   default currency.                                              *
2501  *                                                                  *
2502  * Args: option - the GNCOption                                     *
2503  * Returns: SCM value                                               *
2504 \********************************************************************/
2505 SCM
gnc_currency_accounting_option_get_default_currency(GNCOption * option)2506 gnc_currency_accounting_option_get_default_currency (GNCOption *option)
2507 {
2508     initialize_getters ();
2509 
2510     return scm_call_1
2511               (getters.currency_accounting_option_default_currency,
2512                                         option->guile_option);
2513 }
2514 
2515 /********************************************************************\
2516  * gnc_currency_accounting_option_policy_documentation              *
2517  *   returns the malloc'ed documentation string for policy          *
2518  *   selector of the currency-accounting option, or NULL if it      *
2519  *   can't be retrieved.                                            *
2520  *                                                                  *
2521  * Args: option - the GNCOption                                     *
2522  * Returns: malloc'ed char * or NULL                                *
2523 \********************************************************************/
2524 char *
gnc_currency_accounting_option_policy_documentation(GNCOption * option)2525 gnc_currency_accounting_option_policy_documentation (GNCOption *option)
2526 {
2527     initialize_getters ();
2528 
2529     return gnc_scm_call_1_to_string
2530               (getters.currency_accounting_option_policy_doc_string,
2531                                      option->guile_option);
2532 }
2533 
2534 /********************************************************************\
2535  * gnc_currency_accounting_option_get_default_policy                *
2536  *   returns the SCM value for the currency-accounting option       *
2537  *   default policy.                                                *
2538  *                                                                  *
2539  * Args: option - the GNCOption                                     *
2540  * Returns: SCM value                                               *
2541 \********************************************************************/
2542 SCM
gnc_currency_accounting_option_get_default_policy(GNCOption * option)2543 gnc_currency_accounting_option_get_default_policy (GNCOption *option)
2544 {
2545     initialize_getters ();
2546 
2547     return scm_call_1
2548               (getters.currency_accounting_option_default_policy,
2549                                         option->guile_option);
2550 }
2551 
2552 /********************************************************************\
2553  * gnc_currency_accounting_option_gain_loss_account_documentation   *
2554  *   returns the malloc'ed documentation string for account         *
2555  *   selector of the currency-accounting option, or NULL if it      *
2556  *   can't be retrieved.                                            *
2557  *                                                                  *
2558  * Args: option - the GNCOption                                     *
2559  * Returns: malloc'ed char * or NULL                                *
2560 \********************************************************************/
2561 char *
gnc_currency_accounting_option_gain_loss_account_documentation(GNCOption * option)2562 gnc_currency_accounting_option_gain_loss_account_documentation (GNCOption *option)
2563 {
2564     initialize_getters ();
2565 
2566     return gnc_scm_call_1_to_string
2567               (getters.currency_accounting_option_gain_loss_account_doc_string,
2568                                      option->guile_option);
2569 }
2570 
2571 /*******************************************************************\
2572  * gnc_currency_accounting_option_value_get_method                 *
2573  *   get the currency accounting method of the option as a symbol  *
2574  *                                                                 *
2575  * Args: option_value - option value to get method of              *
2576  * Return: SCM value                                               *
2577 \*******************************************************************/
2578 SCM
gnc_currency_accounting_option_value_get_method(SCM option_value)2579 gnc_currency_accounting_option_value_get_method (SCM option_value)
2580 {
2581     initialize_getters ();
2582 
2583     return scm_call_1 (getters.currency_accounting_option_method,
2584                        option_value);
2585 }
2586 
2587 /*******************************************************************\
2588  * gnc_currency_accounting_option_value_get_book_currency          *
2589  *   get the book-currency if that is the currency accounting      *
2590  *   method of the option as a symbol                              *
2591  *                                                                 *
2592  * Args: option_value - option value to get method of              *
2593  * Return: SCM value                                               *
2594 \*******************************************************************/
2595 SCM
gnc_currency_accounting_option_value_get_book_currency(SCM option_value)2596 gnc_currency_accounting_option_value_get_book_currency (SCM option_value)
2597 {
2598     initialize_getters ();
2599 
2600     return scm_call_1 (getters.currency_accounting_option_book_currency,
2601                        option_value);
2602 }
2603 
2604 /*******************************************************************\
2605  * gnc_currency_accounting_option_value_get_default_policy         *
2606  *   get the default policy if book-currency is the currency       *
2607  *   accounting  method of the option as a symbol                  *
2608  *                                                                 *
2609  * Args: option_value - option value to get method of              *
2610  * Return: SCM value                                               *
2611 \*******************************************************************/
2612 SCM
gnc_currency_accounting_option_value_get_default_policy(SCM option_value)2613 gnc_currency_accounting_option_value_get_default_policy (SCM option_value)
2614 {
2615     initialize_getters ();
2616 
2617     return scm_call_1
2618         (getters.currency_accounting_option_selected_default_policy,
2619           option_value);
2620 }
2621 
2622 /*******************************************************************\
2623  * gnc_currency_accounting_option_value_get_default_account        *
2624  *   get the default gain/loss account if book-currency is the     *
2625  *   currency accounting method, if one is specified, of the       *
2626  *   option as a symbol                                            *
2627  *                                                                 *
2628  * Args: option_value - option value to get method of              *
2629  * Return: SCM value                                               *
2630 \*******************************************************************/
2631 SCM
gnc_currency_accounting_option_value_get_default_account(SCM option_value)2632 gnc_currency_accounting_option_value_get_default_account (SCM option_value)
2633 {
2634     initialize_getters ();
2635 
2636     return scm_call_1
2637         (getters.currency_accounting_option_selected_default_gain_loss_account,
2638           option_value);
2639 }
2640 
2641 static int
find_option_db_with_selectable_pred(gpointer key,gpointer value,gpointer data)2642 find_option_db_with_selectable_pred (gpointer key, gpointer value, gpointer data)
2643 {
2644     SCM guile_options = data;
2645     GNCOptionDB *odb = value;
2646 
2647     if (odb && (odb->guile_options == guile_options) && odb->set_selectable)
2648         return TRUE;
2649 
2650     return FALSE;
2651 }
2652 
2653 static GNCOptionDB *
find_option_db_with_selectable(SCM guile_options)2654 find_option_db_with_selectable (SCM guile_options)
2655 {
2656     return g_hash_table_find (option_dbs, find_option_db_with_selectable_pred,
2657                               guile_options);
2658 }
2659 
2660 /*******************************************************************\
2661  * gnc_option_db_set_option_selectable_by_name                     *
2662  *   set the sensitivity of the option widget                      *
2663  *                                                                 *
2664  * Args: guile_options - guile side option db                      *
2665  *       section       - section of option                         *
2666  *       name          - name of option                            *
2667  *       selectable    - selectable status                         *
2668  * Return: SCM value                                               *
2669 \*******************************************************************/
2670 void
gnc_option_db_set_option_selectable_by_name(SCM guile_options,const char * section,const char * name,gboolean selectable)2671 gnc_option_db_set_option_selectable_by_name (SCM guile_options,
2672                                              const char *section,
2673                                              const char *name,
2674                                              gboolean selectable)
2675 {
2676     GNCOptionDB *odb;
2677     GNCOption *option;
2678 
2679     odb = find_option_db_with_selectable (guile_options);
2680     if (!odb)
2681         return;
2682 
2683     option = gnc_option_db_get_option_by_name (odb, section, name);
2684     if (!option)
2685         return;
2686 
2687     gnc_option_set_selectable (option, selectable);
2688 }
2689 
2690 /* the value is a list of:
2691  * format(symbol), month(symbol), include-years(bool), custom-string(string)
2692  */
2693 
gnc_dateformat_option_value_parse(SCM value,QofDateFormat * format,GNCDateMonthFormat * months,gboolean * years,char ** custom)2694 gboolean gnc_dateformat_option_value_parse (SCM value,
2695                                             QofDateFormat *format,
2696                                             GNCDateMonthFormat *months,
2697                                             gboolean *years,
2698                                             char **custom)
2699 {
2700     SCM val;
2701     gchar *str;
2702 
2703     if (!scm_is_list (value) || scm_is_null (value))
2704         return TRUE;
2705 
2706     do
2707     {
2708         /* Parse the format */
2709         val = SCM_CAR(value);
2710         value = SCM_CDR(value);
2711         if (!scm_is_symbol (val))
2712             break;
2713         str = gnc_scm_symbol_to_locale_string (val);
2714         if (!str)
2715             break;
2716 
2717         if (format)
2718         {
2719             if (gnc_date_string_to_dateformat (str, format))
2720             {
2721                 g_free (str);
2722                 break;
2723             }
2724         }
2725         g_free (str);
2726 
2727         /* parse the months */
2728         val = SCM_CAR(value);
2729         value = SCM_CDR(value);
2730         if (!scm_is_symbol (val))
2731             break;
2732         str = gnc_scm_symbol_to_locale_string (val);
2733         if (!str)
2734             break;
2735 
2736         if (months)
2737         {
2738             if (gnc_date_string_to_monthformat (str, months))
2739             {
2740                 g_free (str);
2741                 break;
2742             }
2743         }
2744         g_free (str);
2745 
2746         /* parse the years */
2747         val = SCM_CAR(value);
2748         value = SCM_CDR(value);
2749         if (!scm_is_bool (val))
2750             break;
2751 
2752         if (years)
2753             *years = scm_is_true (val);
2754 
2755         /* parse the custom */
2756         val = SCM_CAR(value);
2757         value = SCM_CDR(value);
2758         if (!scm_is_string (val))
2759             break;
2760         if (!scm_is_null (value))
2761             break;
2762 
2763         if (custom)
2764             *custom = gnc_scm_to_utf8_string (val);
2765 
2766         return FALSE;
2767     }
2768     while (FALSE);
2769 
2770     return TRUE;
2771 }
2772 
gnc_dateformat_option_set_value(QofDateFormat format,GNCDateMonthFormat months,gboolean years,const char * custom)2773 SCM gnc_dateformat_option_set_value (QofDateFormat format,
2774                                      GNCDateMonthFormat months,
2775                                      gboolean years,
2776                                      const char *custom)
2777 {
2778     SCM value = SCM_EOL;
2779     SCM val;
2780     const char *str;
2781 
2782     /* build the list in reverse order */
2783     if (custom)
2784         val = scm_from_utf8_string (custom);
2785     else
2786         val = SCM_BOOL_F;
2787     value = scm_cons (val, value);
2788 
2789     val = SCM_BOOL(years);
2790     value = scm_cons (val, value);
2791 
2792     str = gnc_date_monthformat_to_string (months);
2793     if (str)
2794         val = scm_from_locale_symbol (str);
2795     else
2796         val = SCM_BOOL_F;
2797     value = scm_cons (val, value);
2798 
2799     str = gnc_date_dateformat_to_string (format);
2800     if (str)
2801         val = scm_from_locale_symbol (str);
2802     else
2803         val = SCM_BOOL_F;
2804     value = scm_cons (val, value);
2805 
2806     return value;
2807 }
2808 
2809 /*
2810  * the generator should be a procedure that takes one argument,
2811  * an options object.  The procedure should fill in the options with
2812  * its defined kvp options.
2813  */
2814 void
gnc_register_kvp_option_generator(QofIdType id_type,SCM generator)2815 gnc_register_kvp_option_generator (QofIdType id_type, SCM generator)
2816 {
2817     GList *list;
2818     init_table();
2819     list = g_hash_table_lookup (kvp_registry, id_type);
2820     list = g_list_prepend (list, generator);
2821     g_hash_table_insert (kvp_registry, (gpointer) id_type, list);
2822     scm_gc_protect_object (generator);
2823 }
2824