GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-tree-model-account.c
1 /*
2  * gnc-tree-model-account.c -- GtkTreeModel implementation to
3  * display accounts in a GtkTreeView.
4  *
5  * Copyright (C) 2003 Jan Arne Petersen <[email protected]>
6  * Copyright (C) 2003 David Hampton <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, contact:
20  *
21  * Free Software Foundation Voice: +1-617-542-5942
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
23  * Boston, MA 02110-1301, USA [email protected]
24  */
25 
26 #include "config.h"
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <string.h>
31 
32 #include "gnc-tree-model-account.h"
33 #include "gnc-component-manager.h"
34 #include "Account.h"
35 #include "gnc-accounting-period.h"
36 #include "gnc-commodity.h"
37 #include "gnc-prefs.h"
38 #include "gnc-engine.h"
39 #include "gnc-event.h"
40 #include "gnc-gobject-utils.h"
41 #include "gnc-ui-balances.h"
42 #include "gnc-ui-util.h"
43 
44 #define TREE_MODEL_ACCOUNT_CM_CLASS "tree-model-account"
45 
47 static QofLogModule log_module = GNC_MOD_GUI;
48 
50 static void gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass);
51 static void gnc_tree_model_account_init (GncTreeModelAccount *model);
52 static void gnc_tree_model_account_finalize (GObject *object);
53 static void gnc_tree_model_account_dispose (GObject *object);
54 
56 static void gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface);
57 static GtkTreeModelFlags gnc_tree_model_account_get_flags (GtkTreeModel *tree_model);
58 static int gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model);
59 static GType gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model,
60  int index);
61 static gboolean gnc_tree_model_account_get_iter (GtkTreeModel *tree_model,
62  GtkTreeIter *iter,
63  GtkTreePath *path);
64 static GtkTreePath *gnc_tree_model_account_get_path (GtkTreeModel *tree_model,
65  GtkTreeIter *iter);
66 static void gnc_tree_model_account_get_value (GtkTreeModel *tree_model,
67  GtkTreeIter *iter,
68  int column,
69  GValue *value);
70 static gboolean gnc_tree_model_account_iter_next (GtkTreeModel *tree_model,
71  GtkTreeIter *iter);
72 static gboolean gnc_tree_model_account_iter_children (GtkTreeModel *tree_model,
73  GtkTreeIter *iter,
74  GtkTreeIter *parent);
75 static gboolean gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model,
76  GtkTreeIter *iter);
77 static int gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model,
78  GtkTreeIter *iter);
79 static gboolean gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model,
80  GtkTreeIter *iter,
81  GtkTreeIter *parent,
82  int n);
83 static gboolean gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model,
84  GtkTreeIter *iter,
85  GtkTreeIter *child);
86 
88 static void gnc_tree_model_account_event_handler (QofInstance *entity,
89  QofEventId event_type,
90  GncTreeModelAccount *model,
91  GncEventData *ed);
92 
95 {
96  QofBook *book;
97  Account *root;
98  gint event_handler_id;
99  const gchar *negative_color;
101 
102 #define GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(o) \
103  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_TREE_MODEL_ACCOUNT, GncTreeModelAccountPrivate))
104 
105 
106 /************************************************************/
107 /* Account Tree Model - Misc Functions */
108 /************************************************************/
109 
116 static void
117 gnc_tree_model_account_update_color (gpointer gsettings, gchar *key, gpointer user_data)
118 {
120  GncTreeModelAccount *model;
121  gboolean use_red;
122 
123  g_return_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(user_data));
124  model = user_data;
125  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
126  use_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
127  priv->negative_color = use_red ? "red" : NULL;
128 }
129 /************************************************************/
130 /* g_object required functions */
131 /************************************************************/
132 
134 static GtkObjectClass *parent_class = NULL;
135 
136 GType
138 {
139  static GType gnc_tree_model_account_type = 0;
140 
141  if (gnc_tree_model_account_type == 0)
142  {
143  static const GTypeInfo our_info =
144  {
145  sizeof (GncTreeModelAccountClass), /* class_size */
146  NULL, /* base_init */
147  NULL, /* base_finalize */
148  (GClassInitFunc) gnc_tree_model_account_class_init,
149  NULL, /* class_finalize */
150  NULL, /* class_data */
151  sizeof (GncTreeModelAccount), /* */
152  0, /* n_preallocs */
153  (GInstanceInitFunc) gnc_tree_model_account_init
154  };
155 
156  static const GInterfaceInfo tree_model_info =
157  {
158  (GInterfaceInitFunc) gnc_tree_model_account_tree_model_init,
159  NULL,
160  NULL
161  };
162 
163  gnc_tree_model_account_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
164  GNC_TREE_MODEL_ACCOUNT_NAME,
165  &our_info, 0);
166 
167  g_type_add_interface_static (gnc_tree_model_account_type,
168  GTK_TYPE_TREE_MODEL,
169  &tree_model_info);
170  }
171 
172  return gnc_tree_model_account_type;
173 }
174 
175 static void
176 gnc_tree_model_account_class_init (GncTreeModelAccountClass *klass)
177 {
178  GObjectClass *o_class;
179 
180  parent_class = g_type_class_peek_parent (klass);
181 
182  o_class = G_OBJECT_CLASS (klass);
183 
184  /* GObject signals */
185  o_class->finalize = gnc_tree_model_account_finalize;
186  o_class->dispose = gnc_tree_model_account_dispose;
187 
188  g_type_class_add_private(klass, sizeof(GncTreeModelAccountPrivate));
189 }
190 
191 static void
192 gnc_tree_model_account_init (GncTreeModelAccount *model)
193 {
195  gboolean red;
196 
197  ENTER("model %p", model);
198  while (model->stamp == 0)
199  {
200  model->stamp = g_random_int ();
201  }
202 
203  red = gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
204 
205  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
206  priv->book = NULL;
207  priv->root = NULL;
208  priv->negative_color = red ? "red" : NULL;
209 
210  gnc_prefs_register_cb(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
211  gnc_tree_model_account_update_color,
212  model);
213 
214  LEAVE(" ");
215 }
216 
217 static void
218 gnc_tree_model_account_finalize (GObject *object)
219 {
221  GncTreeModelAccount *model;
222 
223  g_return_if_fail (object != NULL);
224  g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object));
225 
226  ENTER("model %p", object);
227 
228  model = GNC_TREE_MODEL_ACCOUNT (object);
229  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
230 
231  priv->book = NULL;
232 
233  if (G_OBJECT_CLASS (parent_class)->finalize)
234  G_OBJECT_CLASS(parent_class)->finalize (object);
235  LEAVE(" ");
236 }
237 
238 static void
239 gnc_tree_model_account_dispose (GObject *object)
240 {
242  GncTreeModelAccount *model;
243 
244  g_return_if_fail (object != NULL);
245  g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (object));
246 
247  ENTER("model %p", object);
248 
249  model = GNC_TREE_MODEL_ACCOUNT (object);
250  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
251 
252  if (priv->event_handler_id)
253  {
254  qof_event_unregister_handler (priv->event_handler_id);
255  priv->event_handler_id = 0;
256  }
257 
258  gnc_prefs_remove_cb_by_func(GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED,
259  gnc_tree_model_account_update_color,
260  model);
261 
262  if (G_OBJECT_CLASS (parent_class)->dispose)
263  G_OBJECT_CLASS (parent_class)->dispose (object);
264  LEAVE(" ");
265 }
266 
267 
268 /************************************************************/
269 /* New Model Creation */
270 /************************************************************/
271 
272 GtkTreeModel *
274 {
275  GncTreeModelAccount *model;
277  const GList *item;
278 
279  ENTER("root %p", root);
280  item = gnc_gobject_tracking_get_list(GNC_TREE_MODEL_ACCOUNT_NAME);
281  for ( ; item; item = g_list_next(item))
282  {
283  model = (GncTreeModelAccount *)item->data;
284  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
285  if (priv->root == root)
286  {
287  g_object_ref(G_OBJECT(model));
288  LEAVE("returning existing model %p", model);
289  return GTK_TREE_MODEL(model);
290  }
291  }
292 
293  model = g_object_new (GNC_TYPE_TREE_MODEL_ACCOUNT,
294  NULL);
295 
296  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
297  priv->book = gnc_get_current_book();
298  priv->root = root;
299 
300  priv->event_handler_id = qof_event_register_handler
301  ((QofEventHandler)gnc_tree_model_account_event_handler, model);
302 
303  LEAVE("model %p", model);
304  return GTK_TREE_MODEL (model);
305 }
306 
307 
308 /************************************************************/
309 /* Gnc Tree Model Debugging Utility Function */
310 /************************************************************/
311 
312 #define ITER_STRING_LEN 128
313 
314 static const gchar *
315 iter_to_string (GtkTreeIter *iter)
316 {
317 #ifdef G_THREADS_ENABLED
318 #ifndef HAVE_GLIB_2_32
319  static GStaticPrivate gtmits_buffer_key = G_STATIC_PRIVATE_INIT;
320  gchar *string;
321 
322  string = g_static_private_get (&gtmits_buffer_key);
323  if (string == NULL)
324  {
325  string = g_malloc(ITER_STRING_LEN + 1);
326  g_static_private_set (&gtmits_buffer_key, string, g_free);
327  }
328 #else
329  static GPrivate gtmits_buffer_key = G_PRIVATE_INIT(g_free);
330  gchar *string;
331 
332  string = g_private_get (&gtmits_buffer_key);
333  if (string == NULL)
334  {
335  string = g_malloc(ITER_STRING_LEN + 1);
336  g_private_set (&gtmits_buffer_key, string);
337  }
338 #endif
339 #else
340  static char string[ITER_STRING_LEN + 1];
341 #endif
342 
343  if (iter)
344  snprintf(string, ITER_STRING_LEN,
345  "[stamp:%x data:%p (%s), %p, %d]",
346  iter->stamp, iter->user_data,
347  xaccAccountGetName ((Account *) iter->user_data),
348  iter->user_data2, GPOINTER_TO_INT(iter->user_data3));
349  else
350  strcpy(string, "(null)");
351  return string;
352 }
353 
354 
355 /************************************************************/
356 /* Gtk Tree Model Required Interface Functions */
357 /************************************************************/
358 
359 static void
360 gnc_tree_model_account_tree_model_init (GtkTreeModelIface *iface)
361 {
362  iface->get_flags = gnc_tree_model_account_get_flags;
363  iface->get_n_columns = gnc_tree_model_account_get_n_columns;
364  iface->get_column_type = gnc_tree_model_account_get_column_type;
365  iface->get_iter = gnc_tree_model_account_get_iter;
366  iface->get_path = gnc_tree_model_account_get_path;
367  iface->get_value = gnc_tree_model_account_get_value;
368  iface->iter_next = gnc_tree_model_account_iter_next;
369  iface->iter_children = gnc_tree_model_account_iter_children;
370  iface->iter_has_child = gnc_tree_model_account_iter_has_child;
371  iface->iter_n_children = gnc_tree_model_account_iter_n_children;
372  iface->iter_nth_child = gnc_tree_model_account_iter_nth_child;
373  iface->iter_parent = gnc_tree_model_account_iter_parent;
374 }
375 
376 static GtkTreeModelFlags
377 gnc_tree_model_account_get_flags (GtkTreeModel *tree_model)
378 {
379  return 0;
380 }
381 
382 static int
383 gnc_tree_model_account_get_n_columns (GtkTreeModel *tree_model)
384 {
385  g_return_val_if_fail(GNC_IS_TREE_MODEL_ACCOUNT(tree_model), -1);
386 
387  return GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS;
388 }
389 
390 static GType
391 gnc_tree_model_account_get_column_type (GtkTreeModel *tree_model,
392  int index)
393 {
394  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), G_TYPE_INVALID);
395  g_return_val_if_fail ((index < GNC_TREE_MODEL_ACCOUNT_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
396 
397  switch (index)
398  {
399  case GNC_TREE_MODEL_ACCOUNT_COL_NAME:
400  case GNC_TREE_MODEL_ACCOUNT_COL_TYPE:
401  case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY:
402  case GNC_TREE_MODEL_ACCOUNT_COL_CODE:
403  case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION:
404  case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT:
405  case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT:
406  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE:
407  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT:
408  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD:
409  case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
410  case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT:
411  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED:
412  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT:
413  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE:
414  case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN:
415  case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT:
416  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL:
417  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT:
418  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD:
419  case GNC_TREE_MODEL_ACCOUNT_COL_NOTES:
420  case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO:
421  case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT:
422  case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM:
423 
424  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT:
425  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_ACCOUNT:
426  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE:
427  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD:
428  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED:
429  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED:
430  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN:
431  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL:
432  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD:
433  return G_TYPE_STRING;
434 
435  case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER:
436  return G_TYPE_BOOLEAN;
437 
438  default:
439  g_assert_not_reached ();
440  return G_TYPE_INVALID;
441  }
442 }
443 
444 static gboolean
445 gnc_tree_model_account_get_iter (GtkTreeModel *tree_model,
446  GtkTreeIter *iter,
447  GtkTreePath *path)
448 {
450  GncTreeModelAccount *model;
451  Account *account, *parent;
452  gint i, *indices;
453 
454  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
455 
456  {
457  gchar *path_string = gtk_tree_path_to_string(path);
458  ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
459  g_free(path_string);
460  }
461 
462  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
463  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
464 
465  if (gtk_tree_path_get_depth (path) <= 0)
466  {
467  LEAVE("bad depth");
468  return FALSE;
469  }
470 
471  indices = gtk_tree_path_get_indices (path);
472  if (indices[0] != 0)
473  {
474  LEAVE("bad root index");
475  return FALSE;
476  }
477 
478  parent = NULL;
479  account = priv->root;
480  for (i = 1; i < gtk_tree_path_get_depth (path); i++)
481  {
482  parent = account;
483  account = gnc_account_nth_child(parent, indices[i]);
484  if (account == NULL)
485  {
486  iter->stamp = 0;
487  LEAVE("bad index");
488  return FALSE;
489  }
490  }
491 
492  iter->stamp = model->stamp;
493  iter->user_data = account;
494  iter->user_data2 = parent;
495  iter->user_data3 = GINT_TO_POINTER (indices[i - 1]);
496 
497  LEAVE("iter %s", iter_to_string(iter));
498  return TRUE;
499 }
500 
501 static GtkTreePath *
502 gnc_tree_model_account_get_path (GtkTreeModel *tree_model,
503  GtkTreeIter *iter)
504 {
505  GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
507  Account *account, *parent;
508  GtkTreePath *path;
509  gint i;
510 
511  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
512  g_return_val_if_fail (iter != NULL, NULL);
513  g_return_val_if_fail (iter->user_data != NULL, NULL);
514  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
515 
516  ENTER("model %p, iter %s", model, iter_to_string(iter));
517 
518  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
519  if (priv->root == NULL)
520  {
521  LEAVE("failed (1)");
522  return NULL;
523  }
524 
525  account = (Account *) iter->user_data;
526  parent = (Account *) iter->user_data2;
527 
528  path = gtk_tree_path_new ();
529  while (parent)
530  {
531  i = gnc_account_child_index(parent, account);
532  if (i == -1)
533  {
534  gtk_tree_path_free (path);
535  LEAVE("failed (3)");
536  return NULL;
537  }
538  gtk_tree_path_prepend_index (path, i);
539  account = parent;
540  parent = gnc_account_get_parent(account);
541  };
542 
543  /* Add the root node. */
544  gtk_tree_path_prepend_index (path, 0);
545 
546  {
547  gchar *path_string = gtk_tree_path_to_string(path);
548  LEAVE("path (4) %s", path_string);
549  g_free(path_string);
550  }
551  return path;
552 }
553 
554 static void
555 gnc_tree_model_account_set_color(GncTreeModelAccount *model,
556  gboolean negative,
557  GValue *value)
558 {
560 
561  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
562  if (negative)
563  g_value_set_static_string (value, priv->negative_color);
564  else
565  g_value_set_static_string (value, NULL);
566 }
567 
568 static gchar *
569 gnc_tree_model_account_compute_period_balance(GncTreeModelAccount *model,
570  Account *acct,
571  gboolean recurse,
572  gboolean *negative)
573 {
575  time64 t1, t2;
576  gnc_numeric b3;
577 
578  if ( negative )
579  *negative = FALSE;
580 
581  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
582  if (acct == priv->root)
583  return g_strdup("");
584 
585  t1 = gnc_accounting_period_fiscal_start();
586  t2 = gnc_accounting_period_fiscal_end();
587 
588  if (t1 > t2)
589  return g_strdup("");
590 
591  b3 = xaccAccountGetBalanceChangeForPeriod(acct, t1, t2, recurse);
592  if (gnc_reverse_balance (acct))
593  b3 = gnc_numeric_neg (b3);
594 
595  if (negative)
596  *negative = gnc_numeric_negative_p(b3);
597 
598  return g_strdup(xaccPrintAmount(b3, gnc_account_print_info(acct, TRUE)));
599 }
600 
601 static void
602 gnc_tree_model_account_get_value (GtkTreeModel *tree_model,
603  GtkTreeIter *iter,
604  int column,
605  GValue *value)
606 {
607  GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
609  Account *account;
610  gboolean negative; /* used to set "deficit style" also known as red numbers */
611  gchar *string;
612  time64 last_date;
613 
614  g_return_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model));
615  g_return_if_fail (iter != NULL);
616  g_return_if_fail (iter->user_data != NULL);
617  g_return_if_fail (iter->stamp == model->stamp);
618 
619  ENTER("model %p, iter %s, col %d", tree_model,
620  iter_to_string(iter), column);
621 
622  account = (Account *) iter->user_data;
623  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
624 
625  switch (column)
626  {
627  case GNC_TREE_MODEL_ACCOUNT_COL_NAME:
628  g_value_init (value, G_TYPE_STRING);
629  if (account == priv->root)
630  g_value_set_string (value, _("New top level account"));
631  else
632  g_value_set_string (value, xaccAccountGetName (account));
633  break;
634  case GNC_TREE_MODEL_ACCOUNT_COL_TYPE:
635  g_value_init (value, G_TYPE_STRING);
636  g_value_set_string (value,
638  break;
639  case GNC_TREE_MODEL_ACCOUNT_COL_CODE:
640  g_value_init (value, G_TYPE_STRING);
641  g_value_set_string (value, xaccAccountGetCode (account));
642  break;
643  case GNC_TREE_MODEL_ACCOUNT_COL_COMMODITY:
644  g_value_init (value, G_TYPE_STRING);
645  g_value_set_string (value,
647  break;
648  case GNC_TREE_MODEL_ACCOUNT_COL_DESCRIPTION:
649  g_value_init (value, G_TYPE_STRING);
650  g_value_set_string (value, xaccAccountGetDescription (account));
651  break;
652 
653  case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT:
654  g_value_init (value, G_TYPE_STRING);
655  string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency,
656  account, TRUE, &negative);
657  g_value_take_string (value, string);
658  break;
659  case GNC_TREE_MODEL_ACCOUNT_COL_PRESENT_REPORT:
660  g_value_init (value, G_TYPE_STRING);
661  string = gnc_ui_account_get_print_report_balance(xaccAccountGetPresentBalanceInCurrency,
662  account, TRUE, &negative);
663  g_value_take_string (value, string);
664  break;
665  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_PRESENT:
666  g_value_init (value, G_TYPE_STRING);
667  string = gnc_ui_account_get_print_balance(xaccAccountGetPresentBalanceInCurrency,
668  account, TRUE, &negative);
669  gnc_tree_model_account_set_color(model, negative, value);
670  g_free(string);
671  break;
672 
673  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE:
674  g_value_init (value, G_TYPE_STRING);
675  string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
676  account, TRUE, &negative);
677  g_value_take_string (value, string);
678  break;
679  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_REPORT:
680  g_value_init (value, G_TYPE_STRING);
681  string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency,
682  account, TRUE, &negative);
683  g_value_take_string (value, string);
684  break;
685  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE:
686  g_value_init (value, G_TYPE_STRING);
687  string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
688  account, TRUE, &negative);
689  gnc_tree_model_account_set_color(model, negative, value);
690  g_free(string);
691  break;
692  case GNC_TREE_MODEL_ACCOUNT_COL_BALANCE_PERIOD:
693  g_value_init (value, G_TYPE_STRING);
694  string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative);
695  g_value_take_string (value, string);
696  break;
697  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_BALANCE_PERIOD:
698  g_value_init (value, G_TYPE_STRING);
699  string = gnc_tree_model_account_compute_period_balance(model, account, FALSE, &negative);
700  gnc_tree_model_account_set_color(model, negative, value);
701  g_free (string);
702  break;
703 
704  case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED:
705  g_value_init (value, G_TYPE_STRING);
706  string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency,
707  account, TRUE, &negative);
708  g_value_take_string (value, string);
709  break;
710  case GNC_TREE_MODEL_ACCOUNT_COL_CLEARED_REPORT:
711  g_value_init (value, G_TYPE_STRING);
712  string = gnc_ui_account_get_print_report_balance(xaccAccountGetClearedBalanceInCurrency,
713  account, TRUE, &negative);
714  g_value_take_string (value, string);
715  break;
716  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_CLEARED:
717  g_value_init (value, G_TYPE_STRING);
718  string = gnc_ui_account_get_print_balance(xaccAccountGetClearedBalanceInCurrency,
719  account, TRUE, &negative);
720  gnc_tree_model_account_set_color(model, negative, value);
721  g_free(string);
722  break;
723 
724  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED:
725  g_value_init (value, G_TYPE_STRING);
726  string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency,
727  account, TRUE, &negative);
728  g_value_take_string (value, string);
729  break;
730  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_REPORT:
731  g_value_init (value, G_TYPE_STRING);
732  string = gnc_ui_account_get_print_report_balance(xaccAccountGetReconciledBalanceInCurrency,
733  account, TRUE, &negative);
734  g_value_take_string (value, string);
735  break;
736  case GNC_TREE_MODEL_ACCOUNT_COL_RECONCILED_DATE:
737  g_value_init (value, G_TYPE_STRING);
738  if (xaccAccountGetReconcileLastDate(account, &last_date))
739  {
740  g_value_take_string(value, qof_print_date(last_date));
741  }
742  break;
743 
744  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_RECONCILED:
745  g_value_init (value, G_TYPE_STRING);
746  string = gnc_ui_account_get_print_balance(xaccAccountGetReconciledBalanceInCurrency,
747  account, TRUE, &negative);
748  gnc_tree_model_account_set_color(model, negative, value);
749  g_free (string);
750  break;
751 
752  case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN:
753  g_value_init (value, G_TYPE_STRING);
754  string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
755  account, TRUE, &negative);
756  g_value_take_string (value, string);
757  break;
758  case GNC_TREE_MODEL_ACCOUNT_COL_FUTURE_MIN_REPORT:
759  g_value_init (value, G_TYPE_STRING);
760  string = gnc_ui_account_get_print_report_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
761  account, TRUE, &negative);
762  g_value_take_string (value, string);
763  break;
764  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_FUTURE_MIN:
765  g_value_init (value, G_TYPE_STRING);
766  string = gnc_ui_account_get_print_balance(xaccAccountGetProjectedMinimumBalanceInCurrency,
767  account, TRUE, &negative);
768  gnc_tree_model_account_set_color(model, negative, value);
769  g_free (string);
770  break;
771 
772  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL:
773  g_value_init (value, G_TYPE_STRING);
774  string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
775  account, TRUE, &negative);
776  g_value_take_string (value, string);
777  break;
778  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_REPORT:
779  g_value_init (value, G_TYPE_STRING);
780  string = gnc_ui_account_get_print_report_balance(xaccAccountGetBalanceInCurrency,
781  account, TRUE, &negative);
782  g_value_take_string (value, string);
783  break;
784  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL:
785  g_value_init (value, G_TYPE_STRING);
786  string = gnc_ui_account_get_print_balance(xaccAccountGetBalanceInCurrency,
787  account, TRUE, &negative);
788  gnc_tree_model_account_set_color(model, negative, value);
789  g_free (string);
790  break;
791  case GNC_TREE_MODEL_ACCOUNT_COL_TOTAL_PERIOD:
792  g_value_init (value, G_TYPE_STRING);
793  string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative);
794  g_value_take_string (value, string);
795  break;
796  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_TOTAL_PERIOD:
797  g_value_init (value, G_TYPE_STRING);
798  string = gnc_tree_model_account_compute_period_balance(model, account, TRUE, &negative);
799  gnc_tree_model_account_set_color(model, negative, value);
800  g_free (string);
801  break;
802 
803  case GNC_TREE_MODEL_ACCOUNT_COL_COLOR_ACCOUNT:
804  g_value_init (value, G_TYPE_STRING);
805  g_value_set_string (value, xaccAccountGetColor (account));
806  break;
807 
808  case GNC_TREE_MODEL_ACCOUNT_COL_NOTES:
809  g_value_init (value, G_TYPE_STRING);
810  g_value_set_string (value, xaccAccountGetNotes (account));
811  break;
812 
813  case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO:
814  g_value_init (value, G_TYPE_STRING);
815  g_value_take_string (value, gnc_ui_account_get_tax_info_string (account));
816  break;
817 
818  case GNC_TREE_MODEL_ACCOUNT_COL_TAX_INFO_SUB_ACCT:
819  g_value_init (value, G_TYPE_STRING);
820  g_value_take_string (value, gnc_ui_account_get_tax_info_sub_acct_string (account));
821  break;
822 
823  case GNC_TREE_MODEL_ACCOUNT_COL_LASTNUM:
824  g_value_init (value, G_TYPE_STRING);
825  g_value_set_string (value, xaccAccountGetLastNum (account));
826  break;
827 
828  case GNC_TREE_MODEL_ACCOUNT_COL_PLACEHOLDER:
829  g_value_init (value, G_TYPE_BOOLEAN);
830  g_value_set_boolean (value, xaccAccountGetPlaceholder (account));
831  break;
832 
833  default:
834  g_assert_not_reached ();
835  break;
836  }
837  LEAVE(" ");
838 }
839 
840 static gboolean
841 gnc_tree_model_account_iter_next (GtkTreeModel *tree_model,
842  GtkTreeIter *iter)
843 {
844  GncTreeModelAccount *model = GNC_TREE_MODEL_ACCOUNT (tree_model);
845  Account *account, *parent;
846  gint i;
847 
848  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE);
849  g_return_val_if_fail (iter != NULL, FALSE);
850  g_return_val_if_fail (iter->user_data != NULL, FALSE);
851  g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
852 
853  ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
854 
855  parent = (Account *) iter->user_data2;
856  if (parent == NULL)
857  {
858  /* This is the root. There is no next. */
859  LEAVE("at root");
860  return FALSE;
861  }
862 
863  /* Get the *next* sibling account. */
864  i = GPOINTER_TO_INT (iter->user_data3);
865  account = gnc_account_nth_child (parent, i + 1);
866  if (account == NULL)
867  {
868  iter->stamp = 0;
869  LEAVE("failed (3)");
870  return FALSE;
871  }
872 
873  iter->user_data = account;
874  iter->user_data2 = parent;
875  iter->user_data3 = GINT_TO_POINTER (i + 1);
876 
877  LEAVE("iter %s", iter_to_string(iter));
878  return TRUE;
879 }
880 
881 static gboolean
882 gnc_tree_model_account_iter_children (GtkTreeModel *tree_model,
883  GtkTreeIter *iter,
884  GtkTreeIter *parent_iter)
885 {
887  GncTreeModelAccount *model;
888  Account *account, *parent;
889 
890  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
891  ENTER("model %p, iter %p (to be filed in), parent %s",
892  tree_model, iter, (parent_iter ? iter_to_string(parent_iter) : "(null)"));
893 
894  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
895  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
896 
897  if (priv->root == NULL)
898  {
899  iter->stamp = 0;
900  LEAVE("failed (no root)");
901  return FALSE;
902  }
903 
904  /* Special case when no parent supplied. */
905  if (!parent_iter)
906  {
907  iter->user_data = priv->root;
908  iter->user_data2 = NULL;
909  iter->user_data3 = GINT_TO_POINTER (0);
910  iter->stamp = model->stamp;
911  LEAVE("iter (2) %s", iter_to_string(iter));
912  return TRUE;
913  }
914 
915  gnc_leave_return_val_if_fail (parent_iter != NULL, FALSE);
916  gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE);
917  gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE);
918 
919  parent = (Account *)parent_iter->user_data;
920  account = gnc_account_nth_child (parent, 0);
921 
922  if (account == NULL)
923  {
924  iter->stamp = 0;
925  LEAVE("failed (child account is null)");
926  return FALSE;
927  }
928 
929  iter->user_data = account;
930  iter->user_data2 = parent;
931  iter->user_data3 = GINT_TO_POINTER (0);
932  iter->stamp = model->stamp;
933  LEAVE("iter (3) %s", iter_to_string(iter));
934  return TRUE;
935 }
936 
937 static gboolean
938 gnc_tree_model_account_iter_has_child (GtkTreeModel *tree_model,
939  GtkTreeIter *iter)
940 {
941  GncTreeModelAccount *model;
942  Account *account;
943 
944  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
945 
946  ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
947 
948  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
949 
950  gnc_leave_return_val_if_fail (iter != NULL, FALSE);
951  gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE);
952  gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE);
953 
954  account = (Account *) iter->user_data;
955  if (gnc_account_n_children(account) > 0)
956  {
957  LEAVE("yes");
958  return TRUE;
959  }
960 
961  LEAVE("no");
962  return FALSE;
963 }
964 
965 static int
966 gnc_tree_model_account_iter_n_children (GtkTreeModel *tree_model,
967  GtkTreeIter *iter)
968 {
969  GncTreeModelAccount *model;
970  gint num;
971 
972  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
973  ENTER("model %p, iter %s", tree_model, iter_to_string(iter));
974 
975  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
976 
977  if (iter == NULL)
978  {
979  /* How many children does the invisible root node
980  * have. One! Its the real root account node. */
981  LEAVE("count is 1");
982  return 1;
983  }
984 
985  gnc_leave_return_val_if_fail (iter != NULL, FALSE);
986  gnc_leave_return_val_if_fail (iter->user_data != NULL, FALSE);
987  gnc_leave_return_val_if_fail (iter->stamp == model->stamp, FALSE);
988 
989  num = gnc_account_n_children(iter->user_data);
990  LEAVE("count is %d", num);
991  return num;
992 }
993 
994 static gboolean
995 gnc_tree_model_account_iter_nth_child (GtkTreeModel *tree_model,
996  GtkTreeIter *iter,
997  GtkTreeIter *parent_iter,
998  int n)
999 {
1000  GncTreeModelAccount *model;
1002  Account *account, *parent;
1003 
1004  if (parent_iter)
1005  {
1006  gchar *parent_string;
1007  parent_string = g_strdup(iter_to_string(parent_iter));
1008  ENTER("model %p, iter %s, parent_iter %s, n %d",
1009  tree_model, iter_to_string(iter),
1010  parent_string, n);
1011  g_free(parent_string);
1012  }
1013  else
1014  {
1015  ENTER("model %p, iter %s, parent_iter (null), n %d",
1016  tree_model, iter_to_string(iter), n);
1017  }
1018  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
1019 
1020  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
1021  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
1022 
1023  /* Special case when no parent supplied. */
1024  if (!parent_iter)
1025  {
1026  if (n != 0)
1027  {
1028  LEAVE("bad root index");
1029  return FALSE;
1030  }
1031 
1032  iter->user_data = priv->root;
1033  iter->user_data2 = NULL;
1034  iter->user_data3 = GINT_TO_POINTER (0);
1035  iter->stamp = model->stamp;
1036  LEAVE("root %s", iter_to_string(iter));
1037  return TRUE;
1038  }
1039 
1040  gnc_leave_return_val_if_fail (parent_iter->user_data != NULL, FALSE);
1041  gnc_leave_return_val_if_fail (parent_iter->stamp == model->stamp, FALSE);
1042 
1043  parent = (Account *)parent_iter->user_data;
1044  account = gnc_account_nth_child(parent, n);
1045  if (account == NULL)
1046  {
1047  iter->stamp = 0;
1048  LEAVE("failed (2)");
1049  return FALSE;
1050  }
1051 
1052  iter->user_data = account;
1053  iter->user_data2 = parent;
1054  iter->user_data3 = GINT_TO_POINTER (n);
1055  iter->stamp = model->stamp;
1056  LEAVE("iter (2) %s", iter_to_string(iter));
1057  return TRUE;
1058 }
1059 
1060 static gboolean
1061 gnc_tree_model_account_iter_parent (GtkTreeModel *tree_model,
1062  GtkTreeIter *iter,
1063  GtkTreeIter *child)
1064 {
1065  GncTreeModelAccount *model;
1066  Account *account, *parent;
1067  gint i;
1068 
1069  if (child)
1070  {
1071  gchar *child_string;
1072 
1073  child_string = g_strdup(iter_to_string(child));
1074  ENTER("model %p, iter %s, child %s",
1075  tree_model, iter_to_string(iter),
1076  child_string);
1077  g_free(child_string);
1078  }
1079  else
1080  {
1081  ENTER("model %p, iter %s, child (null)",
1082  tree_model, iter_to_string(iter));
1083  }
1084  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (tree_model), FALSE);
1085 
1086  model = GNC_TREE_MODEL_ACCOUNT (tree_model);
1087 
1088  gnc_leave_return_val_if_fail (child != NULL, FALSE);
1089  gnc_leave_return_val_if_fail (child->user_data != NULL, FALSE);
1090  gnc_leave_return_val_if_fail (child->stamp == model->stamp, FALSE);
1091 
1092  account = (Account *) child->user_data;
1093  account = gnc_account_get_parent(account);
1094  if (account == NULL)
1095  {
1096  /* Can't go up from the root node */
1097  iter->stamp = 0;
1098  LEAVE("failed (1)");
1099  return FALSE;
1100  }
1101 
1102  parent = gnc_account_get_parent(account);
1103  if (parent == NULL)
1104  {
1105  /* Now at the root. */
1106  i = 0;
1107  }
1108  else
1109  {
1110  i = gnc_account_child_index(parent, account);
1111  }
1112  iter->user_data = account;
1113  iter->user_data2 = parent;
1114  iter->user_data3 = GINT_TO_POINTER (i);
1115  iter->stamp = model->stamp;
1116  LEAVE("iter (2) %s", iter_to_string(iter));
1117  return TRUE;
1118 }
1119 
1120 
1121 /************************************************************/
1122 /* Account Tree View Filter Functions */
1123 /************************************************************/
1124 
1125 /*
1126  * Convert a model/iter pair to a gnucash account. This routine should
1127  * only be called from an account tree view filter function.
1128  */
1129 Account *
1131  GtkTreeIter *iter)
1132 {
1133  g_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
1134  g_return_val_if_fail (iter != NULL, NULL);
1135  g_return_val_if_fail (iter->user_data != NULL, NULL);
1136  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
1137 
1138  return (Account *) iter->user_data;
1139 }
1140 
1141 /*
1142  * Convert a model/account pair into a gtk_tree_model_iter. This
1143  * routine should only be called from the file
1144  * gnc-tree-view-account.c.
1145  */
1146 gboolean
1148  Account *account,
1149  GtkTreeIter *iter)
1150 {
1152  Account *parent;
1153  gint i;
1154 
1155  ENTER("model %p, account %p, iter %p", model, account, iter);
1156  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), FALSE);
1157  gnc_leave_return_val_if_fail ((account != NULL), FALSE);
1158  gnc_leave_return_val_if_fail ((iter != NULL), FALSE);
1159 
1160  iter->user_data = account;
1161  iter->stamp = model->stamp;
1162 
1163  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
1164  if (account == priv->root)
1165  {
1166  iter->user_data2 = NULL;
1167  iter->user_data3 = GINT_TO_POINTER (0);
1168  LEAVE("Matched root");
1169  return TRUE;
1170  }
1171 
1172  if (priv->root != gnc_account_get_root (account))
1173  {
1174  LEAVE("Root doesn't match");
1175  return FALSE;
1176  }
1177 
1178  parent = gnc_account_get_parent(account);
1179  i = gnc_account_child_index(parent, account);
1180  iter->user_data2 = parent;
1181  iter->user_data3 = GINT_TO_POINTER (i);
1182  LEAVE("iter %s", iter_to_string(iter));
1183  return (i != -1);
1184 }
1185 
1186 /*
1187  * Convert a model/account pair into a gtk_tree_model_path. This
1188  * routine should only be called from the file
1189  * gnc-tree-view-account.c.
1190  */
1191 GtkTreePath *
1193  Account *account)
1194 {
1195  GtkTreeIter tree_iter;
1196  GtkTreePath *tree_path;
1197 
1198  ENTER("model %p, account %p", model, account);
1199  gnc_leave_return_val_if_fail (GNC_IS_TREE_MODEL_ACCOUNT (model), NULL);
1200  gnc_leave_return_val_if_fail (account != NULL, NULL);
1201 
1202  if (!gnc_tree_model_account_get_iter_from_account (model, account,
1203  &tree_iter))
1204  {
1205  LEAVE("no iter");
1206  return NULL;
1207  }
1208 
1209  tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL(model), &tree_iter);
1210  if (tree_path)
1211  {
1212  gchar *path_string = gtk_tree_path_to_string(tree_path);
1213  LEAVE("path (2) %s", path_string);
1214  g_free(path_string);
1215  }
1216  else
1217  {
1218  LEAVE("no path");
1219  }
1220  return tree_path;
1221 }
1222 
1223 /************************************************************/
1224 /* Account Tree Model - Engine Event Handling Functions */
1225 /************************************************************/
1226 
1227 static void
1228 increment_stamp(GncTreeModelAccount *model)
1229 {
1230  do model->stamp++;
1231  while (!model->stamp);
1232 }
1233 
1234 static void
1235 propagate_change(GtkTreeModel *model, GtkTreePath *path, gint toggle_if_num)
1236 {
1237  GtkTreeIter iter;
1238 
1239  /* Already at the invisible root node? */
1240  if (!gtk_tree_path_up(path))
1241  return;
1242 
1243  /* Did we just move up to the invisible root node? */
1244  if (gtk_tree_path_get_depth(path) == 0)
1245  return;
1246 
1247  /* Handle the immediate parent */
1248  if (gtk_tree_model_get_iter(model, &iter, path))
1249  {
1250  gtk_tree_model_row_changed(model, path, &iter);
1251  if (gtk_tree_model_iter_n_children(model, &iter) == toggle_if_num)
1252  gtk_tree_model_row_has_child_toggled(model, path, &iter);
1253  }
1254 
1255  /* All other ancestors */
1256  while (gtk_tree_path_up(path) && gtk_tree_path_get_depth(path) > 0 &&
1257  gtk_tree_model_get_iter(model, &iter, path))
1258  {
1259  gtk_tree_model_row_changed(model, path, &iter);
1260  }
1261 }
1262 
1291 static void
1292 gnc_tree_model_account_event_handler (QofInstance *entity,
1293  QofEventId event_type,
1294  GncTreeModelAccount *model,
1295  GncEventData *ed)
1296 {
1298  const gchar *parent_name;
1299  GtkTreePath *path = NULL;
1300  GtkTreeIter iter;
1301  Account *account, *parent;
1302 
1303  g_return_if_fail(model); /* Required */
1304  if (!GNC_IS_ACCOUNT(entity))
1305  return;
1306 
1307  ENTER("entity %p of type %d, model %p, event_data %p",
1308  entity, event_type, model, ed);
1309  priv = GNC_TREE_MODEL_ACCOUNT_GET_PRIVATE(model);
1310 
1311  account = GNC_ACCOUNT(entity);
1312  if (gnc_account_get_book(account) != priv->book)
1313  {
1314  LEAVE("not in this book");
1315  return;
1316  }
1317  if (gnc_account_get_root(account) != priv->root)
1318  {
1319  LEAVE("not in this model");
1320  return;
1321  }
1322  /* What to do, that to do. */
1323  switch (event_type)
1324  {
1325  case QOF_EVENT_ADD:
1326  /* Tell the filters/views where the new account was added. */
1327  DEBUG("add account %p (%s)", account, xaccAccountGetName(account));
1328  path = gnc_tree_model_account_get_path_from_account(model, account);
1329  if (!path)
1330  {
1331  DEBUG("can't generate path");
1332  break;
1333  }
1334  increment_stamp(model);
1335  if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path))
1336  {
1337  DEBUG("can't generate iter");
1338  break;
1339  }
1340  gtk_tree_model_row_inserted (GTK_TREE_MODEL(model), path, &iter);
1341  propagate_change(GTK_TREE_MODEL(model), path, 1);
1342  break;
1343 
1344  case QOF_EVENT_REMOVE:
1345  if (!ed) /* Required for a remove. */
1346  break;
1347  parent = ed->node ? GNC_ACCOUNT(ed->node) : priv->root;
1348  parent_name = ed->node ? xaccAccountGetName(parent) : "Root";
1349  DEBUG("remove child %d of account %p (%s)", ed->idx, parent, parent_name);
1350  path = gnc_tree_model_account_get_path_from_account(model, parent);
1351  if (!path)
1352  {
1353  DEBUG("can't generate path");
1354  break;
1355  }
1356  increment_stamp(model);
1357  gtk_tree_path_append_index (path, ed->idx);
1358  gtk_tree_model_row_deleted (GTK_TREE_MODEL(model), path);
1359  propagate_change(GTK_TREE_MODEL(model), path, 0);
1360  break;
1361 
1362  case QOF_EVENT_MODIFY:
1363  DEBUG("modify account %p (%s)", account, xaccAccountGetName(account));
1364  path = gnc_tree_model_account_get_path_from_account(model, account);
1365  if (!path)
1366  {
1367  DEBUG("can't generate path");
1368  break;
1369  }
1370  if (!gnc_tree_model_account_get_iter(GTK_TREE_MODEL(model), &iter, path))
1371  {
1372  DEBUG("can't generate iter");
1373  break;
1374  }
1375  gtk_tree_model_row_changed(GTK_TREE_MODEL(model), path, &iter);
1376  propagate_change(GTK_TREE_MODEL(model), path, -1);
1377  break;
1378 
1379  default:
1380  LEAVE("unknown event type");
1381  return;
1382  }
1383 
1384  if (path)
1385  gtk_tree_path_free(path);
1386  LEAVE(" ");
1387  return;
1388 }
Account * gnc_account_get_parent(const Account *acc)
Definition: Account.c:2623
const char * xaccAccountGetLastNum(const Account *acc)
Definition: Account.c:4472
const GList * gnc_gobject_tracking_get_list(const gchar *name)
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
const char * xaccAccountGetCode(const Account *acc)
Definition: Account.c:3086
gnc_numeric gnc_numeric_neg(gnc_numeric a)
#define DEBUG(format, args...)
Definition: qoflog.h:255
Account * gnc_tree_model_account_get_account(GncTreeModelAccount *model, GtkTreeIter *iter)
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
#define ENTER(format, args...)
Definition: qoflog.h:261
#define gnc_leave_return_val_if_fail(test, val)
Definition: qoflog.h:283
gboolean gnc_tree_model_account_get_iter_from_account(GncTreeModelAccount *model, Account *account, GtkTreeIter *iter)
gboolean gnc_numeric_negative_p(gnc_numeric a)
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
const char * xaccAccountGetColor(const Account *acc)
Definition: Account.c:3100
char * qof_print_date(time64 secs)
GtkTreeModel implementation for gnucash account tree.
Account handling public routines.
gint QofEventId
Definition: qofevent.h:45
Gobject helper routines.
GtkTreeModel * gnc_tree_model_account_new(Account *root)
const char * xaccAccountGetDescription(const Account *acc)
Definition: Account.c:3093
General utilities for dealing with accounting periods.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
const char * gnc_commodity_get_fullname(const gnc_commodity *cm)
Additional event handling code.
gint gnc_account_n_children(const Account *account)
Definition: Account.c:2676
All type declarations for the whole Gnucash engine.
gboolean xaccAccountGetReconcileLastDate(const Account *acc, time64 *last_date)
Definition: Account.c:4264
Generic api to store and retrieve preferences.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
GtkTreePath * gnc_tree_model_account_get_path_from_account(GncTreeModelAccount *model, Account *account)
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
#define LEAVE(format, args...)
Definition: qoflog.h:271
Account * gnc_account_nth_child(const Account *parent, gint num)
Definition: Account.c:2691
gint gnc_account_child_index(const Account *parent, const Account *child)
Definition: Account.c:2683
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
const char * xaccAccountGetTypeStr(GNCAccountType type)
Definition: Account.c:4137
GType gnc_tree_model_account_get_type(void)
Commodity handling public routines.
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:148
const char * xaccAccountGetNotes(const Account *acc)
Definition: Account.c:3121