GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-ui-util.c
1 /********************************************************************\
2  * gnc-ui-util.c -- utility functions for the GnuCash UI *
3  * Copyright (C) 2000 Dave Peticolas <[email protected]> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA [email protected] *
21 \********************************************************************/
22 
23 #include "config.h"
24 
25 #include "gnc-ui-util.h"
26 
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <gio/gio.h>
30 #include <libguile.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <locale.h>
35 #include <math.h>
36 #if defined(G_OS_WIN32) && !defined(_MSC_VER)
37 # include <pow.h>
38 #endif
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 
44 
45 #include "qof.h"
46 #include "guile-mappings.h"
47 #include "gnc-prefs.h"
48 #include "gnc-module/gnc-module.h"
49 #include "engine/Account.h"
50 #include "engine/Transaction.h"
51 #include "engine/gnc-engine.h"
52 #include "app-utils/gnc-euro.h"
53 #include "engine/gnc-hooks.h"
54 #include "engine/gnc-session.h"
55 #include "engine-helpers.h"
56 #include "gnc-locale-utils.h"
57 #include "gnc-component-manager.h"
58 #include "gnc-features.h"
59 #include "gnc-guile-utils.h"
60 
61 #define GNC_PREF_CURRENCY_CHOICE_LOCALE "currency-choice-locale"
62 #define GNC_PREF_CURRENCY_CHOICE_OTHER "currency-choice-other"
63 #define GNC_PREF_CURRENCY_OTHER "currency-other"
64 #define GNC_PREF_REVERSED_ACCTS_NONE "reversed-accounts-none"
65 #define GNC_PREF_REVERSED_ACCTS_CREDIT "reversed-accounts-credit"
66 #define GNC_PREF_REVERSED_ACCTS_INC_EXP "reversed-accounts-incomeexpense"
67 
68 static QofLogModule log_module = GNC_MOD_GUI;
69 
70 static gboolean auto_decimal_enabled = FALSE;
71 static int auto_decimal_places = 2; /* default, can be changed */
72 
73 static gboolean reverse_balance_inited = FALSE;
74 static gboolean reverse_type[NUM_ACCOUNT_TYPES];
75 
76 /* Cache currency ISO codes and only look them up in the settings when
77  * absolutely necessary. Can't cache a pointer to the data structure
78  * as that will change any time the book changes. */
79 static gchar *user_default_currency = NULL;
80 static gchar *user_report_currency = NULL;
81 
82 gchar *gnc_normalize_account_separator (const gchar* separator)
83 {
84  gchar *new_sep=NULL;
85 
86  if (!separator || !*separator || g_strcmp0(separator, "colon") == 0)
87  new_sep = g_strdup (":");
88  else if (g_strcmp0(separator, "slash") == 0)
89  new_sep = g_strdup ("/");
90  else if (g_strcmp0(separator, "backslash") == 0)
91  new_sep = g_strdup ("\\");
92  else if (g_strcmp0(separator, "dash") == 0)
93  new_sep = g_strdup ("-");
94  else if (g_strcmp0(separator, "period") == 0)
95  new_sep = g_strdup (".");
96  else
97  new_sep = g_strdup (separator);
98 
99  return new_sep;
100 }
101 /********************************************************************\
102  * gnc_configure_account_separator *
103  * updates the current account separator character *
104  * *
105  * Args: none *
106  \*******************************************************************/
107 static void
108 gnc_configure_account_separator (void)
109 {
110  gchar *separator;
111  char *string;
112 
113  string = gnc_prefs_get_string(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNT_SEPARATOR);
114  separator = gnc_normalize_account_separator (string);
115 
116  gnc_set_account_separator(separator);
117 
118  g_free(string);
119  g_free(separator);
120 }
121 
122 
123 static void
124 gnc_configure_reverse_balance (void)
125 {
126  gint i;
127 
128  for (i = 0; i < NUM_ACCOUNT_TYPES; i++)
129  reverse_type[i] = FALSE;
130 
131  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_INC_EXP))
132  {
133  reverse_type[ACCT_TYPE_INCOME] = TRUE;
134  reverse_type[ACCT_TYPE_EXPENSE] = TRUE;
135  }
136  else if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_CREDIT))
137  {
138  reverse_type[ACCT_TYPE_LIABILITY] = TRUE;
139  reverse_type[ACCT_TYPE_PAYABLE] = TRUE;
140  reverse_type[ACCT_TYPE_EQUITY] = TRUE;
141  reverse_type[ACCT_TYPE_INCOME] = TRUE;
142  reverse_type[ACCT_TYPE_CREDIT] = TRUE;
143  }
144  else if (!gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_NONE))
145  PWARN("no reversed account preference set, using none");
146 
147 }
148 
149 static void
150 gnc_reverse_balance_init (void)
151 {
152  gnc_configure_reverse_balance ();
153  reverse_balance_inited = TRUE;
154 }
155 
156 gboolean
157 gnc_reverse_balance (const Account *account)
158 {
159  int type;
160 
161  if (account == NULL)
162  return FALSE;
163 
164  type = xaccAccountGetType (account);
165  if ((type < 0) || (type >= NUM_ACCOUNT_TYPES))
166  return FALSE;
167 
168  if (!reverse_balance_inited)
169  gnc_reverse_balance_init ();
170 
171  return reverse_type[type];
172 }
173 
174 
175 gchar *
176 gnc_get_default_directory (const gchar *section)
177 {
178  gchar *dir;
179 
180  dir = gnc_prefs_get_string (section, GNC_PREF_LAST_PATH);
181  if (!dir)
182 #ifdef G_OS_WIN32
183  dir = g_strdup (g_get_user_data_dir ()); /* equivalent of "My Documents" */
184 #else
185  dir = g_strdup (g_get_home_dir ());
186 #endif
187 
188  return dir;
189 }
190 
191 void
192 gnc_set_default_directory (const gchar *section, const gchar *directory)
193 {
194  gnc_prefs_set_string(section, GNC_PREF_LAST_PATH, directory);
195 }
196 
197 QofBook *
198 gnc_get_current_book (void)
199 {
200  return qof_session_get_book (gnc_get_current_session ());
201 }
202 
203 /* If there is no current session, there is no book and we must be dealing
204  * with a new book. When gnucash is started with --nofile, there is
205  * initially no session (and no book), but by the time we check, one
206  * could have been created (for example, if an empty account tree tab is
207  * opened, a session is created which creates a new, but empty, book).
208  * A session is created and a book is loaded from a backend when gnucash is
209  * started with a file, but selecting 'new file' keeps a session open. So we
210  * need to check as well for a book with no accounts (root with no children). */
211 gboolean
212 gnc_is_new_book (void)
213 {
214  return ((!gnc_current_session_exist() ||
215  (gnc_current_session_exist() &&
217  gnc_book_get_root_account(
218  gnc_get_current_book()))))
219  ? TRUE : FALSE);
220 }
221 
222 #define OPTION_TAXUS_NAME "book/tax_US/name"
223 #define OPTION_TAXUS_TYPE "book/tax_US/type"
224 
225 void
226 gnc_set_current_book_tax_name (const gchar *tax_name)
227 {
228  qof_book_set_string_option(gnc_get_current_book(), OPTION_TAXUS_NAME, tax_name);
229 }
230 
231 const gchar *
232 gnc_get_current_book_tax_name (void)
233 {
234  return qof_book_get_string_option(gnc_get_current_book(), OPTION_TAXUS_NAME);
235 }
236 
237 void
238 gnc_set_current_book_tax_type (const gchar *tax_type)
239 {
240  qof_book_set_string_option(gnc_get_current_book(), OPTION_TAXUS_TYPE, tax_type);
241 }
242 
243 const gchar *
244 gnc_get_current_book_tax_type (void)
245 {
246  return qof_book_get_string_option(gnc_get_current_book(), OPTION_TAXUS_TYPE);
247 }
248 
252 void
254 {
255  gnc_suspend_gui_refresh ();
256  if (num_action)
257  {
258  /* Set a feature flag in the book for use of the split action field as number.
259  * This will prevent older GnuCash versions that don't support this feature
260  * from opening this file. */
261  gnc_features_set_used (gnc_get_current_book(),
262  GNC_FEATURE_NUM_FIELD_SOURCE);
263  }
264  gnc_book_option_num_field_source_change (num_action);
265  gnc_resume_gui_refresh ();
266  gnc_gui_refresh_all ();
267 }
268 
269 Account *
270 gnc_get_current_root_account (void)
271 {
272  return gnc_book_get_root_account (gnc_get_current_book ());
273 }
274 
276 gnc_get_current_commodities (void)
277 {
278  return gnc_commodity_table_get_table (gnc_get_current_book ());
279 }
280 
281 gchar *
283 {
284  gboolean show_leaf_accounts;
285  show_leaf_accounts = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
286  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
287 
288  if (show_leaf_accounts)
289  return g_strdup (xaccAccountGetName (account));
290  else
291  return gnc_account_get_full_name (account);
292 }
293 
294 Account *
295 gnc_account_lookup_for_register(const Account *base_account, const char *name)
296 {
297  gboolean show_leaf_accounts;
298  show_leaf_accounts = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER,
299  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
300 
301  if (show_leaf_accounts)
302  return gnc_account_lookup_by_name (base_account, name);
303  else
304  return gnc_account_lookup_by_full_name (base_account, name);
305 }
306 
307 
308 /* Caller is responsible for g_free'ing returned memory */
309 char *
310 gnc_ui_account_get_tax_info_string (const Account *account)
311 {
312  static SCM get_form = SCM_UNDEFINED;
313  static SCM get_desc = SCM_UNDEFINED;
314 
315  gboolean tax_related = FALSE;
316  const char *code;
317 
318  if (!account)
319  return NULL;
320 
321  tax_related = xaccAccountGetTaxRelated (account);
322  code = xaccAccountGetTaxUSCode (account);
323 
324  if (!code)
325  {
326  if (!tax_related)
327  return NULL;
328  /* tax_related && !code */
329  else
330  /* Translators: This and the following strings appear on
331  * the account tab if the Tax Info column is displayed,
332  * i.e. if the user wants to record the tax form number
333  * and location on that tax form which corresponds to this
334  * gnucash account. For the US Income Tax support in
335  * gnucash, each tax code that can be assigned to an
336  * account generally corresponds to a specific line number
337  * on a paper form and each form has a unique
338  * identification (e.g., Form 1040, Schedule A). */
339  return g_strdup (_("Tax-related but has no tax code"));
340  }
341  else /* with tax code */
342  {
343  const gchar *tax_type;
344  GNCAccountType atype;
345  SCM tax_entity_type;
346  SCM category;
347  gchar *num_code = NULL;
348  const gchar *prefix = "N";
349  gchar *return_string = NULL;
350 
351  tax_type = gnc_get_current_book_tax_type ();
352  if (tax_type == NULL || (g_strcmp0 (tax_type, "") == 0))
353  return g_strdup (_("Tax entity type not specified"));
354 
355  atype = xaccAccountGetType (account);
356  tax_entity_type = scm_from_utf8_string (tax_type);
357 
358  if (get_form == SCM_UNDEFINED)
359  {
360  GNCModule module;
361  const gchar *tax_module;
362  /* load the tax info */
363 #ifdef LOCALE_SPECIFIC_TAX
364  /* This is a very simple hack that loads the (new, special) German
365  tax definition file in a German locale, or (default) loads the
366  previous US tax file. */
367 # ifdef G_OS_WIN32
368  gchar *thislocale = g_win32_getlocale();
369  gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
370  g_free(thislocale);
371 # else /* !G_OS_WIN32 */
372  const char *thislocale = setlocale(LC_ALL, NULL);
373  gboolean is_de_DE = (strncmp(thislocale, "de_DE", 5) == 0);
374 # endif /* G_OS_WIN32 */
375 #else /* LOCALE_SPECIFIC_TAX */
376  gboolean is_de_DE = FALSE;
377 #endif /* LOCALE_SPECIFIC_TAX */
378  tax_module = is_de_DE ?
379  "gnucash/tax/de_DE" :
380  "gnucash/tax/us";
381 
382  module = gnc_module_load ((char *)tax_module, 0);
383 
384  g_return_val_if_fail (module, NULL);
385 
386  get_form = scm_c_eval_string
387  ("(false-if-exception gnc:txf-get-form)");
388  get_desc = scm_c_eval_string
389  ("(false-if-exception gnc:txf-get-description)");
390  }
391 
392  g_return_val_if_fail (scm_is_procedure (get_form), NULL);
393  g_return_val_if_fail (scm_is_procedure (get_desc), NULL);
394 
395  category = scm_c_eval_string (atype == ACCT_TYPE_INCOME ?
396  "txf-income-categories" :
397  (atype == ACCT_TYPE_EXPENSE ?
398  "txf-expense-categories" :
399  (((atype == ACCT_TYPE_BANK) ||
400  (atype == ACCT_TYPE_CASH) ||
401  (atype == ACCT_TYPE_ASSET) ||
402  (atype == ACCT_TYPE_STOCK) ||
403  (atype == ACCT_TYPE_MUTUAL) ||
404  (atype == ACCT_TYPE_RECEIVABLE)) ?
405  "txf-asset-categories" :
406  (((atype == ACCT_TYPE_CREDIT) ||
407  (atype == ACCT_TYPE_LIABILITY) ||
408  (atype == ACCT_TYPE_EQUITY) ||
409  (atype == ACCT_TYPE_PAYABLE)) ?
410  "txf-liab-eq-categories" : ""))));
411 
412  if (g_str_has_prefix (code, prefix))
413  {
414  const gchar *num_code_tmp;
415  num_code_tmp = g_strdup (code);
416  num_code_tmp++; /* to lose the leading N */
417  num_code = g_strdup (num_code_tmp);
418  num_code_tmp--;
419  g_free ((gpointer *) num_code_tmp);
420  }
421  else
422  {
423  num_code = g_strdup (code);
424  }
425 
426  if (category == SCM_UNDEFINED)
427  {
428  if (tax_related)
429  return_string = g_strdup_printf
430  (_("Tax type %s: invalid code %s for account type"),
431  tax_type, num_code);
432  else
433  return_string = g_strdup_printf
434  (_("Not tax-related; tax type %s: invalid code %s for account type"),
435  tax_type, num_code);
436  }
437  else
438  {
439  SCM code_scm;
440  SCM form_scm;
441  code_scm = scm_from_locale_symbol (code);
442  form_scm = scm_call_3 (get_form, category, code_scm, tax_entity_type);
443  if (!scm_is_string (form_scm))
444  {
445  if (tax_related)
446  return_string = g_strdup_printf
447  (_("Invalid code %s for tax type %s"),
448  num_code, tax_type);
449  else
450  return_string = g_strdup_printf
451  (_("Not tax-related; invalid code %s for tax type %s"),
452  num_code, tax_type);
453  }
454  else
455  {
456  gchar *form = NULL;
457 
458  /* Note: using scm_to_utf8_string directly here instead
459  of our wrapper gnc_scm_to_utf8_string. 'form' should
460  be freed with 'free' instead of 'g_free'. This will
461  be taken care of automatically during scm_dynwind_end,
462  because we inform guile of this memory allocation via
463  scm_dynwind_free a little further. */
464  form = scm_to_utf8_string (form_scm);
465  if (!form)
466  {
467  if (tax_related)
468  return_string = g_strdup_printf
469  (_("No form: code %s, tax type %s"), num_code,
470  tax_type);
471  else
472  return_string = g_strdup_printf
473  (_("Not tax-related; no form: code %s, tax type %s"),
474  num_code, tax_type);
475  }
476  else
477  {
478  SCM desc_scm;
479 
480  /* Create a dynwind context because we will be calling (scm) functions
481  that potentially exit non-locally */
482  scm_dynwind_begin (0);
483  scm_dynwind_free (form);
484  desc_scm = scm_call_3 (get_desc, category, code_scm,
485  tax_entity_type);
486  if (!scm_is_string (desc_scm))
487  {
488  if (tax_related)
489  return_string = g_strdup_printf
490  (_("No description: form %s, code %s, tax type %s"),
491  form, num_code, tax_type);
492  else
493  return_string = g_strdup_printf
494  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
495  form, num_code, tax_type);
496  }
497  else
498  {
499  gchar *desc = NULL;
500  desc = gnc_scm_to_utf8_string (desc_scm);
501  if (!desc)
502  {
503  if (tax_related)
504  return_string = g_strdup_printf
505  (_("No description: form %s, code %s, tax type %s"),
506  form, num_code, tax_type);
507  else
508  return_string = g_strdup_printf
509  (_("Not tax-related; no description: form %s, code %s, tax type %s"),
510  form, num_code, tax_type);
511  }
512  else
513  {
514  gint64 copy_number;
515  gchar *copy_txt = NULL;
516  copy_number = xaccAccountGetTaxUSCopyNumber (account);
517  copy_txt = (copy_number == 1) ?
518  g_strdup ("") :
519  g_strdup_printf ("(%d)",
520  (gint) copy_number);
521  if (tax_related)
522  {
523  if (g_strcmp0 (form, "") == 0)
524  return_string = g_strdup_printf ("%s", desc);
525  else
526  return_string = g_strdup_printf ("%s%s: %s",
527  form, copy_txt, desc);
528  }
529  else
530  {
531  return_string = g_strdup_printf
532  (_("Not tax-related; %s%s: %s (code %s, tax type %s)"),
533  form, copy_txt, desc, num_code, tax_type);
534  }
535  g_free (copy_txt);
536  }
537  g_free (desc);
538  }
539  scm_dynwind_end ();
540  }
541  }
542  }
543  g_free (num_code);
544  return return_string;
545  }
546 }
547 
548 /* Caller is responsible for g_free'ing returned memory */
549 char *
550 gnc_ui_account_get_tax_info_sub_acct_string (const Account *account)
551 {
552  GList *descendant, *account_descendants;
553 
554  if (!account)
555  return NULL;
556 
557  account_descendants = gnc_account_get_descendants (account);
558  if (account_descendants)
559  {
560  gint sub_acct_tax_number = 0;
561  for (descendant = account_descendants; descendant;
562  descendant = g_list_next(descendant))
563  {
564  if (xaccAccountGetTaxRelated (descendant->data))
565  sub_acct_tax_number++;
566  }
567  g_list_free (account_descendants);
568  g_list_free (descendant);
569  /* Translators: This and the following strings appear on
570  * the account tab if the Tax Info column is displayed,
571  * i.e. if the user wants to record the tax form number
572  * and location on that tax form which corresponds to this
573  * gnucash account. For the US Income Tax support in
574  * gnucash, each tax code that can be assigned to an
575  * account generally corresponds to a specific line number
576  * on a paper form and each form has a unique
577  * identification (e.g., Form 1040, Schedule A). */
578  return (sub_acct_tax_number == 0) ? NULL :
579  g_strdup_printf (_("(Tax-related subaccounts: %d)"),
580  sub_acct_tax_number);
581  }
582  else
583  return NULL;
584 }
585 
586 static const char *
587 string_after_colon (const char *msgstr)
588 {
589  const char *string_at_colon;
590  g_assert(msgstr);
591  string_at_colon = strchr(msgstr, ':');
592  if (string_at_colon)
593  return string_at_colon + 1;
594  else
595  /* No colon found; we assume the translation contains only the
596  part after the colon, similar to the disambiguation prefixes */
597  return msgstr;
598 }
599 
600 /********************************************************************\
601  * gnc_get_reconcile_str *
602  * return the i18n'd string for the given reconciled flag *
603  * *
604  * Args: reconciled_flag - the flag to convert into a string *
605  * Returns: the i18n'd reconciled string *
606 \********************************************************************/
607 const char *
608 gnc_get_reconcile_str (char reconciled_flag)
609 {
610  switch (reconciled_flag)
611  {
612  case NREC:
613  /* Translators: For the following strings, the single letters
614  after the colon are abbreviations of the word before the
615  colon. You should only translate the letter *after* the colon. */
616  return string_after_colon(_("not cleared:n"));
617  case CREC:
618  /* Translators: Please only translate the letter *after* the colon. */
619  return string_after_colon(_("cleared:c"));
620  case YREC:
621  /* Translators: Please only translate the letter *after* the colon. */
622  return string_after_colon(_("reconciled:y"));
623  case FREC:
624  /* Translators: Please only translate the letter *after* the colon. */
625  return string_after_colon(_("frozen:f"));
626  case VREC:
627  /* Translators: Please only translate the letter *after* the colon. */
628  return string_after_colon(_("void:v"));
629  default:
630  PERR("Bad reconciled flag\n");
631  return NULL;
632  }
633 }
634 
635 /********************************************************************\
636  * gnc_get_reconcile_valid_flags *
637  * return a string containing the list of reconciled flags *
638  * *
639  * Returns: the i18n'd reconciled flags string *
640 \********************************************************************/
641 const char *
642 gnc_get_reconcile_valid_flags (void)
643 {
644  static const char flags[] = { NREC, CREC, YREC, FREC, VREC, 0 };
645  return flags;
646 }
647 
648 /********************************************************************\
649  * gnc_get_reconcile_flag_order *
650  * return a string containing the reconciled-flag change order *
651  * *
652  * Args: reconciled_flag - the flag to convert into a string *
653  * Returns: the i18n'd reconciled string *
654 \********************************************************************/
655 const char *
656 gnc_get_reconcile_flag_order (void)
657 {
658  static const char flags[] = { NREC, CREC, 0 };
659  return flags;
660 }
661 
662 
663 static const char *
664 equity_base_name (GNCEquityType equity_type)
665 {
666  switch (equity_type)
667  {
668  case EQUITY_OPENING_BALANCE:
669  return N_("Opening Balances");
670 
671  case EQUITY_RETAINED_EARNINGS:
672  return N_("Retained Earnings");
673 
674  default:
675  return NULL;
676  }
677 }
678 
679 Account *
680 gnc_find_or_create_equity_account (Account *root,
681  GNCEquityType equity_type,
682  gnc_commodity *currency)
683 {
684  Account *parent;
685  Account *account;
686  gboolean name_exists;
687  gboolean base_name_exists;
688  const char *base_name;
689  char *name;
690 
691  g_return_val_if_fail (equity_type >= 0, NULL);
692  g_return_val_if_fail (equity_type < NUM_EQUITY_TYPES, NULL);
693  g_return_val_if_fail (currency != NULL, NULL);
694  g_return_val_if_fail (root != NULL, NULL);
695 
696  base_name = equity_base_name (equity_type);
697 
698  account = gnc_account_lookup_by_name(root, base_name);
699  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
700  account = NULL;
701 
702  if (!account)
703  {
704  base_name = base_name && *base_name ? _(base_name) : "";
705 
706  account = gnc_account_lookup_by_name(root, base_name);
707  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
708  account = NULL;
709  }
710 
711  base_name_exists = (account != NULL);
712 
713  if (account &&
714  gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
715  return account;
716 
717  name = g_strconcat (base_name, " - ",
718  gnc_commodity_get_mnemonic (currency), NULL);
719  account = gnc_account_lookup_by_name(root, name);
720  if (account && xaccAccountGetType (account) != ACCT_TYPE_EQUITY)
721  account = NULL;
722 
723  name_exists = (account != NULL);
724 
725  if (account &&
726  gnc_commodity_equiv (currency, xaccAccountGetCommodity (account)))
727  return account;
728 
729  /* Couldn't find one, so create it */
730  if (name_exists && base_name_exists)
731  {
732  PWARN ("equity account with unexpected currency");
733  g_free (name);
734  return NULL;
735  }
736 
737  if (!base_name_exists &&
739  {
740  g_free (name);
741  name = g_strdup (base_name);
742  }
743 
744  parent = gnc_account_lookup_by_name(root, _("Equity"));
745  if (!parent || xaccAccountGetType (parent) != ACCT_TYPE_EQUITY)
746  parent = root;
747  g_assert(parent);
748 
749  account = xaccMallocAccount (gnc_account_get_book(root));
750 
751  xaccAccountBeginEdit (account);
752 
753  xaccAccountSetName (account, name);
755  xaccAccountSetCommodity (account, currency);
756 
757  xaccAccountBeginEdit (parent);
758  gnc_account_append_child (parent, account);
759  xaccAccountCommitEdit (parent);
760 
761  xaccAccountCommitEdit (account);
762 
763  g_free (name);
764 
765  return account;
766 }
767 
768 gboolean
769 gnc_account_create_opening_balance (Account *account,
770  gnc_numeric balance,
771  time64 date,
772  QofBook *book)
773 {
774  Account *equity_account;
775  Transaction *trans;
776  Split *split;
777 
778  if (gnc_numeric_zero_p (balance))
779  return TRUE;
780 
781  g_return_val_if_fail (account != NULL, FALSE);
782 
783  equity_account =
784  gnc_find_or_create_equity_account (gnc_account_get_root(account),
785  EQUITY_OPENING_BALANCE,
786  xaccAccountGetCommodity (account));
787  if (!equity_account)
788  return FALSE;
789 
790  xaccAccountBeginEdit (account);
791  xaccAccountBeginEdit (equity_account);
792 
793  trans = xaccMallocTransaction (book);
794 
795  xaccTransBeginEdit (trans);
796 
797  xaccTransSetCurrency (trans, gnc_account_or_default_currency (account, NULL));
799  xaccTransSetDescription (trans, _("Opening Balance"));
800 
801  split = xaccMallocSplit (book);
802 
803  xaccTransAppendSplit (trans, split);
804  xaccAccountInsertSplit (account, split);
805 
806  xaccSplitSetAmount (split, balance);
807  xaccSplitSetValue (split, balance);
808 
809  balance = gnc_numeric_neg (balance);
810 
811  split = xaccMallocSplit (book);
812 
813  xaccTransAppendSplit (trans, split);
814  xaccAccountInsertSplit (equity_account, split);
815 
816  xaccSplitSetAmount (split, balance);
817  xaccSplitSetValue (split, balance);
818 
819  xaccTransCommitEdit (trans);
820  xaccAccountCommitEdit (equity_account);
821  xaccAccountCommitEdit (account);
822 
823  return TRUE;
824 }
825 
826 #if 0 /* Not Used */
827 static void
828 gnc_lconv_set_utf8 (char **p_value, char *default_value)
829 {
830  char *value = *p_value;
831  *p_value = NULL;
832 
833  if ((value == NULL) || (value[0] == 0))
834  value = default_value;
835 
836 #ifdef G_OS_WIN32
837  {
838  /* get number of resulting wide characters */
839  size_t count = mbstowcs (NULL, value, 0);
840  if (count > 0)
841  {
842  /* malloc and convert */
843  wchar_t *wvalue = g_malloc ((count + 1) * sizeof(wchar_t));
844  count = mbstowcs (wvalue, value, count + 1);
845  if (count > 0)
846  {
847  *p_value = g_utf16_to_utf8 (wvalue, -1, NULL, NULL, NULL);
848  }
849  g_free (wvalue);
850  }
851  }
852 #else /* !G_OS_WIN32 */
853  *p_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
854 #endif
855 
856  if (*p_value == NULL)
857  {
858  // The g_locale_to_utf8 conversion failed. FIXME: Should we rather
859  // use an empty string instead of the default_value? Not sure.
860  *p_value = default_value;
861  }
862 }
863 
864 static void
865 gnc_lconv_set_char (char *p_value, char default_value)
866 {
867  if ((p_value != NULL) && (*p_value == CHAR_MAX))
868  *p_value = default_value;
869 }
870 #endif /* Not Used */
871 
873 gnc_locale_default_currency_nodefault (void)
874 {
875  gnc_commodity * currency;
877  const char *code;
878 
879  table = gnc_get_current_commodities ();
880  code = gnc_locale_default_iso_currency_code ();
881 
882  currency = gnc_commodity_table_lookup (table, GNC_COMMODITY_NS_CURRENCY, code);
883 
884  /* Some very old locales (notably on win32) still announce a euro
885  currency as default, although it has been replaced by EUR in
886  2001. We use EUR as default in that case, but the user can always
887  override from gsettings. */
888  if (gnc_is_euro_currency (currency))
889  currency = gnc_get_euro();
890 
891  return (currency ? currency : NULL);
892 }
893 
895 gnc_locale_default_currency (void)
896 {
897  gnc_commodity * currency = gnc_locale_default_currency_nodefault ();
898 
899  return (currency ? currency :
900  gnc_commodity_table_lookup (gnc_get_current_commodities (),
901  GNC_COMMODITY_NS_CURRENCY, "USD"));
902 }
903 
904 
905 static gnc_commodity *
906 gnc_default_currency_common (gchar *requested_currency,
907  const gchar *section)
908 {
909  gnc_commodity *currency = NULL;
910  gchar *mnemonic;
911 
912  if (requested_currency)
913  return gnc_commodity_table_lookup(gnc_get_current_commodities(),
914  GNC_COMMODITY_NS_CURRENCY,
915  requested_currency);
916 
917  if (gnc_prefs_get_bool (section, GNC_PREF_CURRENCY_CHOICE_OTHER))
918  {
919  mnemonic = gnc_prefs_get_string(section, GNC_PREF_CURRENCY_OTHER);
920  currency = gnc_commodity_table_lookup(gnc_get_current_commodities(),
921  GNC_COMMODITY_NS_CURRENCY, mnemonic);
922  DEBUG("mnemonic %s, result %p", mnemonic ? mnemonic : "(null)", currency);
923  g_free(mnemonic);
924  }
925 
926  if (!currency)
927  currency = gnc_locale_default_currency ();
928  if (currency)
929  {
930  mnemonic = requested_currency;
931 // ??? Does anyone know what this is supposed to be doing?
932 // requested_currency = g_strdup(gnc_commodity_get_mnemonic(currency));
933  g_free(mnemonic);
934  }
935  return currency;
936 }
937 
940 {
941  return gnc_default_currency_common (user_default_currency, GNC_PREFS_GROUP_GENERAL);
942 }
943 
944 gnc_commodity * gnc_account_or_default_currency(const Account* account, gboolean * currency_from_account_found)
945 {
946  gnc_commodity *currency;
947  if (!account)
948  {
949  if (currency_from_account_found)
950  *currency_from_account_found = FALSE;
951  return gnc_default_currency();
952  }
953 
954  currency = gnc_account_get_currency_or_parent(account);
955  if (currency)
956  {
957  if (currency_from_account_found)
958  *currency_from_account_found = TRUE;
959  }
960  else
961  {
962  if (currency_from_account_found)
963  *currency_from_account_found = FALSE;
964  currency = gnc_default_currency();
965  }
966  return currency;
967 }
968 
969 
970 
973 {
974  return gnc_default_currency_common (user_report_currency, GNC_PREFS_GROUP_GENERAL_REPORT);
975 }
976 
977 static void
978 gnc_currency_changed_cb (GSettings *settings, gchar *key, gpointer user_data)
979 {
980  user_default_currency = NULL;
981  user_report_currency = NULL;
982  gnc_hook_run(HOOK_CURRENCY_CHANGED, NULL);
983 }
984 
985 
987 gnc_default_print_info (gboolean use_symbol)
988 {
989  static GNCPrintAmountInfo info;
990  static gboolean got_it = FALSE;
991  struct lconv *lc;
992 
993  /* These must be updated each time. */
994  info.use_symbol = use_symbol ? 1 : 0;
995  info.commodity = gnc_default_currency ();
996 
997  if (got_it)
998  return info;
999 
1000  lc = gnc_localeconv ();
1001 
1002  info.max_decimal_places = lc->frac_digits;
1003  info.min_decimal_places = lc->frac_digits;
1004 
1005  info.use_separators = 1;
1006  info.use_locale = 1;
1007  info.monetary = 1;
1008  info.force_fit = 0;
1009  info.round = 0;
1010 
1011  got_it = TRUE;
1012 
1013  return info;
1014 }
1015 
1016 static gboolean
1017 is_decimal_fraction (int fraction, guint8 *max_decimal_places_p)
1018 {
1019  guint8 max_decimal_places = 0;
1020 
1021  if (fraction <= 0)
1022  return FALSE;
1023 
1024  while (fraction != 1)
1025  {
1026  if (fraction % 10 != 0)
1027  return FALSE;
1028 
1029  fraction = fraction / 10;
1030  max_decimal_places += 1;
1031  }
1032 
1033  if (max_decimal_places_p)
1034  *max_decimal_places_p = max_decimal_places;
1035 
1036  return TRUE;
1037 }
1038 
1040 gnc_commodity_print_info (const gnc_commodity *commodity,
1041  gboolean use_symbol)
1042 {
1043  GNCPrintAmountInfo info;
1044  gboolean is_iso;
1045 
1046  if (commodity == NULL)
1047  return gnc_default_print_info (use_symbol);
1048 
1049  info.commodity = commodity;
1050 
1051  is_iso = gnc_commodity_is_iso (commodity);
1052 
1053  if (is_decimal_fraction (gnc_commodity_get_fraction (commodity),
1054  &info.max_decimal_places))
1055  {
1056  if (is_iso)
1057  info.min_decimal_places = info.max_decimal_places;
1058  else
1059  info.min_decimal_places = 0;
1060  }
1061  else
1062  info.max_decimal_places = info.min_decimal_places = 0;
1063 
1064  info.use_separators = 1;
1065  info.use_symbol = use_symbol ? 1 : 0;
1066  info.use_locale = is_iso ? 1 : 0;
1067  info.monetary = 1;
1068  info.force_fit = 0;
1069  info.round = 0;
1070 
1071  return info;
1072 }
1073 
1074 static GNCPrintAmountInfo
1075 gnc_account_print_info_helper(const Account *account, gboolean use_symbol,
1076  gnc_commodity * (*efffunc)(const Account *),
1077  int (*scufunc)(const Account*))
1078 {
1079  GNCPrintAmountInfo info;
1080  gboolean is_iso;
1081  int scu;
1082 
1083  if (account == NULL)
1084  return gnc_default_print_info (use_symbol);
1085 
1086  info.commodity = efffunc (account);
1087 
1088  is_iso = gnc_commodity_is_iso (info.commodity);
1089 
1090  scu = scufunc (account);
1091 
1092  if (is_decimal_fraction (scu, &info.max_decimal_places))
1093  {
1094  if (is_iso)
1095  info.min_decimal_places = info.max_decimal_places;
1096  else
1097  info.min_decimal_places = 0;
1098  }
1099  else
1100  info.max_decimal_places = info.min_decimal_places = 0;
1101 
1102  info.use_separators = 1;
1103  info.use_symbol = use_symbol ? 1 : 0;
1104  info.use_locale = is_iso ? 1 : 0;
1105  info.monetary = 1;
1106  info.force_fit = 0;
1107  info.round = 0;
1108 
1109  return info;
1110 }
1111 
1113 gnc_account_print_info (const Account *account, gboolean use_symbol)
1114 {
1115  return gnc_account_print_info_helper(account, use_symbol,
1118 }
1119 
1121 gnc_split_amount_print_info (Split *split, gboolean use_symbol)
1122 {
1123  if (!split)
1124  {
1125  GNCPrintAmountInfo info = gnc_default_share_print_info ();
1126  info.use_symbol = use_symbol;
1127  return info;
1128  }
1129 
1130  return gnc_account_print_info (xaccSplitGetAccount (split), use_symbol);
1131 }
1132 
1133 static GNCPrintAmountInfo
1134 gnc_default_print_info_helper (int decplaces)
1135 {
1136  GNCPrintAmountInfo info;
1137 
1138  info.commodity = NULL;
1139 
1140  info.max_decimal_places = decplaces;
1141  info.min_decimal_places = 0;
1142 
1143  info.use_separators = 1;
1144  info.use_symbol = 0;
1145  info.use_locale = 1;
1146  info.monetary = 1;
1147  info.force_fit = 0;
1148  info.round = 0;
1149 
1150  return info;
1151 }
1152 
1154 gnc_default_share_print_info (void)
1155 {
1156  static GNCPrintAmountInfo info;
1157  static gboolean got_it = FALSE;
1158 
1159  if (!got_it)
1160  {
1161  info = gnc_default_print_info_helper (5);
1162  got_it = TRUE;
1163  }
1164 
1165  return info;
1166 }
1167 
1169 gnc_share_print_info_places (int decplaces)
1170 {
1171  GNCPrintAmountInfo info;
1172 
1173  info = gnc_default_share_print_info ();
1174  info.max_decimal_places = decplaces;
1175  info.min_decimal_places = decplaces;
1176  info.force_fit = 1;
1177  info.round = 1;
1178  return info;
1179 }
1180 
1182 gnc_default_price_print_info (void)
1183 {
1184  static GNCPrintAmountInfo info;
1185  static gboolean got_it = FALSE;
1186 
1187  if (!got_it)
1188  {
1189  info = gnc_default_print_info_helper (6);
1190  got_it = TRUE;
1191  }
1192 
1193  return info;
1194 }
1195 
1197 gnc_integral_print_info (void)
1198 {
1199  static GNCPrintAmountInfo info;
1200  static gboolean got_it = FALSE;
1201 
1202  if (!got_it)
1203  {
1204  info = gnc_default_print_info_helper (0);
1205  got_it = TRUE;
1206  }
1207 
1208  return info;
1209 }
1210 
1211 /* Utility function for printing non-negative amounts */
1212 static int
1213 PrintAmountInternal(char *buf, gnc_numeric val, const GNCPrintAmountInfo *info)
1214 {
1215  struct lconv *lc = gnc_localeconv();
1216  int num_whole_digits;
1217  char temp_buf[128];
1218  gnc_numeric whole, rounding;
1219  int min_dp, max_dp;
1220  gboolean value_is_negative, value_is_decimal;
1221 
1222  g_return_val_if_fail (info != NULL, 0);
1223 
1224  if (gnc_numeric_check (val))
1225  {
1226  PWARN ("Bad numeric: %s.",
1228  *buf = '\0';
1229  return 0;
1230  }
1231 
1232  /* Print the absolute value, but remember sign */
1233  value_is_negative = gnc_numeric_negative_p (val);
1234  val = gnc_numeric_abs (val);
1235 
1236  /* Try to print as decimal. */
1237  value_is_decimal = gnc_numeric_to_decimal(&val, NULL);
1238 
1239  /* Force at least auto_decimal_places zeros */
1240  if (auto_decimal_enabled)
1241  {
1242  min_dp = MAX(auto_decimal_places, info->min_decimal_places);
1243  max_dp = MAX(auto_decimal_places, info->max_decimal_places);
1244  }
1245  else
1246  {
1247  min_dp = info->min_decimal_places;
1248  max_dp = info->max_decimal_places;
1249  }
1250 
1251  /* Don to limit the number of decimal places _UNLESS_ force_fit is
1252  * true. */
1253  if (!info->force_fit)
1254  max_dp = 99;
1255 
1256  /* rounding? -- can only ROUND if force_fit is also true */
1257  if (value_is_decimal && info->round && info->force_fit)
1258  {
1259  rounding.num = 5; /* Limit the denom to 10^13 ~= 2^44, leaving max at ~524288 */
1260  rounding.denom = pow(10, max_dp + 1);
1261  val = gnc_numeric_add(val, rounding, val.denom, GNC_HOW_RND_TRUNC);
1262 
1263  if (gnc_numeric_check(val))
1264  {
1265  PWARN ("Bad numeric from rounding: %s.",
1267  *buf = '\0';
1268  return 0;
1269  }
1270  }
1271 
1272  /* calculate the integer part and the remainder */
1273  whole = gnc_numeric_convert(val, 1, GNC_HOW_RND_TRUNC);
1274  val = gnc_numeric_sub (val, whole, GNC_DENOM_AUTO, GNC_HOW_RND_NEVER);
1275  if (gnc_numeric_check (val))
1276  {
1277  PWARN ("Problem with remainder: %s.",
1279  *buf = '\0';
1280  return 0;
1281  }
1282 
1283  /* print the integer part without separators */
1284  sprintf(temp_buf, "%" G_GINT64_FORMAT, whole.num);
1285  num_whole_digits = strlen (temp_buf);
1286 
1287  if (!info->use_separators)
1288  strcpy (buf, temp_buf);
1289  else
1290  {
1291  int group_count;
1292  char *separator;
1293  char *temp_ptr;
1294  char *buf_ptr;
1295  char *group;
1296  gchar *rev_buf;
1297 
1298  if (info->monetary)
1299  {
1300  separator = lc->mon_thousands_sep;
1301  group = lc->mon_grouping;
1302  }
1303  else
1304  {
1305  separator = lc->thousands_sep;
1306  group = lc->grouping;
1307  }
1308 
1309  buf_ptr = buf;
1310  temp_ptr = &temp_buf[num_whole_digits - 1];
1311  group_count = 0;
1312 
1313  while (temp_ptr != temp_buf)
1314  {
1315  *buf_ptr++ = *temp_ptr--;
1316 
1317  if (*group != CHAR_MAX)
1318  {
1319  group_count++;
1320 
1321  if (group_count == *group)
1322  {
1323  g_utf8_strncpy(buf_ptr, separator, 1);
1324  buf_ptr = g_utf8_find_next_char(buf_ptr, NULL);
1325  group_count = 0;
1326 
1327  /* Peek ahead at the next group code */
1328  switch (group[1])
1329  {
1330  /* A null char means repeat the last group indefinitely */
1331  case '\0':
1332  break;
1333  /* CHAR_MAX means no more grouping allowed */
1334  case CHAR_MAX:
1335  /* fall through */
1336  /* Anything else means another group size */
1337  default:
1338  group++;
1339  break;
1340  }
1341  }
1342  }
1343  }
1344 
1345  /* We built the string backwards, now reverse */
1346  *buf_ptr++ = *temp_ptr;
1347  *buf_ptr = '\0';
1348  rev_buf = g_utf8_strreverse(buf, -1);
1349  strcpy (buf, rev_buf);
1350  g_free(rev_buf);
1351  } /* endif */
1352 
1353  /* at this point, buf contains the whole part of the number */
1354 
1355  /* If it's not decimal, print the fraction as an expression. */
1356  if (!value_is_decimal)
1357  {
1358  val = gnc_numeric_reduce (val);
1359 
1360  if (val.denom > 0)
1361  sprintf (temp_buf, "%" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
1362  val.num, val.denom);
1363  else
1364  sprintf (temp_buf, "%" G_GINT64_FORMAT " * %" G_GINT64_FORMAT,
1365  val.num, -val.denom);
1366 
1367  if (whole.num == 0)
1368  *buf = '\0';
1369  else if (value_is_negative)
1370  strcat(buf, " - ");
1371  else
1372  strcat(buf, " + ");
1373 
1374  strcat (buf, temp_buf);
1375  }
1376  else
1377  {
1378  char *decimal_point;
1379  guint8 num_decimal_places = 0;
1380  char *temp_ptr = temp_buf;
1381 
1382  decimal_point = info->monetary
1383  ? lc->mon_decimal_point
1384  : lc->decimal_point;
1385  g_utf8_strncpy(temp_ptr, decimal_point, 1);
1386  temp_ptr = g_utf8_find_next_char(temp_ptr, NULL);
1387 
1388  while (!gnc_numeric_zero_p (val)
1389  && (val.denom != 1)
1390  && (num_decimal_places < max_dp))
1391  {
1392  gint64 digit;
1393 
1394  val.denom = val.denom / 10;
1395 
1396  digit = val.num / val.denom;
1397 
1398  *temp_ptr++ = digit + '0';
1399  num_decimal_places++;
1400 
1401  val.num = val.num - (digit * val.denom);
1402  }
1403 
1404  while (num_decimal_places < min_dp)
1405  {
1406  *temp_ptr++ = '0';
1407  num_decimal_places++;
1408  }
1409 
1410  /* cap the end and move to the last character */
1411  *temp_ptr-- = '\0';
1412 
1413  /* Here we strip off trailing decimal zeros per the argument. */
1414  while (*temp_ptr == '0' && num_decimal_places > min_dp)
1415  {
1416  *temp_ptr-- = '\0';
1417  num_decimal_places--;
1418  }
1419 
1420  if (num_decimal_places > max_dp)
1421  {
1422  PWARN ("max_decimal_places too small; limit %d, value %s%s",
1423  info->max_decimal_places, buf, temp_buf);
1424  }
1425 
1426  if (num_decimal_places > 0)
1427  strcat (buf, temp_buf);
1428  }
1429 
1430  return strlen(buf);
1431 }
1432 
1436 int
1438 {
1439  struct lconv *lc;
1440 
1441  char *orig_bufp = bufp;
1442  const char *currency_symbol;
1443  const char *sign;
1444 
1445  char cs_precedes;
1446  char sep_by_space;
1447  char sign_posn;
1448 
1449  gboolean print_sign = TRUE;
1450  gboolean is_shares = FALSE;
1451  gboolean print_absolute = FALSE;
1452 
1453  if (!bufp)
1454  return 0;
1455 
1456  lc = gnc_localeconv();
1457  if (info.use_locale)
1458  if (gnc_numeric_negative_p (val))
1459  {
1460  cs_precedes = lc->n_cs_precedes;
1461  sep_by_space = lc->n_sep_by_space;
1462  }
1463  else
1464  {
1465  cs_precedes = lc->p_cs_precedes;
1466  sep_by_space = lc->p_sep_by_space;
1467  }
1468  else
1469  {
1470  cs_precedes = TRUE;
1471  sep_by_space = TRUE;
1472  }
1473 
1474  if (info.commodity && info.use_symbol)
1475  {
1476  if (gnc_commodity_is_iso (info.commodity))
1477  currency_symbol = gnc_commodity_get_nice_symbol (info.commodity);
1478  else
1479  {
1480  currency_symbol = gnc_commodity_get_mnemonic (info.commodity);
1481  cs_precedes = FALSE;
1482  sep_by_space = TRUE;
1483  }
1484  }
1485  else /* !info.use_symbol || !info.commodity */
1486  currency_symbol = "";
1487 
1488  if (gnc_numeric_negative_p (val))
1489  {
1490  sign = lc->negative_sign;
1491  sign_posn = lc->n_sign_posn;
1492  }
1493  else
1494  {
1495  sign = lc->positive_sign;
1496  sign_posn = lc->p_sign_posn;
1497  }
1498 
1499  if (gnc_numeric_zero_p (val) || (sign == NULL) || (sign[0] == 0))
1500  print_sign = FALSE;
1501 
1502  /* See if we print sign now */
1503  if (print_sign && (sign_posn == 1))
1504  bufp = g_stpcpy(bufp, sign);
1505 
1506  /* Now see if we print currency */
1507  if (cs_precedes)
1508  {
1509  /* See if we print sign now */
1510  if (print_sign && (sign_posn == 3))
1511  bufp = g_stpcpy(bufp, sign);
1512 
1513  if (info.use_symbol)
1514  {
1515  bufp = g_stpcpy(bufp, currency_symbol);
1516  if (sep_by_space)
1517  bufp = g_stpcpy(bufp, " ");
1518  }
1519 
1520  /* See if we print sign now */
1521  if (print_sign && (sign_posn == 4))
1522  bufp = g_stpcpy(bufp, sign);
1523  }
1524 
1525  /* Now see if we print parentheses */
1526  if (print_sign && (sign_posn == 0))
1527  {
1528  bufp = g_stpcpy(bufp, "(");
1529  print_absolute = TRUE;
1530  }
1531 
1532  /* Now print the value */
1533  bufp += PrintAmountInternal(bufp,
1534  print_absolute ? gnc_numeric_abs(val) : val,
1535  &info);
1536 
1537  /* Now see if we print parentheses */
1538  if (print_sign && (sign_posn == 0))
1539  bufp = g_stpcpy(bufp, ")");
1540 
1541  /* Now see if we print currency */
1542  if (!cs_precedes)
1543  {
1544  /* See if we print sign now */
1545  if (print_sign && (sign_posn == 3))
1546  bufp = g_stpcpy(bufp, sign);
1547 
1548  if (info.use_symbol)
1549  {
1550  if (sep_by_space)
1551  bufp = g_stpcpy(bufp, " ");
1552  bufp = g_stpcpy(bufp, currency_symbol);
1553  }
1554 
1555  /* See if we print sign now */
1556  if (print_sign && (sign_posn == 4))
1557  bufp = g_stpcpy(bufp, sign);
1558  }
1559 
1560  /* See if we print sign now */
1561  if (print_sign && (sign_posn == 2))
1562  bufp = g_stpcpy(bufp, sign);
1563 
1564  /* return length of printed string */
1565  return (bufp - orig_bufp);
1566 }
1567 
1568 const char *
1569 xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info)
1570 {
1571  /* hack alert -- this is not thread safe ... */
1572  static char buf[1024];
1573 
1574  if (!xaccSPrintAmount (buf, val, info))
1575  buf[0] = '\0';
1576 
1577  /* its OK to return buf, since we declared it static */
1578  return buf;
1579 }
1580 
1581 
1582 /********************************************************************\
1583  ********************************************************************/
1584 
1585 #define FUDGE .00001
1586 
1587 /* This function is basically untranslatable. I'd
1588  guess out of the 29 translations we have, 20 will have their number
1589  wordings in a totally different way than English has (not to
1590  mention gender-dependent number endings). Which means this
1591  word-by-word translation will be useless or even plain
1592  wrong. For this reason, we don't even start to pretend a
1593  word-by-word translation would be of any use, so we don't mark any
1594  of these strings for translation. cstim, 2007-04-15. */
1595 static gchar *small_numbers[] =
1596 {
1597  /* Translators: This section is for generating the "amount, in
1598  words" field when printing a check. This function gets the
1599  wording right for English, but unfortunately not for most other
1600  languages. Decide for yourself whether the check printing is
1601  actually needed in your language; if not, you can safely skip the
1602  translation of all of these strings. */
1603  "Zero", "One", "Two", "Three", "Four",
1604  "Five", "Six", "Seven", "Eight", "Nine",
1605  "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
1606  "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen",
1607  "Twenty"
1608 };
1609 static gchar *medium_numbers[] =
1610 {
1611  "Zero", "Ten", "Twenty", "Thirty", "Forty",
1612  "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
1613 };
1614 static gchar *big_numbers[] =
1615 {
1616  /* Translators: This is the word for the number 10^2 */
1617  "Hundred",
1618  /* Translators: This is the word for the number 10^3 */
1619  "Thousand",
1620  /* Translators: This is the word for the number 10^6, one thousand
1621  thousands. */
1622  "Million",
1623  /* Translators: This is the word for the number 10^9, one thousand
1624  millions. WATCH OUT: In British English and many other languages
1625  this word is used for 10^12 which is one million millions! In
1626  contrast to this, here in GnuCash this is used in the American
1627  English meaning of 10^9. */
1628  "Billion",
1629  /* Translators: This is the word for the number 10^12, one million
1630  millions. */
1631  "Trillion",
1632  /* Translators: This is the word for the number 10^15 */
1633  "Quadrillion",
1634  /* Translators: This is the word for the number 10^18 */
1635  "Quintillion"
1636 };
1637 
1638 static gchar *
1639 integer_to_words(gint64 val)
1640 {
1641  gint64 log_val, pow_val, this_part;
1642  GString *result;
1643  gchar *tmp;
1644 
1645  if (val == 0)
1646  return g_strdup("zero");
1647  if (val < 0)
1648  val = -val;
1649 
1650  result = g_string_sized_new(100);
1651 
1652  while (val >= 1000)
1653  {
1654  log_val = log10(val) / 3 + FUDGE;
1655  pow_val = exp(log_val * 3 * G_LN10) + FUDGE;
1656  this_part = val / pow_val;
1657  val -= this_part * pow_val;
1658  tmp = integer_to_words(this_part);
1659  g_string_append_printf(result, "%s %s ", tmp,
1660  gettext(big_numbers[log_val]));
1661  g_free(tmp);
1662  }
1663 
1664  if (val >= 100)
1665  {
1666  this_part = val / 100;
1667  val -= this_part * 100;
1668  g_string_append_printf(result, "%s %s ",
1669  gettext(small_numbers[this_part]),
1670  gettext(big_numbers[0]));
1671  }
1672 
1673  if (val > 20)
1674  {
1675  this_part = val / 10;
1676  val -= this_part * 10;
1677  g_string_append(result, gettext(medium_numbers[this_part]));
1678  g_string_append_c(result, ' ');
1679  }
1680 
1681  if (val > 0)
1682  {
1683  this_part = val;
1684  val -= this_part;
1685  g_string_append(result, gettext(small_numbers[this_part]));
1686  g_string_append_c(result, ' ');
1687  }
1688 
1689  result = g_string_truncate(result, result->len - 1);
1690  return g_string_free(result, FALSE);
1691 }
1692 
1693 #ifdef _MSC_VER
1694 static double round(double x)
1695 {
1696  // A simple round() implementation because MSVC doesn't seem to have that
1697  return floor(x + 0.5);
1698 }
1699 #endif
1700 
1701 gchar *
1702 number_to_words(gdouble val, gint64 denom)
1703 {
1704  gint64 int_part, frac_part;
1705  gchar *int_string, *nomin_string, *denom_string, *full_string;
1706 
1707  if (val < 0) val = -val;
1708  if (denom < 0) denom = -denom;
1709 
1710  int_part = floor(val);
1711  frac_part = round((val - int_part) * denom);
1712 
1713  int_string = integer_to_words(int_part);
1714  /* Inside of the gettext macro _(...) we must not use any macros but
1715  only plain string literals. For this reason, convert the strings
1716  separately. */
1717  nomin_string = g_strdup_printf("%02" G_GINT64_FORMAT, frac_part);
1718  denom_string = g_strdup_printf("%" G_GINT64_FORMAT, denom);
1719  full_string =
1720  /* Translators: This is for the "amount, in words" field in check
1721  printing. The first %s is the integer amount of dollars (or
1722  whatever currency), the second and third %s the cent amount as
1723  a fraction, e.g. 47/100. */
1724  g_strdup_printf("%s and %s/%s",
1725  int_string, nomin_string, denom_string);
1726  g_free(int_string);
1727  g_free(nomin_string);
1728  g_free(denom_string);
1729  return full_string;
1730 }
1731 
1732 gchar *
1733 numeric_to_words(gnc_numeric val)
1734 {
1735  return number_to_words(gnc_numeric_to_double(val),
1736  gnc_numeric_denom(val));
1737 }
1738 
1739 const gchar *
1740 printable_value (gdouble val, gint denom)
1741 {
1742  GNCPrintAmountInfo info;
1743  gnc_numeric num;
1744 
1745  num = gnc_numeric_create(round(val * denom), denom);
1746  info = gnc_share_print_info_places(log10(denom));
1747  return xaccPrintAmount (num, info);
1748 }
1749 
1750 /********************************************************************\
1751  * xaccParseAmount *
1752  * parses amount strings using locale data *
1753  * *
1754  * Args: in_str -- pointer to string rep of num *
1755  * monetary -- boolean indicating whether value is monetary *
1756  * result -- pointer to result location, may be NULL *
1757  * endstr -- used to store first digit not used in parsing *
1758  * Return: gboolean -- TRUE if a number found and parsed *
1759  * If FALSE, result is not changed *
1760 \********************************************************************/
1761 
1762 /* Parsing state machine states */
1763 typedef enum
1764 {
1765  START_ST, /* Parsing initial whitespace */
1766  NEG_ST, /* Parsed a negative sign or a left paren */
1767  PRE_GROUP_ST, /* Parsing digits before grouping and decimal characters */
1768  START_GROUP_ST, /* Start of a digit group encountered (possibly) */
1769  IN_GROUP_ST, /* Within a digit group */
1770  FRAC_ST, /* Parsing the fractional portion of a number */
1771  DONE_ST, /* Finished, number is correct module grouping constraints */
1772  NO_NUM_ST /* Finished, number was malformed */
1773 } ParseState;
1774 
1775 #define done_state(state) (((state) == DONE_ST) || ((state) == NO_NUM_ST))
1776 
1777 G_INLINE_FUNC long long int multiplier (int num_decimals);
1778 
1779 long long int
1780 multiplier (int num_decimals)
1781 {
1782  switch (num_decimals)
1783  {
1784  case 8:
1785  return 100000000;
1786  case 7:
1787  return 10000000;
1788  case 6:
1789  return 1000000;
1790  case 5:
1791  return 100000;
1792  case 4:
1793  return 10000;
1794  case 3:
1795  return 1000;
1796  case 2:
1797  return 100;
1798  case 1:
1799  return 10;
1800  default:
1801  PERR("bad fraction length");
1802  g_assert_not_reached();
1803  break;
1804  }
1805 
1806  return 1;
1807 }
1808 
1809 gboolean
1810 xaccParseAmount (const char * in_str, gboolean monetary, gnc_numeric *result,
1811  char **endstr)
1812 {
1813  struct lconv *lc = gnc_localeconv();
1814 
1815  gunichar negative_sign;
1816  gunichar decimal_point;
1817  gunichar group_separator;
1818  char *group;
1819 
1820  negative_sign = g_utf8_get_char(lc->negative_sign);
1821  if (monetary)
1822  {
1823  group_separator = g_utf8_get_char(lc->mon_thousands_sep);
1824  decimal_point = g_utf8_get_char(lc->mon_decimal_point);
1825  group = lc->mon_grouping;
1826  }
1827  else
1828  {
1829  group_separator = g_utf8_get_char(lc->thousands_sep);
1830  decimal_point = g_utf8_get_char(lc->decimal_point);
1831  group = lc->grouping;
1832  }
1833 
1834  return xaccParseAmountExtended(in_str, monetary, negative_sign, decimal_point,
1835  group_separator, group, NULL, result, endstr);
1836 }
1837 
1838 /* Note: xaccParseAmountExtended causes test-print-parse-amount
1839 to fail if QOF_SCANF_LLD is simply replaced by G_GINT64_FORMAT. Why?
1840 A: Because scanf and printf use different symbols for 64-bit numbers.
1841 */
1842 gboolean
1843 xaccParseAmountExtended (const char * in_str, gboolean monetary,
1844  gunichar negative_sign, gunichar decimal_point,
1845  gunichar group_separator, char *group, char *ignore_list,
1846  gnc_numeric *result, char **endstr)
1847 {
1848  gboolean is_negative;
1849  gboolean got_decimal;
1850  gboolean need_paren;
1851  GList * group_data;
1852  long long int numer;
1853  long long int denom;
1854  int count, group_count;
1855 
1856  ParseState state;
1857 
1858  const gchar *in;
1859  gunichar uc;
1860  gchar *out_str;
1861  gchar *out;
1862 
1863  /* Initialize *endstr to in_str */
1864  if (endstr != NULL)
1865  *endstr = (char *) in_str;
1866 
1867  if (in_str == NULL)
1868  return FALSE;
1869 
1870  if (!g_utf8_validate(in_str, -1, &in))
1871  {
1872  printf("Invalid utf8 string '%s'. Bad character at position %ld.\n",
1873  in_str, g_utf8_pointer_to_offset (in_str, in));
1874  return FALSE;
1875  }
1876 
1877  /* 'out_str' will be used to store digits for numeric conversion.
1878  * 'out' will be used to traverse out_str. */
1879  out = out_str = g_new(gchar, strlen(in_str) + 128);
1880 
1881  /* 'in' is used to traverse 'in_str'. */
1882  in = in_str;
1883 
1884  is_negative = FALSE;
1885  got_decimal = FALSE;
1886  need_paren = FALSE;
1887  group_data = NULL;
1888  group_count = 0;
1889  numer = 0;
1890  denom = 1;
1891 
1892  /* Initialize the state machine */
1893  state = START_ST;
1894 
1895  /* This while loop implements a state machine for parsing numbers. */
1896  while (TRUE)
1897  {
1898  ParseState next_state = state;
1899 
1900  uc = g_utf8_get_char(in);
1901 
1902  /* Ignore anything in the 'ignore list' */
1903  if (ignore_list && uc && g_utf8_strchr(ignore_list, -1, uc) != NULL)
1904  {
1905  in = g_utf8_next_char(in);
1906  continue;
1907  }
1908 
1909  /* Note we never need to check for the end of 'in_str' explicitly.
1910  * The 'else' clauses on all the state transitions will handle that. */
1911  switch (state)
1912  {
1913  /* START_ST means we have parsed 0 or more whitespace characters */
1914  case START_ST:
1915  if (g_unichar_isdigit(uc))
1916  {
1917  count = g_unichar_to_utf8(uc, out);
1918  out += count; /* we record the digits themselves in out_str
1919  * for later conversion by libc routines */
1920  next_state = PRE_GROUP_ST;
1921  }
1922  else if (uc == decimal_point)
1923  {
1924  next_state = FRAC_ST;
1925  }
1926  else if (g_unichar_isspace(uc))
1927  {
1928  }
1929  else if (uc == negative_sign)
1930  {
1931  is_negative = TRUE;
1932  next_state = NEG_ST;
1933  }
1934  else if (uc == '(')
1935  {
1936  is_negative = TRUE;
1937  need_paren = TRUE;
1938  next_state = NEG_ST;
1939  }
1940  else
1941  {
1942  next_state = NO_NUM_ST;
1943  }
1944 
1945  break;
1946 
1947  /* NEG_ST means we have just parsed a negative sign. For now,
1948  * we only recognize formats where the negative sign comes first. */
1949  case NEG_ST:
1950  if (g_unichar_isdigit(uc))
1951  {
1952  count = g_unichar_to_utf8(uc, out);
1953  out += count;
1954  next_state = PRE_GROUP_ST;
1955  }
1956  else if (uc == decimal_point)
1957  {
1958  next_state = FRAC_ST;
1959  }
1960  else if (g_unichar_isspace(uc))
1961  {
1962  }
1963  else
1964  {
1965  next_state = NO_NUM_ST;
1966  }
1967 
1968  break;
1969 
1970  /* PRE_GROUP_ST means we have started parsing the number, but
1971  * have not encountered a decimal point or a grouping character. */
1972  case PRE_GROUP_ST:
1973  if (g_unichar_isdigit(uc))
1974  {
1975  count = g_unichar_to_utf8(uc, out);
1976  out += count;
1977  }
1978  else if (uc == decimal_point)
1979  {
1980  next_state = FRAC_ST;
1981  }
1982  else if (uc == group_separator)
1983  {
1984  next_state = START_GROUP_ST;
1985  }
1986  else if (uc == ')' && need_paren)
1987  {
1988  next_state = DONE_ST;
1989  need_paren = FALSE;
1990  }
1991  else
1992  {
1993  next_state = DONE_ST;
1994  }
1995 
1996  break;
1997 
1998  /* START_GROUP_ST means we have just parsed a group character.
1999  * Note that group characters might be whitespace!!! In general,
2000  * if a decimal point or a group character is whitespace, we
2001  * try to interpret it in the fashion that will allow parsing
2002  * of the current number to continue. */
2003  case START_GROUP_ST:
2004  if (g_unichar_isdigit(uc))
2005  {
2006  count = g_unichar_to_utf8(uc, out);
2007  out += count;
2008  group_count++; /* We record the number of digits
2009  * in the group for later checking. */
2010  next_state = IN_GROUP_ST;
2011  }
2012  else if (uc == decimal_point)
2013  {
2014  /* If we now get a decimal point, and both the decimal
2015  * and the group separator are also whitespace, assume
2016  * the last group separator was actually whitespace and
2017  * stop parsing. Otherwise, there's a problem. */
2018  if (g_unichar_isspace(group_separator) &&
2019  g_unichar_isspace(decimal_point))
2020  next_state = DONE_ST;
2021  else
2022  next_state = NO_NUM_ST;
2023  }
2024  else if (uc == ')' && need_paren)
2025  {
2026  if (g_unichar_isspace(group_separator))
2027  {
2028  next_state = DONE_ST;
2029  need_paren = FALSE;
2030  }
2031  else
2032  next_state = NO_NUM_ST;
2033  }
2034  else
2035  {
2036  /* If the last group separator is also whitespace,
2037  * assume it was intended as such and stop parsing.
2038  * Otherwise, there is a problem. */
2039  if (g_unichar_isspace(group_separator))
2040  next_state = DONE_ST;
2041  else
2042  next_state = NO_NUM_ST;
2043  }
2044  break;
2045 
2046  /* IN_GROUP_ST means we are in the middle of parsing
2047  * a group of digits. */
2048  case IN_GROUP_ST:
2049  if (g_unichar_isdigit(uc))
2050  {
2051  count = g_unichar_to_utf8(uc, out);
2052  out += count;
2053  group_count++; /* We record the number of digits
2054  * in the group for later checking. */
2055  }
2056  else if (uc == decimal_point)
2057  {
2058  next_state = FRAC_ST;
2059  }
2060  else if (uc == group_separator)
2061  {
2062  next_state = START_GROUP_ST;
2063  }
2064  else if (uc == ')' && need_paren)
2065  {
2066  next_state = DONE_ST;
2067  need_paren = FALSE;
2068  }
2069  else
2070  {
2071  next_state = DONE_ST;
2072  }
2073 
2074  break;
2075 
2076  /* FRAC_ST means we are now parsing fractional digits. */
2077  case FRAC_ST:
2078  if (g_unichar_isdigit(uc))
2079  {
2080  count = g_unichar_to_utf8(uc, out);
2081  out += count;
2082  }
2083  else if (uc == decimal_point)
2084  {
2085  /* If a subsequent decimal point is also whitespace,
2086  * assume it was intended as such and stop parsing.
2087  * Otherwise, there is a problem. */
2088  if (g_unichar_isspace(decimal_point))
2089  next_state = DONE_ST;
2090  else
2091  next_state = NO_NUM_ST;
2092  }
2093  else if (uc == group_separator)
2094  {
2095  /* If a subsequent group separator is also whitespace,
2096  * assume it was intended as such and stop parsing.
2097  * Otherwise, there is a problem. */
2098  if (g_unichar_isspace(group_separator))
2099  next_state = DONE_ST;
2100  else
2101  next_state = NO_NUM_ST;
2102  }
2103  else if (uc == ')' && need_paren)
2104  {
2105  next_state = DONE_ST;
2106  need_paren = FALSE;
2107  }
2108  else
2109  {
2110  next_state = DONE_ST;
2111  }
2112 
2113  break;
2114 
2115  default:
2116  PERR("bad state");
2117  g_assert_not_reached();
2118  break;
2119  }
2120 
2121  /* If we're moving out of the IN_GROUP_ST, record data for the group */
2122  if ((state == IN_GROUP_ST) && (next_state != IN_GROUP_ST))
2123  {
2124  group_data = g_list_prepend(group_data, GINT_TO_POINTER(group_count));
2125  group_count = 0;
2126  }
2127 
2128  /* If we're moving into the FRAC_ST or out of the machine
2129  * without going through FRAC_ST, record the integral value. */
2130  if (((next_state == FRAC_ST) && (state != FRAC_ST)) ||
2131  ((next_state == DONE_ST) && !got_decimal))
2132  {
2133  *out = '\0';
2134 
2135  if (*out_str != '\0' && sscanf(out_str, QOF_SCANF_LLD, &numer) < 1)
2136  {
2137  next_state = NO_NUM_ST;
2138  }
2139  else if (next_state == FRAC_ST)
2140  {
2141  /* reset the out pointer to record the fraction */
2142  out = out_str;
2143  *out = '\0';
2144 
2145  got_decimal = TRUE;
2146  }
2147  }
2148 
2149  state = next_state;
2150  if (done_state (state))
2151  break;
2152 
2153  in = g_utf8_next_char(in);
2154  }
2155 
2156  /* If there was an error, just quit */
2157  if (need_paren || (state == NO_NUM_ST))
2158  {
2159  g_free(out_str);
2160  g_list_free(group_data);
2161  return FALSE;
2162  }
2163 
2164  /* If there were groups, validate them */
2165  if (group_data != NULL)
2166  {
2167  gboolean good_grouping = TRUE;
2168  GList *node;
2169 
2170  /* The groups were built in reverse order. This
2171  * is the easiest order to verify them in. */
2172  for (node = group_data; group && node; node = node->next)
2173  {
2174  /* Verify group size */
2175  if (*group != GPOINTER_TO_INT(node->data))
2176  {
2177  good_grouping = FALSE;
2178  break;
2179  }
2180 
2181  /* Peek ahead at the next group code */
2182  switch (group[1])
2183  {
2184  /* A null char means repeat the last group indefinitely */
2185  case '\0':
2186  break;
2187  /* CHAR_MAX means no more grouping allowed */
2188  case CHAR_MAX:
2189  if (node->next != NULL)
2190  good_grouping = FALSE;
2191  break;
2192  /* Anything else means another group size */
2193  default:
2194  group++;
2195  break;
2196  }
2197 
2198  if (!good_grouping)
2199  break;
2200  }
2201 
2202  g_list_free(group_data);
2203 
2204  if (!good_grouping)
2205  {
2206  g_free(out_str);
2207  return FALSE;
2208  }
2209  }
2210 
2211  /* Cap the end of the fraction string, if any */
2212  *out = '\0';
2213 
2214  /* Add in fractional value */
2215  if (got_decimal && (*out_str != '\0'))
2216  {
2217  size_t len;
2218  long long int fraction;
2219 
2220  len = strlen(out_str);
2221 
2222  if (len > 8)
2223  {
2224  out_str[8] = '\0';
2225  len = 8;
2226  }
2227 
2228  if (sscanf (out_str, QOF_SCANF_LLD, &fraction) < 1)
2229  {
2230  g_free(out_str);
2231  return FALSE;
2232  }
2233 
2234  denom = multiplier(len);
2235  numer *= denom;
2236  numer += fraction;
2237  }
2238  else if (monetary && auto_decimal_enabled && !got_decimal)
2239  {
2240  if ((auto_decimal_places > 0) && (auto_decimal_places < 9))
2241  {
2242  denom = multiplier(auto_decimal_places);
2243 
2244  /* No need to multiply numer by denom at this point,
2245  * since by specifying the auto decimal places the
2246  * user has effectively determined the scaling factor
2247  * for the numerator they entered.
2248  */
2249  }
2250  }
2251 
2252  if (result != NULL)
2253  {
2254  *result = gnc_numeric_create (numer, denom);
2255  if (is_negative)
2256  *result = gnc_numeric_neg (*result);
2257  }
2258 
2259  if (endstr != NULL)
2260  *endstr = (char *) in;
2261 
2262  g_free (out_str);
2263 
2264  return TRUE;
2265 }
2266 
2267 /* enable/disable the auto_decimal_enabled option */
2268 static void
2269 gnc_set_auto_decimal_enabled (gpointer settings, gchar *key, gpointer user_data)
2270 {
2271  auto_decimal_enabled =
2272  gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT);
2273 }
2274 
2275 /* set the number of auto decimal places to use */
2276 static void
2277 gnc_set_auto_decimal_places (gpointer settings, gchar *key, gpointer user_data)
2278 {
2279  auto_decimal_places =
2280  gnc_prefs_get_int (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES);
2281 }
2282 
2283 static void
2284 gnc_auto_decimal_init (void)
2285 {
2286  auto_decimal_enabled =
2287  gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT);
2288  auto_decimal_places =
2289  gnc_prefs_get_int (GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES);
2290 }
2291 
2292 void
2293 gnc_ui_util_init (void)
2294 {
2295  gnc_configure_account_separator ();
2296  gnc_auto_decimal_init();
2297 
2298  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNT_SEPARATOR,
2299  gnc_configure_account_separator, NULL);
2300  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_NONE,
2301  gnc_configure_reverse_balance, NULL);
2302  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_CREDIT,
2303  gnc_configure_reverse_balance, NULL);
2304  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_REVERSED_ACCTS_INC_EXP,
2305  gnc_configure_reverse_balance, NULL);
2306  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_CHOICE_LOCALE,
2307  gnc_currency_changed_cb, NULL);
2308  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_CHOICE_OTHER,
2309  gnc_currency_changed_cb, NULL);
2310  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_CURRENCY_OTHER,
2311  gnc_currency_changed_cb, NULL);
2312  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_CHOICE_LOCALE,
2313  gnc_currency_changed_cb, NULL);
2314  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_CHOICE_OTHER,
2315  gnc_currency_changed_cb, NULL);
2316  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_CURRENCY_OTHER,
2317  gnc_currency_changed_cb, NULL);
2318  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_POINT,
2319  gnc_set_auto_decimal_enabled, NULL);
2320  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_AUTO_DECIMAL_PLACES,
2321  gnc_set_auto_decimal_places, NULL);
2322 
2323 }
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
#define xaccTransAppendSplit(t, s)
Definition: Transaction.h:357
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
Definition: Transaction.c:1920
int gnc_commodity_get_fraction(const gnc_commodity *cm)
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:237
gint64 xaccAccountGetTaxUSCopyNumber(const Account *acc)
Definition: Account.c:3876
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
utility functions for the GnuCash UI
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2458
gnc_numeric gnc_numeric_neg(gnc_numeric a)
#define DEBUG(format, args...)
Definition: qoflog.h:255
void gnc_features_set_used(QofBook *book, const gchar *feature)
Definition: gnc-features.c:131
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
gnc_numeric gnc_numeric_add(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean gnc_numeric_to_decimal(gnc_numeric *a, guint8 *max_decimal_places)
void gnc_book_option_num_field_source_change_cb(gboolean num_action)
Definition: gnc-ui-util.c:253
gboolean gnc_numeric_zero_p(gnc_numeric a)
gboolean gnc_prefs_set_string(const gchar *group, const gchar *pref_name, const gchar *value)
Definition: gnc-prefs.c:324
#define PERR(format, args...)
Definition: qoflog.h:237
gnc_commodity * gnc_default_report_currency(void)
Definition: gnc-ui-util.c:972
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:206
gboolean gnc_numeric_negative_p(gnc_numeric a)
#define VREC
Definition: Split.h:71
gnc_numeric gnc_numeric_reduce(gnc_numeric n)
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
Definition: Account.c:2803
#define PWARN(format, args...)
Definition: qoflog.h:243
gchar * gnc_get_account_name_for_register(const Account *account)
Definition: gnc-ui-util.c:282
gdouble gnc_numeric_to_double(gnc_numeric n)
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
QofBook * qof_session_get_book(const QofSession *session)
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
Account handling public routines.
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
#define YREC
Definition: Split.h:68
const char * gnc_numeric_errorCode_to_string(GNCNumericErrorCode error_code)
#define FREC
Definition: Split.h:69
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
Definition: Account.c:2915
const char * gnc_commodity_get_nice_symbol(const gnc_commodity *cm)
const char * xaccAccountGetTaxUSCode(const Account *acc)
Definition: Account.c:3833
gnc_numeric gnc_numeric_abs(gnc_numeric a)
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
gboolean xaccAccountGetTaxRelated(const Account *acc)
Definition: Account.c:3808
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
All type declarations for the whole Gnucash engine.
#define CREC
Definition: Split.h:67
int xaccSPrintAmount(char *bufp, gnc_numeric val, GNCPrintAmountInfo info)
Definition: gnc-ui-util.c:1437
GNCAccountType
Definition: Account.h:96
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Definition: Account.c:3155
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
Generic api to store and retrieve preferences.
gnc_numeric gnc_numeric_sub(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
GList * gnc_account_get_descendants(const Account *account)
Definition: Account.c:2755
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Definition: gnc-ui-util.c:944
GList * gnc_account_get_children(const Account *account)
Definition: Account.c:2654
Definition: SplitP.h:71
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
gint64 time64
Definition: gnc-date.h:83
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2630
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
Account * gnc_account_lookup_for_register(const Account *base_account, const gchar *name)
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void xaccAccountSetName(Account *acc, const char *str)
Definition: Account.c:2229
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
const gchar * QofLogModule
Definition: qofid.h:89
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
#define NREC
Definition: Split.h:70
Utility functions for file access.