GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
assistant-hierarchy.c
1 /********************************************************************\
2  * assistant-hierarchy.c -- account hierarchy creation functionality*
3  * Copyright (C) 2001 Gnumatic, Inc. *
4  * Copyright (C) 2006 David Hampton <[email protected]> *
5  * Copyright (C) 2010 Geert Janssens *
6  * *
7  * This program is free software; you can redistribute it and/or *
8  * modify it under the terms of the GNU General Public License as *
9  * published by the Free Software Foundation; either version 2 of *
10  * the License, or (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License*
18  * along with this program; if not, contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA [email protected] *
23 \********************************************************************/
24 
25 #include "config.h"
26 
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 
34 #include "gnc-account-merge.h"
35 #include "dialog-new-user.h"
36 #include "dialog-options.h"
37 #include "dialog-utils.h"
38 #include "dialog-file-access.h"
39 #include "assistant-hierarchy.h"
40 #include "assistant-utils.h"
41 #include "gnc-amount-edit.h"
42 #include "gnc-currency-edit.h"
43 #include "gnc-exp-parser.h"
44 #include "gnc-general-select.h"
45 #include "gnc-gnome-utils.h"
46 #include "gnc-prefs.h"
47 #include "gnc-hooks.h"
48 #include "gnc-component-manager.h"
49 #include "gnc-path.h"
50 #include "gnc-gui-query.h"
51 #include "gnc-tree-view-account.h"
52 #include "gnc-ui-util.h"
53 #include "io-example-account.h"
54 #include "top-level.h"
55 #include "gnc-main-window.h"
57 
58 #include "gnc-engine.h"
59 static QofLogModule log_module = GNC_MOD_IMPORT;
60 
61 #define GNC_PREFS_GROUP "dialogs.new-hierarchy"
62 #define GNC_PREF_SHOW_ON_NEW_FILE "show-on-new-file"
63 
64 typedef enum
65 {
66  COL_CHECKED,
67  COL_TITLE,
68  COL_SHORT_DESCRIPTION,
69  COL_LONG_DESCRIPTION,
70  COL_ACCOUNT,
71  NUM_COLUMNS
72 } ColumnNames;
73 
74 
75 typedef struct
76 {
77  GtkWidget *dialog;
78  GtkWidget *assistant;
79  gboolean next_ok;
80 
81  GtkWidget *currency_selector;
82 
83  GtkTreeView *categories_tree;
84  GtkTreeRowReference *initial_category;
85  GtkTextView *category_description;
86  GtkWidget *category_accounts_container;
87  GtkLabel *category_accounts_label;
88  GtkTreeView *category_accounts_tree;
89  gboolean category_set_changed;
90 
91  GncTreeViewAccount *final_account_tree;
92  GtkWidget *final_account_tree_container;
93  Account *selected_account;
95  GHashTable *balance_hash;
96 
97  Account *our_account_tree;
98  QofBook *temporary;
99 
100  gboolean account_list_added;
101  gboolean use_defaults;
102  gboolean new_book; /* presumably only used for new book creation but we check*/
103 
104  GNCOptionDB *options;
105  GNCOptionWin *optionwin;
106 
107  GncHierarchyAssistantFinishedCallback when_completed;
108 
110 
111 void on_prepare (GtkAssistant *assistant, GtkWidget *page,
112  hierarchy_data *data);
113 void on_choose_account_categories_prepare (hierarchy_data *data);
114 void select_all_clicked (GtkButton *button,
115  hierarchy_data *data);
116 void clear_all_clicked (GtkButton *button,
117  hierarchy_data *data);
118 void on_final_account_prepare (hierarchy_data *data);
119 void on_cancel (GtkAssistant *gtkassistant, hierarchy_data *data);
120 void on_finish (GtkAssistant *gtkassistant, hierarchy_data *data);
121 
122 // ------------------------------------------------------------
123 
124 static void
125 delete_hierarchy_dialog (hierarchy_data *data)
126 {
127  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(data->dialog));
128  gtk_widget_destroy (data->dialog);
129 }
130 
131 static void
132 destroy_hash_helper (gpointer key, gpointer value, gpointer user_data)
133 {
134  gnc_numeric *balance = value;
135  g_free (balance);
136 }
137 
138 static void
139 gnc_hierarchy_destroy_cb (GtkObject *obj, hierarchy_data *data)
140 {
141  GHashTable *hash;
142 
143  hash = data->balance_hash;
144  if (hash)
145  {
146  g_hash_table_foreach (hash, destroy_hash_helper, NULL);
147  g_hash_table_destroy (hash);
148  data->balance_hash = NULL;
149  }
150 }
151 
152 static gnc_numeric
153 get_final_balance (GHashTable *hash, Account *account)
154 {
155  gnc_numeric *balance;
156 
157  if (!hash || !account)
158  return gnc_numeric_zero ();
159 
160  balance = g_hash_table_lookup(hash, account);
161  if (balance)
162  return *balance;
163  return gnc_numeric_zero ();
164 }
165 
166 static void
167 set_final_balance (GHashTable *hash, Account *account, gnc_numeric in_balance)
168 {
169  gnc_numeric *balance;
170 
171  if (!hash || !account)
172  return;
173 
174  balance = g_hash_table_lookup (hash, account);
175  if (balance)
176  {
177  *balance = in_balance;
178  return;
179  }
180 
181  balance = g_new (gnc_numeric, 1);
182  *balance = in_balance;
183  g_hash_table_insert (hash, account, balance);
184 }
185 
186 static gchar*
187 gnc_get_ea_locale_dir(const char *top_dir)
188 {
189  static gchar *default_locale = "C";
190  gchar *ret;
191  gchar *locale;
192  struct stat buf;
193  int i;
194 
195 #ifdef HAVE_LC_MESSAGES
196  locale = g_strdup(setlocale(LC_MESSAGES, NULL));
197 #else
198 # ifdef G_OS_WIN32
199  /* On win32, setlocale() doesn't say anything useful. Use
200  glib's function instead. */
201  locale = g_win32_getlocale();
202  if (!locale)
203  {
204  PWARN ("Couldn't retrieve locale. Falling back to default one.");
205  locale = g_strdup ("C");
206  }
207 # else
208  /*
209  * Mac OS X 10.1 and earlier, not only doesn't have LC_MESSAGES
210  * setlocale can sometimes return NULL instead of "C"
211  */
212  locale = g_strdup(setlocale(LC_ALL, NULL) ?
213  setlocale(LC_ALL, NULL) : "C");
214 # endif
215 #endif
216 
217  i = strlen(locale);
218  ret = g_build_filename(top_dir, locale, (char *)NULL);
219 
220  while (g_stat(ret, &buf) != 0)
221  {
222  i--;
223  if (i < 1)
224  {
225  g_free(ret);
226  ret = g_build_filename(top_dir, default_locale, (char *)NULL);
227  break;
228  }
229  locale[i] = '\0';
230  g_free(ret);
231  ret = g_build_filename(top_dir, locale, (char *)NULL);
232  }
233 
234  g_free(locale);
235 
236  return ret;
237 }
238 
239 /************************************************************
240  * Choose Categories Page *
241  ************************************************************/
242 
260 static gboolean
261 account_set_checked_helper (GtkListStore *store,
262  GtkTreePath *path,
263  GtkTreeIter *iter,
264  gboolean *result)
265 {
266  gboolean checked;
267 
268  g_return_val_if_fail(GTK_IS_LIST_STORE(store), FALSE);
269 
270  gtk_tree_model_get (GTK_TREE_MODEL(store), iter, COL_CHECKED, &checked, -1);
271  if (checked)
272  {
273  *result = TRUE;
274  return TRUE; /* Stop tree walk. */
275  }
276 
277  return FALSE;
278 }
279 
286 static void
287 categories_page_enable_next (hierarchy_data *data)
288 {
289  gint currentpagenum;
290  GtkWidget *currentpage;
291  GtkAssistant *assistant = GTK_ASSISTANT(data->dialog);
292 
293  data->next_ok = FALSE;
294  gtk_tree_model_foreach (gtk_tree_view_get_model (data->categories_tree),
295  (GtkTreeModelForeachFunc)account_set_checked_helper,
296  &data->next_ok);
297 
298  currentpagenum = gtk_assistant_get_current_page(assistant);
299  currentpage = gtk_assistant_get_nth_page(assistant, currentpagenum);
300 
301  gtk_assistant_set_page_complete(assistant, currentpage, data->next_ok);
302 }
303 
304 
305 static void
306 categories_selection_changed (GtkTreeModel *treemodel,
307  GtkTreePath *arg1,
308  GtkTreeIter *arg2,
309  hierarchy_data *data)
310 {
311  data->category_set_changed = TRUE;
312  categories_page_enable_next(data);
313 }
314 
315 
316 static void
317 add_one_category (GncExampleAccount *acc,
318  hierarchy_data *data)
319 {
320  GtkTreeView *view;
321  GtkListStore *store;
322  GtkTreeIter iter;
323  GtkTreePath* path;
324  gboolean use_defaults;
325 
326  g_return_if_fail(acc != NULL);
327  g_return_if_fail(data != NULL);
328 
329  view = data->categories_tree;
330  store = GTK_LIST_STORE(gtk_tree_view_get_model(view));
331  use_defaults = data->use_defaults && acc->start_selected;
332 
333  gtk_list_store_append(store, &iter);
334  gtk_list_store_set(store, &iter,
335  COL_CHECKED, use_defaults,
336  COL_TITLE, acc->title,
337  COL_SHORT_DESCRIPTION, acc->short_description,
338  COL_LONG_DESCRIPTION, acc->long_description,
339  COL_ACCOUNT, acc,
340  -1);
341 
342  if (use_defaults)
343  {
344  data->category_set_changed = TRUE;
345  path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
346  data->initial_category = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), path);
347  gtk_tree_path_free(path);
348  }
349 }
350 
351 static void
352 category_checkbox_toggled (GtkCellRendererToggle *toggle,
353  gchar *path,
354  GtkListStore *store)
355 {
356  GtkTreeIter iter;
357  gboolean active;
358 
359  if (!gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store),
360  &iter, path))
361  return;
362 
363  /* Get current state of the category */
364  active = gtk_cell_renderer_toggle_get_active(toggle);
365  gtk_list_store_set(store, &iter, COL_CHECKED, !active, -1);
366 }
367 
368 static void
369 account_categories_tree_view_prepare (hierarchy_data *data)
370 {
371  GSList *list;
372  gchar *gnc_accounts_dir;
373  gchar *locale_dir;
374  GtkTreeView *tree_view;
375  GtkListStore *model;
376  GtkTreeViewColumn *column;
377  GtkCellRenderer *renderer;
378  GtkTreeSelection *selection;
379  GtkTreePath *path;
380 
381  gnc_accounts_dir = gnc_path_get_accountsdir ();
382  locale_dir = gnc_get_ea_locale_dir (gnc_accounts_dir);
383  list = gnc_load_example_account_list (locale_dir);
384  g_free (gnc_accounts_dir);
385  g_free (locale_dir);
386 
387  /* Prepare the account_categories GtkTreeView with a model and with some columns */
388  tree_view = data->categories_tree;
389  model = gtk_list_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING,
390  G_TYPE_STRING, G_TYPE_POINTER);
391  gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL(model));
392  g_object_unref (model);
393 
394  g_slist_foreach(list, (GFunc)add_one_category, data);
395 
396  g_signal_connect (G_OBJECT (model), "row_changed",
397  G_CALLBACK (categories_selection_changed),
398  data);
399 
400  renderer = gtk_cell_renderer_toggle_new ();
401  g_object_set (G_OBJECT (renderer), "activatable", TRUE, NULL);
402  column = gtk_tree_view_column_new_with_attributes (_("Selected"),
403  renderer,
404  "active", COL_CHECKED,
405  NULL);
406  gtk_tree_view_append_column (tree_view, column);
407  gtk_tree_view_column_set_sort_column_id (column, COL_CHECKED);
408  g_signal_connect (G_OBJECT (renderer), "toggled",
409  G_CALLBACK (category_checkbox_toggled),
410  model);
411 
412 
413  renderer = gtk_cell_renderer_text_new ();
414  column = gtk_tree_view_column_new_with_attributes (_("Account Types"),
415  renderer,
416  "text", COL_TITLE,
417  NULL);
418  gtk_tree_view_append_column (tree_view, column);
419  gtk_tree_view_column_set_sort_column_id (column, COL_TITLE);
420 
421 // renderer = gtk_cell_renderer_text_new ();
422 // column = gtk_tree_view_column_new_with_attributes (_("Description"),
423 // renderer,
424 // "text", COL_SHORT_DESCRIPTION,
425 // NULL);
426 // gtk_tree_view_append_column (tree_view, column);
427 // gtk_tree_view_column_set_sort_column_id (column, COL_SHORT_DESCRIPTION);
428 
429  gtk_tree_view_set_headers_clickable(tree_view, TRUE);
430  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(model),
431  COL_TITLE,
432  GTK_SORT_ASCENDING);
433 
434  if (data->initial_category)
435  {
436  path = gtk_tree_row_reference_get_path(data->initial_category);
437  selection = gtk_tree_view_get_selection(tree_view);
438  gtk_tree_view_scroll_to_cell(tree_view, path, NULL, TRUE, 0.5, 0.5);
439  gtk_tree_selection_select_path(selection, path);
440  gtk_tree_path_free(path);
441  }
442 }
443 
444 void on_prepare (GtkAssistant *assistant, GtkWidget *page,
445  hierarchy_data *data)
446 {
447  const int selection_page = data->new_book ? 3 : 2;
448  const int final_page = data->new_book ? 4 : 3;
449  const int current_page = gtk_assistant_get_current_page (assistant);
450 
451  if (current_page == selection_page)
452  on_choose_account_categories_prepare(data);
453 
454  if (current_page == final_page)
455  on_final_account_prepare (data);
456 }
457 
458 void
459 on_choose_account_categories_prepare (hierarchy_data *data)
460 {
461  GtkTextBuffer* buffer;
462 
463  if (!data->account_list_added)
464  {
465  /* clear out the description/tree */
466  if (data->category_accounts_tree)
467  gtk_widget_destroy(GTK_WIDGET(data->category_accounts_tree));
468  data->category_accounts_tree = NULL;
469  buffer = gtk_text_view_get_buffer(data->category_description);
470  gtk_text_buffer_set_text(buffer, "", -1);
471 
472  data->account_list_added = TRUE;
473 
474  /* Build the categories tree if necessary */
475  gnc_suspend_gui_refresh ();
476  account_categories_tree_view_prepare (data);
477  gnc_resume_gui_refresh ();
478  }
479  categories_page_enable_next(data);
480 }
481 
482 static void
483 categories_tree_selection_changed (GtkTreeSelection *selection,
484  hierarchy_data *data)
485 {
486  GtkTreeView *tree_view;
487  GtkTreeModel *model;
488  GtkTreeViewColumn *column;
489  GtkTreeIter iter;
490  GncExampleAccount *gea;
491  GtkTextBuffer* buffer;
492  gchar *text;
493 
494  /* Remove the old account tree */
495  if (data->category_accounts_tree)
496  gtk_widget_destroy(GTK_WIDGET(data->category_accounts_tree));
497  data->category_accounts_tree = NULL;
498 
499  /* Add a new one if something selected */
500  if (gtk_tree_selection_get_selected (selection, &model, &iter))
501  {
502  gchar *text2;
503  gtk_tree_model_get (model, &iter, COL_ACCOUNT, &gea, -1);
504  /* Translators: '%s' is the name of the selected account hierarchy template. */
505  text2 = g_strdup_printf(_("Accounts in '%s'"), gea->title);
506  text = g_strdup_printf("<b>%s</b>", text2);
507  gtk_label_set_markup(data->category_accounts_label, text);
508  g_free(text2);
509  g_free(text);
510  buffer = gtk_text_view_get_buffer(data->category_description);
511  gtk_text_buffer_set_text(buffer, gea->long_description ?
512  gea->long_description :
513  _("No description provided."), -1);
514 
515  tree_view = gnc_tree_view_account_new_with_root (gea->root, FALSE);
516  /* Override the normal fixed (user settable) sizing */
517  column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view), 0);
518  gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
519 
520  data->category_accounts_tree = tree_view;
521  gtk_tree_view_expand_all (tree_view);
522  gtk_container_add(GTK_CONTAINER(data->category_accounts_container), GTK_WIDGET(tree_view));
523  gtk_widget_show(GTK_WIDGET(tree_view));
524  }
525  else
526  {
527  gchar *text;
528  text = g_strdup_printf ("<b>%s</b>", _("Accounts in Category"));
529  gtk_label_set_markup(data->category_accounts_label, text);
530  g_free (text);
531  buffer = gtk_text_view_get_buffer(data->category_description);
532  gtk_text_buffer_set_text(buffer, "", -1);
533  }
534 }
535 
536 static gboolean
537 select_helper (GtkListStore *store,
538  GtkTreePath *path,
539  GtkTreeIter *iter,
540  gpointer data)
541 {
542  GncExampleAccount *gea;
543 
544  g_return_val_if_fail(GTK_IS_LIST_STORE(store), FALSE);
545 
546  gtk_tree_model_get (GTK_TREE_MODEL(store), iter, COL_ACCOUNT, &gea, -1);
547  if ((gea != NULL) && !gea->exclude_from_select_all)
548  {
549  gtk_list_store_set(store, iter,
550  COL_CHECKED, GPOINTER_TO_INT(data),
551  -1);
552  }
553 
554  return FALSE; /* Run entire tree */
555 }
556 
557 void
558 select_all_clicked (GtkButton *button,
559  hierarchy_data *data)
560 {
561  gtk_tree_model_foreach (gtk_tree_view_get_model (data->categories_tree),
562  (GtkTreeModelForeachFunc)select_helper,
563  GINT_TO_POINTER(TRUE));
564 }
565 
566 void
567 clear_all_clicked (GtkButton *button,
568  hierarchy_data *data)
569 {
570  gtk_tree_model_foreach (gtk_tree_view_get_model (data->categories_tree),
571  (GtkTreeModelForeachFunc)select_helper,
572  GINT_TO_POINTER(FALSE));
573 }
574 
575 /************************************************************
576  * Opening Balances Page *
577  ************************************************************/
578 
579 static void
580 delete_our_account_tree (hierarchy_data *data)
581 {
582  if (data->our_account_tree != NULL)
583  {
584  xaccAccountBeginEdit (data->our_account_tree);
585  xaccAccountDestroy (data->our_account_tree);
586  data->our_account_tree = NULL;
587  }
588 }
589 
590 static Account*
591 clone_account (const Account* from, gnc_commodity *com)
592 {
593  Account *ret;
594 
595  ret = xaccCloneAccount (from, gnc_get_current_book ());
596 
597  xaccAccountSetCommodity (ret, com);
598 
599  return ret;
600 }
601 
603 {
604  Account *to;
605  Account *parent;
606  gnc_commodity *com;
607 };
608 
609 static void
610 add_groups_for_each (Account *toadd, gpointer data)
611 {
612  struct add_group_data_struct *dadata = data;
613  Account *foundact;
614 
615  foundact = gnc_account_lookup_by_name(dadata->to, xaccAccountGetName(toadd));
616 
617  if (!foundact)
618  {
619  foundact = clone_account (toadd, dadata->com);
620 
621  if (dadata->to)
622  gnc_account_append_child (dadata->to, foundact);
623  else if (dadata->parent)
624  gnc_account_append_child (dadata->parent, foundact);
625  else
626  {
627  g_warning ("add_groups_for_each: no valid parent");
628  }
629  }
630 
631  {
632  if (gnc_account_n_children(toadd) > 0)
633  {
634  struct add_group_data_struct downdata;
635 
636  downdata.to = foundact;
637  downdata.parent = foundact;
638  downdata.com = dadata->com;
639 
640  gnc_account_foreach_child (toadd, add_groups_for_each, &downdata);
641  }
642  }
643 }
644 
645 static void
646 add_new_accounts_with_random_guids (Account *into, Account *from,
647  gnc_commodity *com)
648 {
649  struct add_group_data_struct data;
650  data.to = into;
651  data.parent = NULL;
652  data.com = com;
653 
654  gnc_account_foreach_child (from, add_groups_for_each, &data);
655 }
656 
657 static Account *
658 hierarchy_merge_accounts (GSList *dalist, gnc_commodity *com)
659 {
660  GSList *mark;
661  Account *ret = xaccMallocAccount (gnc_get_current_book ());
662 
663  for (mark = dalist; mark; mark = mark->next)
664  {
665  GncExampleAccount *xea = mark->data;
666 
667  add_new_accounts_with_random_guids (ret, xea->root, com);
668  }
669 
670  return ret;
671 }
672 
673 static gboolean
674 accumulate_accounts (GtkListStore *store,
675  GtkTreePath *path,
676  GtkTreeIter *iter,
677  GSList **list)
678 {
679  GncExampleAccount *gea;
680  gboolean active;
681 
682  g_return_val_if_fail(GTK_IS_LIST_STORE(store), FALSE);
683 
684  gtk_tree_model_get (GTK_TREE_MODEL(store), iter,
685  COL_CHECKED, &active,
686  COL_ACCOUNT, &gea,
687  -1);
688  if (active && gea)
689  *list = g_slist_prepend(*list, gea);
690 
691  return FALSE; /* Run entire list */
692 }
693 
694 
695 static GSList *
696 get_selected_account_list (GtkTreeView *tree_view)
697 {
698  GSList *actlist = NULL;
699  GtkTreeModel *model;
700 
701  model = gtk_tree_view_get_model (tree_view);
702  gtk_tree_model_foreach (model,
703  (GtkTreeModelForeachFunc)accumulate_accounts,
704  &actlist);
705  return actlist;
706 }
707 
708 static void
709 balance_cell_data_func (GtkTreeViewColumn *tree_column,
710  GtkCellRenderer *cell,
711  GtkTreeModel *model,
712  GtkTreeIter *iter,
713  gpointer user_data)
714 {
715  Account *account;
716  gnc_numeric balance;
717  const gchar *string;
718  GNCPrintAmountInfo print_info;
719  hierarchy_data *data = (hierarchy_data *)user_data;
720  gboolean allow_value;
721 
722  g_return_if_fail (GTK_TREE_MODEL (model));
723  account = gnc_tree_view_account_get_account_from_iter (model, iter);
724 
725  balance = get_final_balance (data->balance_hash, account);
726  if (gnc_numeric_zero_p (balance))
727  {
728  string = "";
729  }
730  else
731  {
732  print_info = gnc_account_print_info (account, FALSE);
733  string = xaccPrintAmount (balance, print_info);
734  }
735 
736  if (xaccAccountGetType(account) == ACCT_TYPE_EQUITY ||
738  {
739  allow_value = FALSE;
740  string = _("zero");
741  }
742  else
743  {
744  GncAccountMergeDisposition disp;
745  disp = determine_merge_disposition(gnc_book_get_root_account(gnc_get_current_book()), account);
746  if (disp == GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW)
747  {
748  allow_value = !xaccAccountGetPlaceholder(account);
749  }
750  else
751  {
752  allow_value = FALSE;
753  string = _("existing account");
754  }
755  }
756  g_object_set (G_OBJECT (cell),
757  "text", string,
758  "editable", allow_value,
759  "sensitive", allow_value,
760  NULL);
761 }
762 
763 static void
764 balance_cell_edited (GtkCellRendererText *cell,
765  gchar *path,
766  gchar *new_text,
767  gpointer user_data)
768 {
769  Account *account;
770  char *error_loc;
771  gnc_numeric amount;
772  hierarchy_data *data = (hierarchy_data *)user_data;
773 
774  g_return_if_fail(data != NULL);
775 
776  account = gnc_tree_view_account_get_selected_account(data->final_account_tree);
777  if (account == NULL)
778  {
779  g_critical("account is null");
780  return;
781  }
782 
783  error_loc = NULL;
784  if (!gnc_exp_parser_parse (new_text, &amount, &error_loc))
785  {
786  amount = gnc_numeric_zero();
787  g_object_set (G_OBJECT(cell), "text", "", NULL);
788  }
789  /* Bug#348364: Emulating price-cell, we need to ensure the denominator of
790  * the amount is in the SCU of the account's commodity (so
791  * gnc-ui-util.c:is_decimal_fraction() on the remainder denom for
792  * fractional values will be a "decimal").
793  */
794  {
795  int account_cmdty_fraction = xaccAccountGetCommoditySCU(account);
796  amount = gnc_numeric_convert(amount, account_cmdty_fraction, GNC_HOW_RND_ROUND_HALF_UP);
797  }
798  set_final_balance (data->balance_hash, account, amount);
799  qof_event_gen (QOF_INSTANCE(account), QOF_EVENT_MODIFY, NULL);
800 }
801 
802 static void
803 placeholder_cell_data_func (GtkTreeViewColumn *tree_column,
804  GtkCellRenderer *cell,
805  GtkTreeModel *model,
806  GtkTreeIter *iter,
807  gpointer user_data)
808 {
809  Account *account, *root;
810  gboolean willbe_placeholder = FALSE;
811  GncAccountMergeDisposition disp;
812 
813  g_return_if_fail (GTK_TREE_MODEL (model));
814  account = gnc_tree_view_account_get_account_from_iter (model, iter);
815  root = gnc_book_get_root_account(gnc_get_current_book());
816  disp = determine_merge_disposition(root, account);
817  switch (disp)
818  {
819  case GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING:
820  {
821  /* find the existing account, do whatever it is. */
822  gchar *full_name;
823  Account *existing_acct;
824  full_name = gnc_account_get_full_name(account);
825  existing_acct = gnc_account_lookup_by_full_name(root, full_name);
826  willbe_placeholder = xaccAccountGetPlaceholder(existing_acct);
827  g_free(full_name);
828  }
829  break;
830  case GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW:
831  willbe_placeholder = xaccAccountGetPlaceholder(account);
832  break;
833  }
834 
835  gtk_cell_renderer_toggle_set_active(GTK_CELL_RENDERER_TOGGLE(cell), willbe_placeholder);
836 }
837 
838 
839 static void
840 use_existing_account_data_func(GtkTreeViewColumn *tree_column,
841  GtkCellRenderer *cell,
842  GtkTreeModel *tree_model,
843  GtkTreeIter *iter,
844  gpointer user_data)
845 {
846  Account *new_acct;
847  Account *real_root;
848  GncAccountMergeDisposition disposition;
849  char *to_user = "(error; unknown condition)";
850 
851  g_return_if_fail (GTK_TREE_MODEL (tree_model));
852  new_acct = gnc_tree_view_account_get_account_from_iter(tree_model, iter);
853  if (new_acct == NULL)
854  {
855  g_object_set (G_OBJECT(cell), "text", "(null account)", NULL);
856  return;
857  }
858 
859  real_root = gnc_book_get_root_account(gnc_get_current_book());
860  disposition = determine_merge_disposition(real_root, new_acct);
861  switch (disposition)
862  {
863  case GNC_ACCOUNT_MERGE_DISPOSITION_USE_EXISTING:
864  to_user = _("Yes");
865  break;
866  case GNC_ACCOUNT_MERGE_DISPOSITION_CREATE_NEW:
867  to_user = _("No");
868  break;
869  }
870 
871  g_object_set(G_OBJECT(cell), "text", to_user, NULL);
872 }
873 
874 void
875 on_final_account_prepare (hierarchy_data *data)
876 {
877  GSList *actlist;
878  GtkTreeView *tree_view;
879  GtkTreeSelection *selection;
880  GtkCellRenderer *renderer;
881  GtkTreeViewColumn *column;
882  gnc_commodity *com;
883 
884  /* Anything to do? */
885  if (!data->category_set_changed)
886  return;
887  data->category_set_changed = FALSE;
888 
889  gnc_suspend_gui_refresh ();
890 
891  /* Delete any existing account tree */
892  if (data->final_account_tree)
893  {
894  gtk_widget_destroy(GTK_WIDGET(data->final_account_tree));
895  data->final_account_tree = NULL;
896  }
897  delete_our_account_tree (data);
898 
899 
900  /* Build a new account list */
901  actlist = get_selected_account_list (data->categories_tree);
902  com = gnc_currency_edit_get_currency (GNC_CURRENCY_EDIT(data->currency_selector));
903  data->our_account_tree = hierarchy_merge_accounts (actlist, com);
904 
905 
906  /* Now build a new account tree */
907  data->final_account_tree
908  = GNC_TREE_VIEW_ACCOUNT(gnc_tree_view_account_new_with_root (data->our_account_tree, FALSE));
909  tree_view = GTK_TREE_VIEW(data->final_account_tree);
910  gnc_tree_view_account_set_name_edited(data->final_account_tree,
911  gnc_tree_view_account_name_edited_cb);
912  gnc_tree_view_account_set_code_edited(data->final_account_tree,
913  gnc_tree_view_account_code_edited_cb);
914  gnc_tree_view_account_set_description_edited(data->final_account_tree,
915  gnc_tree_view_account_description_edited_cb);
916  gnc_tree_view_account_set_notes_edited(data->final_account_tree,
917  gnc_tree_view_account_notes_edited_cb);
918 
919  gtk_tree_view_set_headers_visible (tree_view, TRUE);
921  GNC_TREE_VIEW(data->final_account_tree), "type");
922  g_object_set_data(G_OBJECT(column), DEFAULT_VISIBLE, GINT_TO_POINTER(1));
923  gnc_tree_view_configure_columns (GNC_TREE_VIEW(data->final_account_tree));
924  gnc_tree_view_set_show_column_menu (GNC_TREE_VIEW(data->final_account_tree),
925  FALSE);
926 
927  selection = gtk_tree_view_get_selection (tree_view);
928  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
929 
930  // This is a re-definition of the placeholder that the account-tree model
931  // provides, reflecting the to-be-created state of the account tree
932  // post-merge.
933  {
934  renderer = gtk_cell_renderer_toggle_new();
935  g_object_set(G_OBJECT (renderer),
936  "activatable", FALSE,
937  "sensitive", FALSE,
938  NULL);
939  column = gtk_tree_view_column_new_with_attributes(_("Placeholder"),
940  renderer, NULL);
941  gtk_tree_view_column_set_cell_data_func (column, renderer,
942  placeholder_cell_data_func,
943  (gpointer)data, NULL);
944  gnc_tree_view_append_column (GNC_TREE_VIEW(tree_view), column);
945  }
946 
947 
948  {
949  renderer = gtk_cell_renderer_text_new ();
950  g_object_set (G_OBJECT (renderer),
951  "xalign", 1.0,
952  (char *)NULL);
953  g_signal_connect (G_OBJECT (renderer), "edited",
954  G_CALLBACK (balance_cell_edited),
955  data);
956  column = gtk_tree_view_column_new_with_attributes (_("Opening Balance"),
957  renderer,
958  NULL);
959  gtk_tree_view_column_set_cell_data_func (column, renderer,
960  balance_cell_data_func,
961  (gpointer)data, NULL);
962  gnc_tree_view_append_column (GNC_TREE_VIEW(tree_view), column);
963  }
964 
965  // only in the case where there *are* existing accounts...
966  if (gnc_account_n_descendants(gnc_book_get_root_account(gnc_get_current_book())) > 0)
967  {
968  GList *renderers;
969  column = gnc_tree_view_add_text_column(GNC_TREE_VIEW(tree_view),
970  _("Use Existing"),
971  NULL,
972  NULL,
973  "yes",
974  GNC_TREE_VIEW_COLUMN_DATA_NONE,
975  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS,
976  NULL);
977  renderers = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(column));
978  g_object_set(G_OBJECT(renderer), "xalign", 1.0, (char*)NULL);
979  gtk_tree_view_column_set_cell_data_func(column, GTK_CELL_RENDERER(renderers->data),
980  use_existing_account_data_func, (gpointer)data, NULL);
981  g_list_free(renderers);
982  }
983 
984  gtk_container_add(GTK_CONTAINER(data->final_account_tree_container),
985  GTK_WIDGET(data->final_account_tree));
986 
987  /* Expand the entire tree */
988  gtk_tree_view_expand_all (tree_view);
989  gtk_widget_show(GTK_WIDGET(data->final_account_tree));
990  gnc_resume_gui_refresh ();
991 }
992 
993 void
994 on_cancel (GtkAssistant *gtkassistant,
995  hierarchy_data *data)
996 {
997  gnc_suspend_gui_refresh ();
998  if (data->new_book)
999  gtk_dialog_response(GTK_DIALOG(gnc_options_dialog_widget (data->optionwin)), GTK_RESPONSE_CANCEL);
1000  delete_hierarchy_dialog (data);
1001  delete_our_account_tree (data);
1002  g_free(data);
1003  gnc_resume_gui_refresh ();
1004 }
1005 
1006 static void
1007 finish_book_options_helper(GNCOptionWin * optionwin,
1008  gpointer user_data)
1009 {
1010  GNCOptionDB * options = user_data;
1011  QofBook *book = gnc_get_current_book ();
1012  gboolean use_split_action_for_num_before =
1014  gboolean use_split_action_for_num_after;
1015 
1016  if (!options) return;
1017 
1018  gnc_option_db_commit (options);
1019  qof_book_save_options (book, gnc_option_db_save_to_kvp, options, TRUE);
1020  use_split_action_for_num_after =
1022  if (use_split_action_for_num_before != use_split_action_for_num_after)
1023  gnc_book_option_num_field_source_change_cb (use_split_action_for_num_after);
1024 }
1025 
1026 static void
1027 starting_balance_helper (Account *account, hierarchy_data *data)
1028 {
1029  gnc_numeric balance;
1030 
1031  balance = get_final_balance (data->balance_hash, account);
1032  if (gnc_reverse_balance(account))
1033  balance = gnc_numeric_neg(balance);
1034  if (!gnc_numeric_zero_p (balance))
1035  gnc_account_create_opening_balance (account, balance, gnc_time (NULL),
1036  gnc_get_current_book ());
1037 }
1038 
1039 void
1040 on_finish (GtkAssistant *gtkassistant,
1041  hierarchy_data *data)
1042 {
1043  GncHierarchyAssistantFinishedCallback when_completed;
1044  gnc_commodity *com;
1045  Account * root;
1046  ENTER (" ");
1047  com = gnc_currency_edit_get_currency (GNC_CURRENCY_EDIT(data->currency_selector));
1048 
1049  if (data->our_account_tree)
1050  {
1051  gnc_account_foreach_descendant (data->our_account_tree,
1052  (AccountCb)starting_balance_helper,
1053  data);
1054 
1055 
1056  }
1057 
1058  /* Set book options based on the user's choices */
1059  if (data->new_book)
1060  finish_book_options_helper(data->optionwin, data->options);
1061 
1062  // delete before we suspend GUI events, and then muck with the model,
1063  // because the model doesn't seem to handle this correctly.
1064  if (data->initial_category)
1065  gtk_tree_row_reference_free(data->initial_category);
1066  delete_hierarchy_dialog (data);
1067 
1068  gnc_suspend_gui_refresh ();
1069  if (data->new_book)
1070  gtk_dialog_response(GTK_DIALOG(gnc_options_dialog_widget (data->optionwin)), GTK_RESPONSE_CANCEL);
1071 
1072  account_trees_merge(gnc_get_current_root_account(), data->our_account_tree);
1073 
1074  delete_our_account_tree (data);
1075 
1076  when_completed = data->when_completed;
1077  g_free(data);
1078 
1079  root = gnc_get_current_root_account();
1080  xaccAccountSetCommodity(root, com);
1081 
1082  gnc_resume_gui_refresh ();
1083 
1084  if (when_completed)
1085  {
1086  (*when_completed)();
1087  }
1088 
1089  LEAVE (" ");
1090 }
1091 
1092 /********************************************************
1093  * For a new book the assistant will also allow the user
1094  * to set default book options, because this impacts how
1095  * transactions are created.
1096  * Ideally, the book options code can cleanly provide us
1097  * with a page to insert in the assistant and be done with
1098  * it. Unfortunately this is not possible without a serious
1099  * rewrite of the options dialog code.
1100  * So instead the following hack is used:
1101  * we create the complete dialog, but only use the notebook
1102  * part of it to create a new page.
1103  * To make sure this dialog is cleaned up properly
1104  * when the assistant closes, the close callback is set up anyway
1105  * and at the finish we'll send a "close" response signal to the
1106  * dialog to make it clean up after itself.
1107  */
1108 static void
1109 book_options_dialog_close_cb(GNCOptionWin * optionwin,
1110  gpointer user_data)
1111 {
1112  GNCOptionDB * options = user_data;
1113 
1114  gnc_options_dialog_destroy(optionwin);
1115  gnc_option_db_destroy(options);
1116 }
1117 
1118 static void
1119 assistant_instert_book_options_page (hierarchy_data *data)
1120 {
1121  GtkWidget *vbox = gtk_vbox_new (FALSE, 0);
1122 
1123  data->options = gnc_option_db_new_for_type (QOF_ID_BOOK);
1124  qof_book_load_options (gnc_get_current_book (),
1125  gnc_option_db_load_from_kvp, data->options);
1126  gnc_option_db_clean (data->options);
1127 
1128  data->optionwin = gnc_options_dialog_new_modal (TRUE, _("New Book Options"));
1129  gnc_options_dialog_build_contents_full (data->optionwin, data->options, FALSE);
1130 
1131  gnc_options_dialog_set_close_cb (data->optionwin,
1132  book_options_dialog_close_cb,
1133  (gpointer)data->options);
1135 
1136  gtk_widget_reparent (gnc_options_dialog_notebook (data->optionwin), vbox);
1137  gtk_widget_show_all (vbox);
1138  gtk_assistant_insert_page (GTK_ASSISTANT(data->dialog), vbox, 2);
1139  gtk_assistant_set_page_title (GTK_ASSISTANT(data->dialog), vbox, _("New Book Options"));
1140  gtk_assistant_set_page_complete (GTK_ASSISTANT(data->dialog), vbox, TRUE);
1141 
1142 }
1143 
1144 static GtkWidget *
1145 gnc_create_hierarchy_assistant (gboolean use_defaults, GncHierarchyAssistantFinishedCallback when_completed)
1146 {
1147  hierarchy_data *data;
1148  GtkWidget *dialog;
1149  GtkTreeView *tree_view;
1150  GtkWidget *box;
1151  GtkBuilder *builder;
1152 
1153  data = g_new0 (hierarchy_data, 1);
1154 
1155  /* Presumably this assistant is only used to create a new book but we check.
1156  * When gnucash is started with --nofile, there is initially no session (and
1157  * no book), but by the time we get here, one could have been created (for
1158  * example, if an empty account tree tab is opened, a session is created
1159  * which creates a new, but empty, book). */
1160  data->new_book = gnc_is_new_book();
1161 
1162  builder = gtk_builder_new();
1163  gnc_builder_add_from_file (builder, "assistant-hierarchy.glade", "Hierarchy Assistant");
1164 
1165  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Hierarchy Assistant"));
1166  data->dialog = dialog;
1167 
1168  /* If we have a callback, make this window stay on top */
1169  if (when_completed != NULL)
1170  gtk_window_set_keep_above (GTK_WINDOW(data->dialog), TRUE);
1171 
1172  gnc_assistant_set_colors (GTK_ASSISTANT (data->dialog));
1173 
1174  /* Enable buttons on first and last page. */
1175  gtk_assistant_set_page_complete (GTK_ASSISTANT (dialog),
1176  GTK_WIDGET(gtk_builder_get_object(builder, "intro_page_label")),
1177  TRUE);
1178  gtk_assistant_set_page_complete (GTK_ASSISTANT (dialog),
1179  GTK_WIDGET(gtk_builder_get_object(builder, "currency_book_option_page_vbox")),
1180  TRUE);
1181  gtk_assistant_set_page_complete (GTK_ASSISTANT (dialog),
1182  GTK_WIDGET(gtk_builder_get_object(builder, "final_account_vbox")),
1183  TRUE);
1184  gtk_assistant_set_page_complete (GTK_ASSISTANT (dialog),
1185  GTK_WIDGET(gtk_builder_get_object(builder, "finish_page_label")),
1186  TRUE);
1187 
1188  /* Currency Page */
1189  data->currency_selector = gnc_currency_edit_new();
1190  gnc_currency_edit_set_currency (GNC_CURRENCY_EDIT(data->currency_selector), gnc_default_currency());
1191  gtk_widget_show (data->currency_selector);
1192  box = GTK_WIDGET(gtk_builder_get_object (builder, "currency_chooser_hbox"));
1193  gtk_box_pack_start(GTK_BOX(box), data->currency_selector, TRUE, TRUE, 0);
1194 
1195  /* Categories Page */
1196  tree_view = GTK_TREE_VIEW(gtk_builder_get_object (builder, "account_categories_tree_view"));
1197  g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (tree_view)), "changed",
1198  G_CALLBACK (categories_tree_selection_changed), data);
1199  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (tree_view), GTK_SELECTION_SINGLE);
1200  data->categories_tree = tree_view;
1201 
1202  data->category_accounts_label = GTK_LABEL(gtk_builder_get_object (builder, "accounts_in_category_label"));
1203  data->category_accounts_container = GTK_WIDGET(gtk_builder_get_object (builder, "accounts_in_category"));
1204  data->category_description = GTK_TEXT_VIEW(gtk_builder_get_object (builder, "account_types_description"));
1205  data->account_list_added = FALSE;
1206 
1207  /* Book options page - only on new books */
1208  if (data->new_book)
1209  assistant_instert_book_options_page (data);
1210 
1211  /* Final Accounts Page */
1212  data->final_account_tree_container = GTK_WIDGET(gtk_builder_get_object (builder, "final_account_tree_box"));
1213  data->final_account_tree = NULL;
1214 
1215  data->balance_hash = g_hash_table_new(NULL, NULL);
1216 
1217  gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(data->dialog));
1218 
1219  g_signal_connect (G_OBJECT(dialog), "destroy",
1220  G_CALLBACK (gnc_hierarchy_destroy_cb), data);
1221 
1222  gtk_builder_connect_signals(builder, data);
1223  g_object_unref(G_OBJECT(builder));
1224 
1225  data->when_completed = when_completed;
1226  data->use_defaults = use_defaults;
1227  return dialog;
1228 }
1229 
1230 GtkWidget*
1231 gnc_ui_hierarchy_assistant(gboolean use_defaults)
1232 {
1233  return gnc_create_hierarchy_assistant(use_defaults, NULL);
1234 }
1235 
1236 GtkWidget*
1237 gnc_ui_hierarchy_assistant_with_callback(gboolean use_defaults,
1238  GncHierarchyAssistantFinishedCallback when_finished)
1239 {
1240  return gnc_create_hierarchy_assistant(use_defaults, when_finished);
1241 }
1242 
1243 static void
1244 after_assistant(void)
1245 {
1246  qof_book_mark_session_dirty(gnc_get_current_book());
1247  gnc_ui_file_access_for_save_as();
1248 }
1249 
1250 static void
1251 gnc_ui_hierarchy_assistant_hook (void)
1252 {
1253  if (gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_SHOW_ON_NEW_FILE))
1254  {
1255  gnc_ui_hierarchy_assistant_with_callback(TRUE, after_assistant);
1256  }
1257 }
1258 
1259 void
1260 gnc_ui_hierarchy_assistant_initialize (void)
1261 {
1262  gnc_hook_add_dangler(HOOK_NEW_BOOK,
1263  (GFunc)gnc_ui_hierarchy_assistant_hook, NULL);
1264 }
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
gint gnc_account_n_descendants(const Account *account)
Definition: Account.c:2698
void gnc_currency_edit_set_currency(GNCCurrencyEdit *gce, const gnc_commodity *currency)
GtkTreeViewColumn * gnc_tree_view_add_text_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *stock_icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
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)
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
GHashTable * balance_hash
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)
void gnc_tree_view_set_show_column_menu(GncTreeView *view, gboolean visible)
GtkTreeViewColumn * gnc_tree_view_find_column_by_name(GncTreeView *view, const gchar *wanted)
#define ENTER(format, args...)
Definition: qoflog.h:261
Functions for adding content to a window.
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
Definition: Account.c:2803
#define PWARN(format, args...)
Definition: qoflog.h:243
gint gnc_tree_view_append_column(GncTreeView *view, GtkTreeViewColumn *column)
Currency selection widget.
gchar * gnc_account_get_full_name(const Account *account)
Definition: Account.c:3038
gnc_numeric gnc_numeric_convert(gnc_numeric n, gint64 denom, gint how)
GtkTreeView implementation for gnucash account tree.
void gnc_account_foreach_child(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2940
GtkTreeView * gnc_tree_view_account_new_with_root(Account *root, gboolean show_root)
void gnc_tree_view_configure_columns(GncTreeView *view)
gnc_commodity * gnc_currency_edit_get_currency(GNCCurrencyEdit *gce)
Account * gnc_tree_view_account_get_account_from_iter(GtkTreeModel *s_model, GtkTreeIter *s_iter)
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
Definition: Account.c:2915
Gnome specific utility functions.
Account * xaccCloneAccount(const Account *from, QofBook *book)
Definition: Account.c:1114
gint gnc_account_n_children(const Account *account)
Definition: Account.c:2676
All type declarations for the whole Gnucash engine.
void qof_book_mark_session_dirty(QofBook *book)
Generic api to store and retrieve preferences.
Functions providing a chart of account page.
GtkWidget * gnc_currency_edit_new(void)
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
void gnc_options_dialog_set_new_book_option_values(GNCOptionDB *odb)
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Account * gnc_tree_view_account_get_selected_account(GncTreeViewAccount *view)
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccAccountGetName(const Account *acc)
Definition: Account.c:3031
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
const gchar * QofLogModule
Definition: qofid.h:89
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389