GnuCash  4.11-243-g1cac132214+
gnc-tree-model-split-reg.c
1 /********************************************************************\
2  * gnc-tree-model-split-reg.c -- GtkTreeView implementation to *
3  * display registers in a GtkTreeView. *
4  * *
5  * Copyright (C) 2006-2007 Chris Shoemaker <c.shoemaker@cox.net> *
6  * Copyright (C) 2012 Robert Fewell *
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 gnu@gnu.org *
24  * *
25 \********************************************************************/
26 
27 #include <config.h>
28 
29 #include <gtk/gtk.h>
30 #include <glib/gi18n.h>
31 #include <string.h>
32 
34 #include "gnc-component-manager.h"
35 #include "gnc-commodity.h"
36 #include "gnc-prefs.h"
37 #include "gnc-engine.h"
38 #include "gnc-event.h"
39 #include "gnc-gobject-utils.h"
40 #include "Query.h"
41 #include "Transaction.h"
42 #include "Scrub.h"
43 
44 #include "gnc-ui-util.h"
45 #include "engine-helpers.h"
46 
47 #define TREE_MODEL_SPLIT_REG_CM_CLASS "tree-model-split-reg"
48 
49 /* Signal codes */
50 enum
51 {
52  REFRESH_TRANS,
53  REFRESH_STATUS_BAR,
54  REFRESH_VIEW,
55  SCROLL_SYNC,
56  SELECTION_MOVE_DELETE,
57  LAST_SIGNAL
58 };
59 
60 
62 static QofLogModule log_module = GNC_MOD_LEDGER;
63 
65 static void gnc_tree_model_split_reg_class_init (GncTreeModelSplitRegClass *klass);
66 static void gnc_tree_model_split_reg_init (GncTreeModelSplitReg *model);
67 static void gnc_tree_model_split_reg_finalize (GObject *object);
68 static void gnc_tree_model_split_reg_dispose (GObject *object);
69 
70 static guint gnc_tree_model_split_reg_signals[LAST_SIGNAL] = {0};
71 
72 static const gchar *iter_to_string (GtkTreeIter *iter);
73 
75 static void gnc_tree_model_split_reg_tree_model_init (GtkTreeModelIface *iface);
76 
77 static GtkTreeModelFlags gnc_tree_model_split_reg_get_flags (GtkTreeModel *tree_model);
78 static int gnc_tree_model_split_reg_get_n_columns (GtkTreeModel *tree_model);
79 static GType gnc_tree_model_split_reg_get_column_type (GtkTreeModel *tree_model, int index);
80 static gboolean gnc_tree_model_split_reg_get_iter (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path);
81 static GtkTreePath *gnc_tree_model_split_reg_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter);
82 static void gnc_tree_model_split_reg_get_value (GtkTreeModel *tree_model, GtkTreeIter *iter, int column, GValue *value);
83 static gboolean gnc_tree_model_split_reg_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter);
84 static gboolean gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent);
85 static gboolean gnc_tree_model_split_reg_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter);
86 static int gnc_tree_model_split_reg_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter);
87 static gboolean gnc_tree_model_split_reg_iter_nth_child (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, int n);
88 static gboolean gnc_tree_model_split_reg_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child);
89 static void gtm_sr_increment_stamp (GncTreeModelSplitReg *model);
90 
91 
92 static void gtm_sr_insert_trans (GncTreeModelSplitReg *model, Transaction *trans, gboolean before);
93 static void gtm_sr_delete_trans (GncTreeModelSplitReg *model, Transaction *trans);
94 
96 static void gnc_tree_model_split_reg_event_handler (QofInstance *entity, QofEventId event_type, GncTreeModelSplitReg *model, GncEventData *ed);
97 
100 {
101  QofBook *book; // GNC Book
102  Account *anchor; // Account of register
103 
104  GList *full_tlist; // List of unique transactions derived from the query slist in same order
105  GList *tlist; // List of unique transactions derived from the full_tlist to display in same order
106  gint tlist_start; // The position of the first transaction in tlist in the full_tlist
107 
108  Transaction *btrans; // The Blank transaction
109 
110  Split *bsplit; // The Blank split
111  GList *bsplit_node; // never added to any list, just for representation of the iter
112  GList *bsplit_parent_node; // this equals the tnode of the transaction with the blank split
113 
114  gboolean display_subacc; // Are we displaying subaccounts
115  gboolean display_gl; // Is this the General ledger
116 
117  const GncGUID *template_account; // The template account which template transaction should belong to
118 
119  gpointer user_data; // User data for users of SplitRegisters, used to get parent window
120  SRGetParentCallback2 get_parent; // hook to get parent widget, used to get parent window
121 
122  GtkListStore *description_list; // description field autocomplete list
123  GtkListStore *notes_list; // notes field autocomplete list
124  GtkListStore *memo_list; // memo field autocomplete list
125  GtkListStore *action_list; // action combo list
126  GtkListStore *account_list; // Account combo list
127 
128  gint event_handler_id;
129 };
130 
131 
132 /* Define some background colors for the rows */
133 #define GREENROW "#BFDEB9"
134 #define TANROW "#F6FFDA"
135 #define SPLITROW "#EDE7D3"
136 #define YELLOWROW "#FFEF98"
137 
138 #define TROW1 0x1 // Transaction row 1 depth 1
139 #define TROW2 0x2 // Transaction row 2 depth 2
140 #define SPLIT 0x4 // Split row depth 3
141 #define BLANK 0x8 // Blank row
142 #define IS_TROW1(x) (GPOINTER_TO_INT((x)->user_data) & TROW1)
143 #define IS_TROW2(x) (GPOINTER_TO_INT((x)->user_data) & TROW2)
144 #define IS_BLANK(x) (GPOINTER_TO_INT((x)->user_data) & BLANK)
145 #define IS_SPLIT(x) (GPOINTER_TO_INT((x)->user_data) & SPLIT)
146 #define IS_BLANK_SPLIT(x) (IS_BLANK(x) && IS_SPLIT(x))
147 #define IS_BLANK_TRANS(x) (IS_BLANK(x) && !IS_SPLIT(x))
148 /* Meaning of user_data fields in iter struct:
149  *
150  * user_data: a bitfield for TROW1, TROW2, SPLIT, BLANK
151  * user_data2: a pointer to a node in a GList of Transactions
152  * user_data3: a pointer to a node in a GList of Splits.
153  *
154  */
155 
156 
157 /*FIXME This is the original define
158 #define VALID_ITER(model, iter) \
159  (GNC_IS_TREE_MODEL_TRANSACTION(model) && \
160  ((iter) && (iter)->user_data2) && \
161  ((iter)->stamp == (model)->stamp) && \
162  (!IS_SPLIT(iter) ^ ((iter)->user_data3 != NULL)) && \
163  (!IS_BLANK_SPLIT(iter) || \
164  ((iter)->user_data2 == (model)->priv->bsplit_parent_node)) \
165  )
166 */
167 
168 /*FIXME I thought this would work, it does not ????????? */
169 /* Do we need to test for a valid iter every where, is it enough to test on make iter ? */
170 #define VALID_ITER (model, iter) \
171  (GNC_IS_TREE_MODEL_SPLIT_REG (model) && \
172  ((iter).user_data != NULL) && ((iter).user_data2 != NULL) && (model->stamp == (gint)(iter).stamp) && \
173  ( (IS_SPLIT (iter) && (iter).user_data3) || (IS_BLANK_SPLIT (iter) && ((GList *)(iter).user_data2 == model->priv->bsplit_parent_node)) || \
174  (!IS_SPLIT (iter) && (iter).user_data2) || (IS_BLANK_TRANS (iter) && (iter).user_data3 == NULL)))
175 
176 
177 /* Used in the sort functions */
178 gboolean
179 gnc_tree_model_split_reg_is_blank_trans (GncTreeModelSplitReg *model, GtkTreeIter *iter)
180 {
181  return IS_BLANK_TRANS (iter);
182 }
183 
184 
185 /* Validate the iter */
186 static gboolean
187 gtm_sr_valid_iter (GncTreeModelSplitReg *model, GtkTreeIter *iter)
188 {
189  if (GNC_IS_TREE_MODEL_SPLIT_REG (model) && (iter->user_data != NULL) && (iter->user_data2 != NULL) && (model->stamp == (gint)iter->stamp)
190  && ( (IS_SPLIT (iter) && iter->user_data3) || (IS_BLANK_SPLIT (iter) && ((GList *)iter->user_data2 == model->priv->bsplit_parent_node))
191  || (!IS_SPLIT (iter) && iter->user_data2) || (IS_BLANK_TRANS (iter) && iter->user_data3 == NULL)))
192  return TRUE;
193  else
194  return FALSE;
195 }
196 
197 
198 /* Make an iter from the given parameters */
199 static GtkTreeIter
200 gtm_sr_make_iter (GncTreeModelSplitReg *model, gint f, GList *tnode, GList *snode)
201 {
202  GtkTreeIter iter, *iter_p;
203  iter_p = &iter;
204  iter.stamp = model->stamp;
205  iter.user_data = GINT_TO_POINTER(f);
206  iter.user_data2 = tnode;
207  iter.user_data3 = snode;
208 
209 //FIXME If I use this in place of 'if' below it works ??????
210 // if (!(GNC_IS_TREE_MODEL_SPLIT_REG (model) && (iter_p->user_data != NULL) && (iter_p->user_data2 != NULL) && (model->stamp == (gint)iter_p->stamp)
211 // && ( (IS_SPLIT (iter_p) && iter_p->user_data3) || (IS_BLANK_SPLIT (iter_p) && ((GList *)iter_p->user_data2 == model->priv->bsplit_parent_node))
212 // || (!IS_SPLIT (iter_p) && iter_p->user_data2) || (IS_BLANK_TRANS (iter_p) && iter_p->user_data3 == NULL) )))
213 
214 // if (!VALID_ITER (model, &iter))
215 
216  if (!(gtm_sr_valid_iter (model, iter_p)))
217  PERR ("Making invalid iter %s", iter_to_string (iter_p));
218  return iter;
219 }
220 
221 
222 #define GNC_TREE_MODEL_SPLIT_REG_GET_PRIVATE(o) \
223  ((GncTreeModelSplitRegPrivate*)gnc_tree_model_split_reg_get_instance_private((GncTreeModelSplitReg*)o))
224 
225 /************************************************************/
226 /* g_object required functions */
227 /************************************************************/
228 
230 static GObjectClass *parent_class = NULL;
231 
232 GType
234 {
235  static GType gnc_tree_model_split_reg_type = 0;
236 
237  if (gnc_tree_model_split_reg_type == 0)
238  {
239  static const GTypeInfo our_info =
240  {
241  sizeof (GncTreeModelSplitRegClass), /* class_size */
242  NULL, /* base_init */
243  NULL, /* base_finalize */
244  (GClassInitFunc) gnc_tree_model_split_reg_class_init,
245  NULL, /* class_finalize */
246  NULL, /* class_data */
247  sizeof (GncTreeModelSplitReg), /* */
248  0, /* n_preallocs */
249  (GInstanceInitFunc) gnc_tree_model_split_reg_init
250  };
251 
252  static const GInterfaceInfo tree_model_info =
253  {
254  (GInterfaceInitFunc) gnc_tree_model_split_reg_tree_model_init,
255  NULL,
256  NULL
257  };
258 
259  gnc_tree_model_split_reg_type = g_type_register_static (GNC_TYPE_TREE_MODEL,
260  GNC_TREE_MODEL_SPLIT_REG_NAME,
261  &our_info, 0);
262 
263  g_type_add_interface_static (gnc_tree_model_split_reg_type,
264  GTK_TYPE_TREE_MODEL,
265  &tree_model_info);
266  }
267  return gnc_tree_model_split_reg_type;
268 }
269 
270 
271 static void
272 gnc_tree_model_split_reg_class_init (GncTreeModelSplitRegClass *klass)
273 {
274  GObjectClass *o_class;
275 
276  parent_class = g_type_class_peek_parent (klass);
277 
278  o_class = G_OBJECT_CLASS (klass);
279 
280  /* GObject signals */
281  o_class->finalize = gnc_tree_model_split_reg_finalize;
282  o_class->dispose = gnc_tree_model_split_reg_dispose;
283 
284  gnc_tree_model_split_reg_signals[REFRESH_TRANS] =
285  g_signal_new("refresh_trans",
286  G_TYPE_FROM_CLASS (o_class),
287  G_SIGNAL_RUN_FIRST,
288  G_STRUCT_OFFSET (GncTreeModelSplitRegClass, refresh_trans),
289  NULL, NULL,
290  g_cclosure_marshal_VOID__POINTER,
291  G_TYPE_NONE,
292  1,
293  G_TYPE_POINTER);
294 
295  gnc_tree_model_split_reg_signals[REFRESH_STATUS_BAR] =
296  g_signal_new("refresh_status_bar",
297  G_TYPE_FROM_CLASS (o_class),
298  G_SIGNAL_RUN_LAST,
299  G_STRUCT_OFFSET (GncTreeModelSplitRegClass, refresh_status_bar),
300  NULL, NULL,
301  g_cclosure_marshal_VOID__VOID,
302  G_TYPE_NONE, 0);
303 
304  gnc_tree_model_split_reg_signals[REFRESH_VIEW] =
305  g_signal_new("refresh_view",
306  G_TYPE_FROM_CLASS (o_class),
307  G_SIGNAL_RUN_LAST,
308  G_STRUCT_OFFSET (GncTreeModelSplitRegClass, refresh_view),
309  NULL, NULL,
310  g_cclosure_marshal_VOID__VOID,
311  G_TYPE_NONE, 0);
312 
313  gnc_tree_model_split_reg_signals[SCROLL_SYNC] =
314  g_signal_new("scroll_sync",
315  G_TYPE_FROM_CLASS (o_class),
316  G_SIGNAL_RUN_LAST,
317  G_STRUCT_OFFSET (GncTreeModelSplitRegClass, scroll_sync),
318  NULL, NULL,
319  g_cclosure_marshal_VOID__VOID,
320  G_TYPE_NONE, 0);
321 
322  gnc_tree_model_split_reg_signals[SELECTION_MOVE_DELETE] =
323  g_signal_new("selection_move_delete",
324  G_TYPE_FROM_CLASS (o_class),
325  G_SIGNAL_RUN_FIRST,
326  G_STRUCT_OFFSET (GncTreeModelSplitRegClass, selection_move_delete),
327  NULL, NULL,
328  g_cclosure_marshal_VOID__POINTER,
329  G_TYPE_NONE,
330  1,
331  G_TYPE_POINTER);
332 
333  klass->refresh_trans = NULL;
334  klass->refresh_status_bar = NULL;
335  klass->refresh_view = NULL;
336  klass->scroll_sync = NULL;
337  klass->selection_move_delete = NULL;
338 }
339 
340 
341 static void
342 gnc_tree_model_split_reg_prefs_changed (gpointer prefs, gchar *pref, gpointer user_data)
343 {
344  GncTreeModelSplitReg *model = user_data;
345 
346  g_return_if_fail (pref);
347 
348  if (model == NULL)
349  return;
350 
351  if (g_str_has_suffix (pref, GNC_PREF_ACCOUNTING_LABELS))
352  {
353  model->use_accounting_labels = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS);
354  }
355  else if (g_str_has_suffix (pref, GNC_PREF_ACCOUNT_SEPARATOR))
356  {
357  model->separator_changed = TRUE;
358  }
359  else
360  {
361  g_warning("gnc_tree_model_split_reg_prefs_changed: Unknown preference %s", pref);
362  }
363 }
364 
365 
366 static void
367 gnc_tree_model_split_reg_init (GncTreeModelSplitReg *model)
368 {
369  ENTER("model %p", model);
370  while (model->stamp == 0)
371  {
372  model->stamp = g_random_int ();
373  }
374 
375  model->priv = g_new0 (GncTreeModelSplitRegPrivate, 1);
376 
377  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
378  GNC_PREF_ACCOUNTING_LABELS,
379  gnc_tree_model_split_reg_prefs_changed,
380  model);
381  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
382  GNC_PREF_ACCOUNT_SEPARATOR,
383  gnc_tree_model_split_reg_prefs_changed,
384  model);
385  LEAVE(" ");
386 }
387 
388 
389 static void
390 gnc_tree_model_split_reg_finalize (GObject *object)
391 {
392  ENTER("model split reg %p", object);
393  g_return_if_fail (object != NULL);
394  g_return_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (object));
395 
396  if (G_OBJECT_CLASS (parent_class)->finalize)
397  G_OBJECT_CLASS (parent_class)->finalize (object);
398  LEAVE(" ");
399 }
400 
401 
402 static void
403 gnc_tree_model_split_reg_dispose (GObject *object)
404 {
406  GncTreeModelSplitReg *model;
407 
408  ENTER("model split reg %p", object);
409  g_return_if_fail (object != NULL);
410  g_return_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (object));
411 
412  model = GNC_TREE_MODEL_SPLIT_REG (object);
413  priv = model->priv;
414 
415  if (priv->event_handler_id)
416  {
417  qof_event_unregister_handler (priv->event_handler_id);
418  priv->event_handler_id = 0;
419  }
420 
421  priv->book = NULL;
422 
423  /* Free the tlist */
424  g_list_free (priv->tlist);
425  priv->tlist = NULL;
426 
427  /* Free the full_tlist */
428  g_list_free (priv->full_tlist);
429  priv->full_tlist = NULL;
430 
431  /* Free the blank split */
432  priv->bsplit = NULL;
433  priv->bsplit_node = NULL;
434 
435  /* Free the blank transaction */
436  priv->btrans = NULL;
437 
438 /*FIXME Other stuff here */
439 
440  g_free (priv);
441 
442  if (G_OBJECT_CLASS (parent_class)->dispose)
443  G_OBJECT_CLASS (parent_class)->dispose (object);
444  LEAVE(" ");
445 }
446 
447 
448 /************************************************************/
449 /* New Model Creation */
450 /************************************************************/
451 /* Create a new tree model */
454  gboolean use_double_line, gboolean is_template, gboolean mismatched_commodities)
455 {
456  GncTreeModelSplitReg *model;
458 
459  ENTER("Create Model");
460 
461  model = g_object_new (GNC_TYPE_TREE_MODEL_SPLIT_REG, NULL);
462 
463  priv = model->priv;
464  priv->book = gnc_get_current_book();
465  priv->display_gl = FALSE;
466  priv->display_subacc = FALSE;
467 
468  model->type = reg_type;
469  model->style = style;
470  model->use_double_line = use_double_line;
471  model->is_template = is_template;
472  model->mismatched_commodities = mismatched_commodities;
473 
474  model->sort_col = 1;
475  model->sort_depth = 1;
476  model->sort_direction = GTK_SORT_ASCENDING;
477 
478  model->current_trans = NULL;
479  model->current_row = -1;
480 
481  /* Setup the blank transaction */
482  priv->btrans = xaccMallocTransaction (priv->book);
483 
484  /* Setup the blank split */
485  priv->bsplit = xaccMallocSplit (priv->book);
486  priv->bsplit_node = g_list_append (priv->bsplit_node, priv->bsplit);
487 
488  /* Setup some config entries */
489  model->use_accounting_labels = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_ACCOUNTING_LABELS);
490  model->use_gnc_color_theme = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_USE_GNUCASH_COLOR_THEME);
491  model->alt_colors_by_txn = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_ALT_COLOR_BY_TRANS);
492  model->read_only = FALSE;
493 
494  /* Create the ListStores for the auto completion / combo's */
495  priv->description_list = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
496  priv->notes_list = gtk_list_store_new (1, G_TYPE_STRING);
497  priv->memo_list = gtk_list_store_new (1, G_TYPE_STRING);
498  priv->action_list = gtk_list_store_new (1, G_TYPE_STRING);
499  priv->account_list = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
500 
501  priv->event_handler_id = qof_event_register_handler
502  ((QofEventHandler)gnc_tree_model_split_reg_event_handler, model);
503 
504  LEAVE("model %p", model);
505  return model;
506 }
507 
508 /* ForEach function to walk the list of model entries */
509 static gboolean
510 gtm_sr_foreach_func (GtkTreeModel *model,
511  GtkTreePath *path,
512  GtkTreeIter *iter,
513  GList **rowref_list)
514 {
515  GtkTreeRowReference *rowref;
516  g_assert ( rowref_list != NULL );
517 
518  rowref = gtk_tree_row_reference_new (model, path);
519  *rowref_list = g_list_prepend (*rowref_list, rowref);
520 
521  return FALSE; /* do not stop walking the store, call us with next row */
522 }
523 
524 /* Remove all model entries */
525 static void
526 gtm_sr_remove_all_rows (GncTreeModelSplitReg *model)
527 {
528  GList *rr_list = NULL; /* list of GtkTreeRowReferences to remove */
529  GList *node;
530 
531  gtk_tree_model_foreach (GTK_TREE_MODEL(model), (GtkTreeModelForeachFunc)gtm_sr_foreach_func, &rr_list);
532 
533  for ( node = rr_list; node != NULL; node = node->next )
534  {
535  GtkTreePath *path;
536  path = gtk_tree_row_reference_get_path ((GtkTreeRowReference*)node->data);
537 
538  if (path)
539  {
540  gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
541  gtk_tree_path_free (path);
542  }
543  }
544  g_list_foreach (rr_list, (GFunc) gtk_tree_row_reference_free, NULL);
545  g_list_free (rr_list);
546 }
547 
548 static void
549 gtm_sr_reg_load (GncTreeModelSplitReg *model, GncTreeModelSplitRegUpdate model_update, gint num_of_rows)
550 {
552  GList *node;
553  gint rows = 0;
554 
555  priv = model->priv;
556 
557  if (model_update == VIEW_HOME)
558  {
559  priv->tlist_start = 0;
560 
561  for (node = g_list_nth (priv->full_tlist, priv->tlist_start); node; node = node->next)
562  {
563  Transaction *trans = node->data;
564 
565  priv->tlist = g_list_append (priv->tlist, trans);
566  rows++;
567 
568  if (rows == num_of_rows)
569  break;
570  }
571  }
572 
573  if (model_update == VIEW_END)
574  {
575  priv->tlist_start = g_list_length (priv->full_tlist) - num_of_rows;
576 
577  for (node = g_list_nth (priv->full_tlist, priv->tlist_start); node; node = node->next)
578  {
579  Transaction *trans = node->data;
580 
581  priv->tlist = g_list_append (priv->tlist, trans);
582  rows++;
583 
584  if (rows == num_of_rows)
585  break;
586  }
587  }
588 
589  if (model_update == VIEW_GOTO)
590  {
591  priv->tlist_start = num_of_rows - NUM_OF_TRANS*1.5;
592 
593  for (node = g_list_nth (priv->full_tlist, priv->tlist_start); node; node = node->next)
594  {
595  Transaction *trans = node->data;
596 
597  priv->tlist = g_list_append (priv->tlist, trans);
598  rows++;
599 
600  if (rows == (NUM_OF_TRANS*3))
601  break;
602  }
603  }
604 }
605 
606 
607 /* Load the model with unique transactions based on a GList of splits */
608 void
609 gnc_tree_model_split_reg_load (GncTreeModelSplitReg *model, GList *slist, Account *default_account)
610 {
612 
613  ENTER("#### Load ModelSplitReg = %p and slist length is %d ####", model, g_list_length (slist));
614 
615  priv = model->priv;
616 
617  /* Clear the treeview */
618  gtm_sr_remove_all_rows (model);
619  priv->full_tlist = NULL;
620  priv->tlist = NULL;
621 
622  if (model->current_trans == NULL)
623  model->current_trans = priv->btrans;
624 
625  /* Get a list of Unique Transactions from an slist */
626  priv->full_tlist = xaccSplitListGetUniqueTransactionsReversed (slist);
627 
628  /* Add the blank transaction to the full_tlist */
629  priv->full_tlist = g_list_prepend (priv->full_tlist, priv->btrans);
630 
631  if (model->sort_direction == GTK_SORT_ASCENDING)
632  priv->full_tlist = g_list_reverse (priv->full_tlist);
633 
634  // Update the scrollbar
635  gnc_tree_model_split_reg_sync_scrollbar (model);
636 
637  model->number_of_trans_in_full_tlist = g_list_length (priv->full_tlist);
638 
639  if (model->number_of_trans_in_full_tlist < NUM_OF_TRANS*3)
640  {
641  // Copy the full_tlist to tlist
642  priv->tlist = g_list_copy (priv->full_tlist);
643  }
644  else
645  {
646  if (model->position_of_trans_in_full_tlist < (NUM_OF_TRANS*3))
647  gtm_sr_reg_load (model, VIEW_HOME, NUM_OF_TRANS*3);
648 
649  else if (model->position_of_trans_in_full_tlist >
650  model->number_of_trans_in_full_tlist - (NUM_OF_TRANS*3))
651  gtm_sr_reg_load (model, VIEW_END, NUM_OF_TRANS*3);
652 
653  else
654  gtm_sr_reg_load (model, VIEW_GOTO, model->position_of_trans_in_full_tlist);
655  }
656 
657  PINFO("#### Register for Account '%s' has %d transactions and %d splits and tlist is %d ####",
658  default_account ? xaccAccountGetName (default_account) : "NULL", g_list_length (priv->full_tlist), g_list_length (slist), g_list_length (priv->tlist));
659 
660  /* Update the completion model liststores */
661  g_idle_add ((GSourceFunc) gnc_tree_model_split_reg_update_completion, model);
662 
663  priv->anchor = default_account;
664  priv->bsplit_parent_node = NULL;
665 
666  LEAVE("#### Leave Model Load ####");
667 }
668 
669 
670 void
671 gnc_tree_model_split_reg_move (GncTreeModelSplitReg *model, GncTreeModelSplitRegUpdate model_update)
672 {
674  GList *inode, *dnode;
675  gint rows = 0;
676  gint icount = 0;
677  gint dcount = 0;
678 
679  priv = model->priv;
680 
681  // if list is not long enough, return
682  if (g_list_length (priv->full_tlist) < NUM_OF_TRANS*3)
683  return;
684 
685  if ((model_update == VIEW_UP) && (model->current_row < NUM_OF_TRANS) && (priv->tlist_start > 0))
686  {
687  gint dblock_end = 0;
688  gint iblock_start = priv->tlist_start - NUM_OF_TRANS;
689  gint iblock_end = priv->tlist_start - 1;
690  gint dblock_start = priv->tlist_start + NUM_OF_TRANS*2;
691 
692  if (iblock_start < 0)
693  iblock_start = 0;
694 
695  icount = iblock_end - iblock_start + 1;
696 
697  dcount = icount;
698  dblock_end = dblock_start + dcount - 1;
699 
700  priv->tlist_start = iblock_start;
701 
702  // Insert at the front end
703  for (inode = g_list_nth (priv->full_tlist, iblock_end); inode; inode = inode->prev)
704  {
705  Transaction *trans = inode->data;
706 
707  gtm_sr_insert_trans (model, trans, TRUE);
708 
709  rows++;
710 
711  if (rows == icount)
712  break;
713  }
714  rows = 0;
715  // Delete at the back end
716  for (dnode = g_list_nth (priv->full_tlist, dblock_end); dnode; dnode = dnode->prev)
717  {
718  Transaction *trans = dnode->data;
719 
720  gtm_sr_delete_trans (model, trans);
721 
722  rows++;
723 
724  if (rows == dcount)
725  break;
726  }
727  g_signal_emit_by_name (model, "refresh_view");
728  }
729 
730  if ((model_update == VIEW_DOWN) && (model->current_row > NUM_OF_TRANS*2) && (priv->tlist_start < (g_list_length (priv->full_tlist) - NUM_OF_TRANS*3 )))
731  {
732  gint dblock_end = 0;
733  gint iblock_start = priv->tlist_start + NUM_OF_TRANS*3;
734  gint iblock_end = iblock_start + NUM_OF_TRANS - 1;
735  gint dblock_start = priv->tlist_start;
736 
737  if (iblock_start < 0)
738  iblock_start = 0;
739 
740  if (iblock_end > g_list_length (priv->full_tlist))
741  iblock_end = g_list_length (priv->full_tlist) - 1;
742 
743  icount = iblock_end - iblock_start + 1;
744 
745  dcount = icount;
746  dblock_end = dblock_start + dcount;
747 
748  priv->tlist_start = dblock_end;
749 
750  // Insert at the back end
751  for (inode = g_list_nth (priv->full_tlist, iblock_start); inode; inode = inode->next)
752  {
753  Transaction *trans = inode->data;
754 
755  gtm_sr_insert_trans (model, trans, FALSE);
756 
757  rows++;
758 
759  if (rows == icount)
760  break;
761  }
762  rows = 0;
763  // Delete at the front end
764  for (dnode = g_list_nth (priv->full_tlist, dblock_start); dnode; dnode = dnode->next)
765  {
766  Transaction *trans = dnode->data;
767 
768  gtm_sr_delete_trans (model, trans);
769 
770  rows++;
771 
772  if (rows == dcount)
773  break;
774  }
775  g_signal_emit_by_name (model, "refresh_view");
776  }
777 }
778 
779 
780 /* Return the first transaction, opposite to blank transaction in the full list. */
781 Transaction *
783 {
785  GList *node;
786  Transaction *trans;
787 
788  priv = model->priv;
789 
790  node = g_list_first (priv->full_tlist);
791 
792  trans = node->data;
793 
794  if (trans == priv->btrans)
795  {
796  node = g_list_last (priv->full_tlist);
797  trans = node->data;
798  }
799  return trans;
800 }
801 
802 
803 /* Return TRUE if transaction is in the view list. */
804 gboolean
806 {
808 
809  priv = model->priv;
810 
811  if (g_list_index (priv->tlist, trans) == -1)
812  return FALSE;
813  else
814  return TRUE;
815 }
816 
817 
818 /* Return the tooltip for transaction at position in full_tlist. */
819 gchar *
820 gnc_tree_model_split_reg_get_tooltip (GncTreeModelSplitReg *model, gint position)
821 {
823  Transaction *trans;
824  char date_text[MAX_DATE_LENGTH + 1];
825  const gchar *desc_text;
826  GList *node;
827 
828  memset (date_text, 0, sizeof(date_text));
829  priv = model->priv;
830 
831  node = g_list_nth (priv->full_tlist, position);
832  if (node == NULL)
833  return g_strconcat ("Error", NULL);
834  else
835  {
836  trans = node->data;
837  if (trans == NULL)
838  return g_strconcat ("Error", NULL);
839  else if (trans == priv->btrans)
840  return g_strconcat ("Blank Transaction", NULL);
841  else
842  {
843  time64 t = xaccTransRetDatePosted (trans);
844  qof_print_date_buff (date_text, MAX_DATE_LENGTH, t);
845  desc_text = xaccTransGetDescription (trans);
846  model->current_trans = trans;
847  return g_strconcat (date_text, "\n", desc_text, NULL);
848  }
849  }
850 }
851 
852 
853 /* Set the current transaction to that at position in full_tlist */
854 void
855 gnc_tree_model_split_reg_set_current_trans_by_position (GncTreeModelSplitReg *model, gint position)
856 {
858  GList *node;
859 
860  priv = model->priv;
861 
862  node = g_list_nth (priv->full_tlist, position);
863  if (node == NULL)
864  node = g_list_last (priv->full_tlist);
865 
866  model->current_trans = node->data;
867 }
868 
869 
870 /* Sync the vertical scrollbar to position in full_tlist. */
871 void
872 gnc_tree_model_split_reg_sync_scrollbar (GncTreeModelSplitReg *model)
873 {
875 
876  priv = model->priv;
877 
878  model->position_of_trans_in_full_tlist = g_list_index (priv->full_tlist, model->current_trans);
879 
880  g_signal_emit_by_name (model, "scroll_sync");
881 }
882 
883 
884 /* Set the template account for this register. */
885 void
887 {
889 
890  priv = model->priv;
891  priv->template_account = xaccAccountGetGUID (template_account);
892 }
893 
894 
895 /* Return the template account for this register. */
896 Account *
898 {
900  Account *acct;
901 
902  priv = model->priv;
903 
904  acct = xaccAccountLookup (priv->template_account, priv->book);
905  return acct;
906 }
907 
908 
909 /* Return TRUE if this is a template register. */
910 gboolean
912 {
913  return model->is_template;
914 }
915 
916 
917 /* Destroy the model */
918 void
920 {
922 
923  ENTER("Model is %p", model);
924 
925  priv = model->priv;
926 
927  g_object_unref (priv->description_list);
928  g_object_unref (priv->notes_list);
929  g_object_unref (priv->memo_list);
930  g_object_unref (priv->action_list);
931  g_object_unref (priv->account_list);
932 
933  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
934  GNC_PREF_ACCOUNTING_LABELS,
935  gnc_tree_model_split_reg_prefs_changed,
936  model);
937  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
938  GNC_PREF_ACCOUNT_SEPARATOR,
939  gnc_tree_model_split_reg_prefs_changed,
940  model);
941  LEAVE(" ");
942 }
943 
944 
945 /* Setup the data to obtain the parent window */
946 void
948  SRGetParentCallback2 get_parent)
949 {
951 
952 /*FIXME This is used to get the parent window, maybe move to view */
953  priv = model->priv;
954 
955  priv->user_data = user_data;
956  priv->get_parent = get_parent;
957 }
958 
959 
960 /* Update the config of this model */
961 void
963  SplitRegisterStyle2 newstyle, gboolean use_double_line)
964 {
965  model->type = newtype;
966 
967  if (model->type >= NUM_SINGLE_REGISTER_TYPES2)
968  newstyle = REG2_STYLE_JOURNAL;
969 
970  model->style = newstyle;
971  model->use_double_line = use_double_line;
972 }
973 
974 
975 /* Return TRUE if this is a sub account view */
976 gboolean
977 gnc_tree_model_split_reg_get_sub_account (GncTreeModelSplitReg *model)
978 {
979  return model->priv->display_subacc;
980 }
981 
982 
983 void
985 {
986  GSList *p1 = NULL, *p2 = NULL, *standard;
987 
988  time64 start;
989  struct tm tm;
990 
991  standard = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
992 
993  PINFO("## gnc_tree_model_split_reg_update_query - query is %p ##", query);
994 
995  switch (model->sort_col)
996  {
997  case GNC_TREE_MODEL_SPLIT_REG_COL_DATE:
998  if (model->sort_depth == 1)
999  {
1000  p1 = g_slist_prepend (p1, TRANS_DATE_POSTED);
1001  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1002  p2 = standard;
1003  }
1004  else if (model->sort_depth == 2)
1005  {
1006  p1 = g_slist_prepend (p1, TRANS_DATE_ENTERED);
1007  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1008  p2 = standard;
1009  }
1010  else if (model->sort_depth == 3)
1011  {
1012  p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
1013  p1 = g_slist_prepend (p1, SPLIT_DATE_RECONCILED);
1014  p2 = standard;
1015  }
1016  break;
1017 
1018  case GNC_TREE_MODEL_SPLIT_REG_COL_DESCNOTES:
1019  if (model->sort_depth == 1)
1020  {
1021  p1 = g_slist_prepend (p1, TRANS_DESCRIPTION);
1022  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1023  p2 = standard;
1024  }
1025  else if (model->sort_depth == 2)
1026  {
1027  p1 = g_slist_prepend (p1, TRANS_NOTES);
1028  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1029  p2 = standard;
1030  }
1031  else if (model->sort_depth == 3)
1032  {
1033  p1 = g_slist_prepend (p1, SPLIT_MEMO);
1034  p2 = standard;
1035  }
1036  break;
1037 
1038  case GNC_TREE_MODEL_SPLIT_REG_COL_NUMACT:
1039  if (model->sort_depth == 1)
1040  {
1041  p1 = g_slist_prepend (p1, TRANS_NUM);
1042  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1043  p2 = standard;
1044  }
1045  else if ((model->sort_depth == 2) || (model->sort_depth == 3))
1046  {
1047  p1 = g_slist_prepend (p1, SPLIT_ACTION);
1048  p2 = standard;
1049  }
1050  break;
1051 
1052  case GNC_TREE_MODEL_SPLIT_REG_COL_RECN:
1053  {
1054  p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
1055  p1 = g_slist_prepend (p1, SPLIT_DATE_RECONCILED);
1056  p2 = standard;
1057  }
1058  break;
1059 
1060  case GNC_TREE_MODEL_SPLIT_REG_COL_DEBIT:
1061  case GNC_TREE_MODEL_SPLIT_REG_COL_CREDIT:
1062  {
1063  p1 = g_slist_prepend (p1, SPLIT_VALUE);
1064  p2 = standard;
1065  }
1066  break;
1067 
1068  default:
1069  p1 = standard;
1070  break;
1071  }
1072 
1073  //FIXME Not sure why I need to do this, refresh / sort change segfaults on gl
1074  if (model->priv->display_gl == TRUE && model->type == GENERAL_JOURNAL2)
1075  {
1077  tm.tm_mon--; /* Default the register to the last month's worth of transactions. */
1078  start = gnc_mktime (&tm);
1079  xaccQueryAddDateMatchTT (query, TRUE, start, FALSE, 0, QOF_QUERY_AND);
1080  }
1081 
1082  qof_query_set_sort_order (query, p1, p2, NULL);
1083 
1084 }
1085 
1086 /************************************************************/
1087 /* Gnc Tree Model Debugging Utility Function */
1088 /************************************************************/
1089 #define ITER_STRING_LEN 128
1090 
1091 static const gchar *
1092 iter_to_string (GtkTreeIter *iter)
1093 {
1094 #ifdef G_THREADS_ENABLED
1095  static GPrivate gtmits_buffer_key = G_PRIVATE_INIT (g_free);
1096  gchar *string;
1097 
1098  string = g_private_get (&gtmits_buffer_key);
1099  if (string == NULL)
1100  {
1101  string = g_malloc (ITER_STRING_LEN + 1);
1102  g_private_set (&gtmits_buffer_key, string);
1103  }
1104 #else
1105  static char string[ITER_STRING_LEN + 1];
1106 #endif
1107 
1108  if (iter)
1109  snprintf(
1110  string, ITER_STRING_LEN,
1111  "[stamp:%x data:%d, %p (%p:%s), %p (%p:%s)]",
1112  iter->stamp, GPOINTER_TO_INT (iter->user_data),
1113  iter->user_data2,
1114  iter->user_data2 ? ((GList *) iter->user_data2)->data : 0,
1115  iter->user_data2 ?
1116  (QOF_INSTANCE (((GList *) iter->user_data2)->data))->e_type : "",
1117  iter->user_data3,
1118  iter->user_data3 ? ((GList *) iter->user_data3)->data : 0,
1119  iter->user_data3 ?
1120  (QOF_INSTANCE (((GList *) iter->user_data3)->data))->e_type : "");
1121  else
1122  strcpy (string, "(null)");
1123  return string;
1124 }
1125 
1126 
1127 /************************************************************/
1128 /* Gtk Tree Model Required Interface Functions */
1129 /************************************************************/
1130 static void
1131 gnc_tree_model_split_reg_tree_model_init (GtkTreeModelIface *iface)
1132 {
1133  iface->get_flags = gnc_tree_model_split_reg_get_flags;
1134  iface->get_n_columns = gnc_tree_model_split_reg_get_n_columns;
1135  iface->get_column_type = gnc_tree_model_split_reg_get_column_type;
1136  iface->get_iter = gnc_tree_model_split_reg_get_iter;
1137  iface->get_path = gnc_tree_model_split_reg_get_path;
1138  iface->get_value = gnc_tree_model_split_reg_get_value;
1139  iface->iter_next = gnc_tree_model_split_reg_iter_next;
1140  iface->iter_children = gnc_tree_model_split_reg_iter_children;
1141  iface->iter_has_child = gnc_tree_model_split_reg_iter_has_child;
1142  iface->iter_n_children = gnc_tree_model_split_reg_iter_n_children;
1143  iface->iter_nth_child = gnc_tree_model_split_reg_iter_nth_child;
1144  iface->iter_parent = gnc_tree_model_split_reg_iter_parent;
1145 }
1146 
1147 
1148 static GtkTreeModelFlags
1149 gnc_tree_model_split_reg_get_flags (GtkTreeModel *tree_model)
1150 {
1151  /* Returns a set of flags supported by this interface. The flags
1152  are a bitwise combination of GtkTreeModelFlags. The flags supported
1153  should not change during the lifecycle of the tree_model. */
1154  return 0;
1155 }
1156 
1157 
1158 static int
1159 gnc_tree_model_split_reg_get_n_columns (GtkTreeModel *tree_model)
1160 {
1161  /* Returns the number of columns supported by tree_model. */
1162  g_return_val_if_fail(GNC_IS_TREE_MODEL_SPLIT_REG(tree_model), -1);
1163 
1164  return GNC_TREE_MODEL_SPLIT_REG_NUM_COLUMNS;
1165 }
1166 
1167 
1168 static GType
1169 gnc_tree_model_split_reg_get_column_type (GtkTreeModel *tree_model, int index)
1170 {
1171  /* Returns the type of the column. */
1172  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), G_TYPE_INVALID);
1173  g_return_val_if_fail ((index < GNC_TREE_MODEL_SPLIT_REG_NUM_COLUMNS) && (index >= 0), G_TYPE_INVALID);
1174 
1175  switch (index)
1176  {
1177  case GNC_TREE_MODEL_SPLIT_REG_COL_GUID:
1178  return G_TYPE_POINTER;
1179 
1180  case GNC_TREE_MODEL_SPLIT_REG_COL_DATE:
1181  case GNC_TREE_MODEL_SPLIT_REG_COL_DUEDATE:
1182  case GNC_TREE_MODEL_SPLIT_REG_COL_NUMACT:
1183  case GNC_TREE_MODEL_SPLIT_REG_COL_DESCNOTES:
1184  case GNC_TREE_MODEL_SPLIT_REG_COL_TRANSFERVOID:
1185  case GNC_TREE_MODEL_SPLIT_REG_COL_RECN:
1186  case GNC_TREE_MODEL_SPLIT_REG_COL_DEBIT:
1187  case GNC_TREE_MODEL_SPLIT_REG_COL_CREDIT:
1188  return G_TYPE_STRING;
1189 
1190  case GNC_TREE_MODEL_SPLIT_REG_COL_RO:
1191  case GNC_TREE_MODEL_SPLIT_REG_COL_NUM_VIS:
1192  case GNC_TREE_MODEL_SPLIT_REG_COL_ACT_VIS:
1193  return G_TYPE_BOOLEAN;
1194 
1195  default:
1196  g_assert_not_reached ();
1197  return G_TYPE_INVALID;
1198  }
1199 }
1200 
1201 
1202 static gboolean
1203 gnc_tree_model_split_reg_get_iter (GtkTreeModel *tree_model,
1204  GtkTreeIter *iter,
1205  GtkTreePath *path)
1206 {
1207  /* Sets iter to a valid iterator pointing to path. */
1208  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1209  GList *tnode;
1210  SplitList *slist;
1211  GList *snode;
1212  Split *split;
1213  gint depth, *indices, flags = 0;
1214 
1215  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), FALSE);
1216 
1217  {
1218  gchar *path_string = gtk_tree_path_to_string (path);
1219  //ENTER("model %p, iter %p, path %s", tree_model, iter, path_string);
1220  g_free (path_string);
1221  }
1222 
1223  depth = gtk_tree_path_get_depth (path);
1224 
1225  indices = gtk_tree_path_get_indices (path);
1226 
1227  tnode = g_list_nth (model->priv->tlist, indices[0]);
1228 
1229  if (!tnode) {
1230  DEBUG("path index off end of tlist");
1231  goto fail;
1232  }
1233 
1234  slist = xaccTransGetSplitList (tnode->data);
1235 
1236  if (depth == 1) { /* Trans Row 1 */
1237  flags = TROW1;
1238  /* Check if this is the blank trans */
1239  if (tnode->data == model->priv->btrans)
1240  {
1241  flags |= BLANK;
1242 
1243  if (xaccTransCountSplits (tnode->data) == 0)
1244  {
1245  if (model->priv->bsplit_parent_node == tnode)
1246  snode = model->priv->bsplit_node; // blank split
1247  else
1248  snode = NULL; // blank trans - not selected
1249  }
1250  else
1251  {
1252  split = xaccTransGetSplit (tnode->data, 0);
1253  snode = g_list_find (slist, split); // else first split
1254  }
1255  }
1256  else
1257  {
1258  split = xaccTransGetSplit (tnode->data, 0);
1259  snode = g_list_find (slist, split); // else first split
1260  }
1261  }
1262  else if (depth == 2) { /* Trans Row 2 */
1263  flags = TROW2;
1264  /* Check if this is the blank trans */
1265  if (tnode->data == model->priv->btrans)
1266  {
1267  flags |= BLANK;
1268 
1269  if (xaccTransCountSplits (tnode->data) == 0)
1270  {
1271  if (model->priv->bsplit_parent_node == tnode)
1272  snode = model->priv->bsplit_node; // blank split
1273  else
1274  snode = NULL; // blank trans - not selected
1275  }
1276  else
1277  {
1278  split = xaccTransGetSplit (tnode->data, 0);
1279  snode = g_list_find (slist, split); // else first split
1280  }
1281  }
1282  else
1283  {
1284  split = xaccTransGetSplit (tnode->data, 0);
1285  snode = g_list_find (slist, split); // else first split
1286  }
1287  }
1288  else if (depth == 3) { /* Split */
1289  flags = SPLIT;
1290 
1291  /* Check if this is the blank split */
1292  if ((tnode == model->priv->bsplit_parent_node) && (xaccTransCountSplits (tnode->data) == indices[2]))
1293  {
1294  flags |= BLANK;
1295  snode = model->priv->bsplit_node; // blank split = number of splits in list
1296  }
1297  else
1298  {
1299  split = xaccTransGetSplit (tnode->data, indices[2]);
1300  snode = g_list_find (slist, split); // split = position in list
1301  }
1302 
1303  if (!snode) {
1304  DEBUG("path index off end of slist");
1305  goto fail;
1306  }
1307  }
1308  else {
1309  DEBUG("Invalid path depth");
1310  goto fail;
1311  }
1312 
1313  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1314 /* g_assert(VALID_ITER(model, iter)); */
1315  //LEAVE("True");
1316  return TRUE;
1317  fail:
1318  iter->stamp = 0;
1319  //LEAVE("False");
1320  return FALSE;
1321 }
1322 
1323 
1324 static GtkTreePath *
1325 gnc_tree_model_split_reg_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter)
1326 {
1327  /* Returns a newly-created GtkTreePath referenced by iter.
1328  This path should be freed with gtk_tree_path_free(). */
1329  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1330  GtkTreePath *path;
1331  gint tpos = -1, spos = -1;
1332  GList *tnode, *snode;
1333 
1334  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
1335 
1336  //ENTER("model %p, iter %s", model, iter_to_string (iter));
1337 /* g_assert(VALID_ITER(model, iter)); */
1338 
1339  path = gtk_tree_path_new();
1340 
1341  tnode = iter->user_data2;
1342 
1343  snode = iter->user_data3;
1344 
1345  /* Level 1 */
1346  tpos = g_list_position (model->priv->tlist, tnode);
1347 
1348  if (tpos == -1)
1349  goto fail;
1350 
1351  gtk_tree_path_append_index (path, tpos);
1352 
1353  /* Level 2 - All ways 0 */
1354  if (IS_TROW2 (iter))
1355  gtk_tree_path_append_index (path, 0);
1356 
1357  /* Level 3 */
1358  if (IS_SPLIT (iter))
1359  {
1360  /* Check if this is the blank split */
1361  if ((tnode == model->priv->bsplit_parent_node) && (IS_BLANK (iter)))
1362  {
1363  spos = xaccTransCountSplits (tnode->data);
1364  }
1365  else if (tnode && snode)
1366  {
1367  /* Can not use snode position directly as slist length does not follow
1368  number of splits exactly, especially if you delete a split */
1369  spos = xaccTransGetSplitIndex (tnode->data, snode->data);
1370  }
1371 
1372  if (spos == -1)
1373  goto fail;
1374 
1375  gtk_tree_path_append_index (path, 0); /* Add the Level 2 part */
1376  gtk_tree_path_append_index (path, spos);
1377  }
1378 
1379  {
1380  gchar *path_string = gtk_tree_path_to_string (path);
1381  //LEAVE("get path %s", path_string);
1382  g_free (path_string);
1383  }
1384  return path;
1385 
1386  fail:
1387  //LEAVE("No Valid Path");
1388  return NULL;
1389 }
1390 
1391 
1392 /* Decide which renderer should be shown in the NUM/ACT column */
1393 static gboolean
1394 gnc_tree_model_split_reg_get_numact_vis (GncTreeModelSplitReg *model, gboolean trow1, gboolean trow2)
1395 {
1396  // TRUE for SHOW and FALSE for HIDE, TRUE for NUM is FALSE for ACT
1397 
1398  if (trow1)
1399  return TRUE;
1400 
1401  if (trow2)
1402  {
1403  if (qof_book_use_split_action_for_num_field (model->priv->book))
1404  return TRUE;
1405  else
1406  return FALSE;
1407  }
1408  return FALSE;
1409 }
1410 
1411 
1412 /* Return TRUE if this row should be marked read only */
1413 gboolean
1414 gnc_tree_model_split_reg_get_read_only (GncTreeModelSplitReg *model, Transaction *trans)
1415 {
1416  if (qof_book_is_readonly (model->priv->book)) // book is read only
1417  return TRUE;
1418 
1419  if (model->read_only) // register is read only
1420  return TRUE;
1421 
1422  /* Voided Transaction. */
1423  if (xaccTransHasSplitsInState (trans, VREC))
1424  return TRUE;
1425 
1426  if (qof_book_uses_autoreadonly (model->priv->book)) // use auto read only
1427  {
1428  if (trans == model->priv->btrans) // blank transaction
1429  return FALSE;
1430  else
1431  return xaccTransIsReadonlyByPostedDate (trans);
1432  }
1433  return FALSE;
1434 }
1435 
1436 
1437 /* Returns the row color */
1438 gchar*
1439 gnc_tree_model_split_reg_get_row_color (GncTreeModelSplitReg *model, gboolean is_trow1, gboolean is_trow2, gboolean is_split, gint num)
1440 {
1441 
1442  gchar *cell_color = NULL;
1443 
1444  if (model->use_gnc_color_theme)
1445  {
1446  if (model->use_double_line)
1447  {
1448  if (model->alt_colors_by_txn)
1449  {
1450  if (num % 2 == 0)
1451  {
1452  if (is_trow1 || is_trow2)
1453  cell_color = (gchar*)GREENROW;
1454  }
1455  else
1456  {
1457  if (is_trow1 || is_trow2)
1458  cell_color = (gchar*)TANROW;
1459  }
1460  }
1461  else
1462  {
1463  if (is_trow1)
1464  cell_color = (gchar*)GREENROW;
1465  else if (is_trow2)
1466  cell_color = (gchar*)TANROW;
1467  }
1468  }
1469  else
1470  {
1471  if (num % 2 == 0)
1472  {
1473  if (is_trow1)
1474  cell_color = (gchar*)GREENROW;
1475  else if (is_trow2)
1476  cell_color = (gchar*)TANROW;
1477  }
1478  else
1479  {
1480  if (is_trow1)
1481  cell_color = (gchar*)TANROW;
1482  else if (is_trow2)
1483  cell_color = (gchar*)GREENROW;
1484  }
1485  }
1486  if (is_split)
1487  cell_color = (gchar*)SPLITROW;
1488  }
1489  else
1490  cell_color = (gchar*)NULL;
1491 
1492  return cell_color;
1493 }
1494 
1495 
1496 static void
1497 gnc_tree_model_split_reg_get_value (GtkTreeModel *tree_model,
1498  GtkTreeIter *iter,
1499  int column,
1500  GValue *value)
1501 {
1502  /* Initializes and sets value to that at column. When done with value,
1503  g_value_unset() needs to be called to free any allocated memory. */
1504  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1505  const GncGUID *guid;
1506  GList *tnode;
1507 
1508  g_return_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model));
1509 
1510  //ENTER("model %p, iter %s, col %d", tree_model, iter_to_string (iter), column);
1511 
1512  tnode = (GList *) iter->user_data2;
1513 
1514  g_value_init (value, gnc_tree_model_split_reg_get_column_type (tree_model, column));
1515 
1516  switch (column)
1517  {
1518  case GNC_TREE_MODEL_SPLIT_REG_COL_GUID:
1519  guid = qof_entity_get_guid (QOF_INSTANCE (tnode->data));
1520  g_value_set_pointer (value, (gpointer) guid);
1521  break;
1522 
1523  case GNC_TREE_MODEL_SPLIT_REG_COL_DATE:
1524  break;
1525 
1526  case GNC_TREE_MODEL_SPLIT_REG_COL_DUEDATE:
1527  break;
1528 
1529  case GNC_TREE_MODEL_SPLIT_REG_COL_NUMACT:
1530  break;
1531 
1532  case GNC_TREE_MODEL_SPLIT_REG_COL_DESCNOTES:
1533  break;
1534 
1535  case GNC_TREE_MODEL_SPLIT_REG_COL_TRANSFERVOID:
1536  break;
1537 
1538  case GNC_TREE_MODEL_SPLIT_REG_COL_RECN:
1539  break;
1540 
1541  case GNC_TREE_MODEL_SPLIT_REG_COL_DEBIT:
1542  break;
1543 
1544  case GNC_TREE_MODEL_SPLIT_REG_COL_CREDIT:
1545  break;
1546 
1547  case GNC_TREE_MODEL_SPLIT_REG_COL_RO:
1548  g_value_set_boolean (value, gnc_tree_model_split_reg_get_read_only (model, tnode->data));
1549  break;
1550 
1551  case GNC_TREE_MODEL_SPLIT_REG_COL_NUM_VIS:
1552  g_value_set_boolean (value, gnc_tree_model_split_reg_get_numact_vis (model, IS_TROW1(iter), IS_TROW2(iter)));
1553  break;
1554 
1555  case GNC_TREE_MODEL_SPLIT_REG_COL_ACT_VIS:
1556  g_value_set_boolean (value, !gnc_tree_model_split_reg_get_numact_vis (model, IS_TROW1(iter), IS_TROW2(iter)));
1557  break;
1558 
1559  default:
1560  g_assert_not_reached ();
1561  }
1562  //LEAVE(" ");
1563 }
1564 
1565 
1566 static gboolean
1567 gnc_tree_model_split_reg_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
1568 {
1569  /* Sets iter to point to the node following it at the current level.
1570  If there is no next iter, FALSE is returned and iter is set to be
1571  invalid */
1572  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1573  Split *split;
1574  SplitList *slist;
1575  GList *tnode = NULL, *snode = NULL;
1576  gint flags = 0;
1577 
1578  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), FALSE);
1579 
1580  ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
1581 
1582  if (IS_TROW2 (iter)) {
1583  LEAVE("Transaction row 2 never has a next");
1584  goto fail;
1585  }
1586 
1587  if (IS_TROW1 (iter)) {
1588  flags = TROW1;
1589  tnode = iter->user_data2;
1590  tnode = g_list_next (tnode);
1591 
1592  if (!tnode) {
1593  LEAVE("last trans has no next");
1594  goto fail;
1595  }
1596 
1597  slist = xaccTransGetSplitList (tnode->data);
1598 
1599  /* Check if this is the blank trans */
1600  if (tnode->data == model->priv->btrans)
1601  {
1602  flags |= BLANK;
1603 
1604  if (xaccTransCountSplits (tnode->data) == 0)
1605  {
1606  if (model->priv->bsplit_parent_node == tnode)
1607  snode = model->priv->bsplit_node; // blank split
1608  else
1609  snode = NULL; // blank trans with no splits
1610  }
1611  else
1612  {
1613  split = xaccTransGetSplit (tnode->data, 0);
1614  snode = g_list_find (slist, split); // else first split
1615  }
1616  }
1617  else
1618  {
1619  split = xaccTransGetSplit (tnode->data, 0);
1620  snode = g_list_find (slist, split); // else first split
1621  }
1622  }
1623 
1624  if (IS_SPLIT (iter)) {
1625 
1626  gint i = 0;
1627  flags = SPLIT;
1628  tnode = iter->user_data2;
1629 
1630  if (IS_BLANK (iter)) {
1631  LEAVE("Blank split never has a next");
1632  goto fail;
1633  }
1634 
1635  slist = xaccTransGetSplitList (tnode->data);
1636  snode = iter->user_data3;
1637 
1638  i = xaccTransGetSplitIndex (tnode->data, snode->data);
1639  i++;
1640  split = xaccTransGetSplit (tnode->data, i);
1641  snode = g_list_find (slist, split);
1642 
1643  if (!snode) {
1644  if (tnode == model->priv->bsplit_parent_node) {
1645  snode = model->priv->bsplit_node;
1646  flags |= BLANK;
1647  } else {
1648  LEAVE("Last non-blank split has no next");
1649  goto fail;
1650  }
1651  }
1652  }
1653 
1654  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1655  LEAVE("iter %s", iter_to_string (iter));
1656  return TRUE;
1657  fail:
1658  iter->stamp = 0;
1659  return FALSE;
1660 }
1661 
1662 
1663 static gboolean
1664 gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model,
1665  GtkTreeIter *iter,
1666  GtkTreeIter *parent_iter)
1667 {
1668  /* Sets iter to point to the first child of parent. If parent has no children,
1669  FALSE is returned and iter is set to be invalid. Parent will remain a valid
1670  node after this function has been called. */
1671  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1672  GList *tnode = NULL, *snode = NULL;
1673  gint flags = 0;
1674  Split *split;
1675  SplitList *slist;
1676 
1677  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), FALSE);
1678  ENTER("model %p, iter %p , parent %s",
1679  tree_model, iter, (parent_iter ? iter_to_string (parent_iter) : "(null)"));
1680 
1681  if (!parent_iter) // special parent iter is NULL
1682  {
1683  /* Get the very first iter */
1684  tnode = g_list_first (model->priv->tlist);
1685  if (tnode)
1686  {
1687  flags = TROW1;
1688  slist = xaccTransGetSplitList (tnode->data);
1689  if (tnode->data == model->priv->btrans)
1690  {
1691  flags |= BLANK;
1692 
1693  if (xaccTransCountSplits (tnode->data) == 0)
1694  {
1695  if (model->priv->bsplit_parent_node == tnode)
1696  snode = model->priv->bsplit_node; // blank split
1697  else
1698  snode = NULL; // blank trans with no splits
1699  }
1700  else
1701  {
1702  split = xaccTransGetSplit (tnode->data, 0);
1703  snode = g_list_find (slist, split); // else first split
1704  }
1705  }
1706  else
1707  {
1708  split = xaccTransGetSplit (tnode->data, 0);
1709  snode = g_list_find (slist, split); // else first split
1710  }
1711 
1712  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1713  LEAVE("Parent iter NULL, First iter is %s", iter_to_string (iter));
1714  return TRUE;
1715  }
1716  else
1717  {
1718  PERR("We should never have a NULL trans list.");
1719  goto fail;
1720  }
1721  }
1722 
1723 /* g_assert(VALID_ITER(model, parent_iter)); */
1724 
1725  if (IS_TROW1 (parent_iter))
1726  {
1727  flags = TROW2;
1728  tnode = parent_iter->user_data2;
1729  slist = xaccTransGetSplitList (tnode->data);
1730 
1731  if (tnode->data == model->priv->btrans)
1732  {
1733  flags |= BLANK;
1734 
1735  if (xaccTransCountSplits (tnode->data) == 0)
1736  {
1737  if (model->priv->bsplit_parent_node == tnode)
1738  snode = model->priv->bsplit_node; // blank split
1739  else
1740  snode = NULL; // blank trans with no splits
1741  }
1742  else
1743  {
1744  split = xaccTransGetSplit (tnode->data, 0);
1745  snode = g_list_find (slist, split); // else first split
1746  }
1747  }
1748  else
1749  {
1750  split = xaccTransGetSplit (tnode->data, 0);
1751  snode = g_list_find (slist, split); // else first split
1752  }
1753  }
1754 
1755  if (IS_TROW2 (parent_iter))
1756  {
1757  tnode = parent_iter->user_data2;
1758 
1759  if ((tnode->data == model->priv->btrans) && (tnode != model->priv->bsplit_parent_node)) // blank trans has no split to start with
1760  goto fail;
1761  else if ((tnode->data != model->priv->btrans) && (xaccTransCountSplits (tnode->data) == 0) && (tnode != model->priv->bsplit_parent_node)) // trans has no splits after trans reinit.
1762  goto fail;
1763  else
1764  {
1765  flags = SPLIT;
1766  tnode = parent_iter->user_data2;
1767  slist = xaccTransGetSplitList (tnode->data);
1768 
1769  if (((tnode->data == model->priv->btrans) || (xaccTransCountSplits (tnode->data) == 0)) && (tnode == model->priv->bsplit_parent_node))
1770  {
1771  flags |= BLANK;
1772  snode = model->priv->bsplit_node; // blank split on blank trans
1773  }
1774  else
1775  {
1776  split = xaccTransGetSplit (tnode->data, 0);
1777  snode = g_list_find (slist, split); // else first split
1778  }
1779  }
1780  }
1781 
1782  if (IS_SPLIT (parent_iter)) // Splits do not have children
1783  goto fail;
1784 
1785  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1786  LEAVE("First Child iter is %s", iter_to_string (iter));
1787  return TRUE;
1788  fail:
1789  LEAVE("iter has no children");
1790  iter->stamp = 0;
1791  return FALSE;
1792 }
1793 
1794 
1795 static gboolean
1796 gnc_tree_model_split_reg_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *iter)
1797 {
1798  /* Returns TRUE if iter has children, FALSE otherwise. */
1799  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1800  GList *tnode;
1801 
1802  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), FALSE);
1803 
1804  ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
1805 
1806  tnode = iter->user_data2;
1807 
1808  if (IS_TROW1 (iter)) // Normal Transaction TROW1
1809  {
1810  LEAVE ("Transaction Row 1 is yes");
1811  return TRUE;
1812  }
1813 
1814  if (IS_TROW2 (iter) && !(IS_BLANK (iter))) // Normal Transaction TROW2
1815  {
1816  if (xaccTransCountSplits (tnode->data) != 0) // with splits
1817  {
1818  LEAVE ("Transaction Row 2 is yes");
1819  return TRUE;
1820  }
1821  else
1822  {
1823  if (tnode == model->priv->bsplit_parent_node) // with no splits, just blank split
1824  {
1825  LEAVE ("Transaction Row 2 is yes, blank split");
1826  return TRUE;
1827  }
1828  }
1829  }
1830 
1831  if (IS_TROW2 (iter) && IS_BLANK (iter) && (tnode == model->priv->bsplit_parent_node)) // Blank Transaction TROW2
1832  {
1833  LEAVE ("Blank Transaction Row 2 is yes");
1834  return TRUE;
1835  }
1836 
1837  LEAVE ("We have no child");
1838  return FALSE;
1839 }
1840 
1841 
1842 static int
1843 gnc_tree_model_split_reg_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *iter)
1844 {
1845  /* Returns the number of children that iter has. As a special case,
1846  if iter is NULL, then the number of toplevel nodes is returned. */
1847  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1848  GList *tnode;
1849  int i;
1850 
1851  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), FALSE);
1852  ENTER("model %p, iter %s", tree_model, iter_to_string (iter));
1853 
1854  if (iter == NULL) {
1855  i = g_list_length (model->priv->tlist);
1856  LEAVE ("toplevel count is %d", i);
1857  return i;
1858  }
1859 
1860  if (IS_SPLIT (iter))
1861  i = 0;
1862 
1863  if (IS_TROW1 (iter))
1864  i = 1;
1865 
1866  if (IS_TROW2 (iter))
1867  {
1868  tnode = iter->user_data2;
1869  i = xaccTransCountSplits (tnode->data);
1870  if (tnode == model->priv->bsplit_parent_node)
1871  i++;
1872  }
1873 
1874  LEAVE ("The number of children iter has is %d", i);
1875  return i;
1876 }
1877 
1878 
1879 static gboolean
1880 gnc_tree_model_split_reg_iter_nth_child (GtkTreeModel *tree_model,
1881  GtkTreeIter *iter,
1882  GtkTreeIter *parent_iter,
1883  int n)
1884 {
1885  /* Sets iter to be the n'th child of parent, using the given index. 0 > */
1886  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1887  Split *split;
1888  SplitList *slist;
1889  GList *tnode, *snode;
1890  gint flags = 0;
1891 
1892  ENTER("model %p, iter %s, n %d", tree_model, iter_to_string (parent_iter), n);
1893  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (tree_model), FALSE);
1894 
1895  if (parent_iter == NULL) { /* Top-level */
1896  flags = TROW1;
1897  tnode = g_list_nth (model->priv->tlist, n);
1898 
1899  if (!tnode) {
1900  PERR("Index greater than trans list.");
1901  goto fail;
1902  }
1903 
1904  slist = xaccTransGetSplitList (tnode->data);
1905 
1906  /* Check if this is the blank trans */
1907  if (tnode->data == model->priv->btrans)
1908  {
1909  flags |= BLANK;
1910 
1911  if (xaccTransCountSplits (tnode->data) == 0)
1912  {
1913  if (model->priv->bsplit_parent_node == tnode)
1914  snode = model->priv->bsplit_node; // blank split
1915  else
1916  snode = NULL; // blank trans with no splits
1917  }
1918  else
1919  {
1920  split = xaccTransGetSplit (tnode->data, 0);
1921  snode = g_list_find (slist, split); // else first split
1922  }
1923  }
1924  else
1925  {
1926  split = xaccTransGetSplit (tnode->data, 0);
1927  snode = g_list_find (slist, split); // else first split
1928  }
1929 
1930  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1931  LEAVE ("iter (2) %s", iter_to_string (iter));
1932  return TRUE;
1933  }
1934 
1935 /* g_assert(VALID_ITER(model, parent_iter)); */
1936 
1937  if (IS_SPLIT (parent_iter))
1938  goto fail; /* Splits have no children */
1939 
1940  if (IS_TROW1 (parent_iter) && (n != 0))
1941  goto fail; /* TROW1 has only one child */
1942 
1943  flags = TROW2;
1944  snode = NULL;
1945 
1946  tnode = parent_iter->user_data2;
1947 
1948  if (IS_TROW1 (parent_iter) && IS_BLANK (parent_iter))
1949  {
1950  flags |= BLANK;
1951  }
1952 
1953  if (IS_TROW2 (parent_iter) && (n > xaccTransCountSplits (tnode->data)))
1954  {
1955  goto fail;
1956  }
1957  else
1958  {
1959  if (tnode->data == model->priv->btrans)
1960  {
1961  snode = NULL;
1962  }
1963  else if ((tnode == model->priv->bsplit_parent_node) && (xaccTransCountSplits (tnode->data) == n))
1964  {
1965  flags = SPLIT | BLANK;
1966  snode = model->priv->bsplit_node;
1967  }
1968  else
1969  {
1970  flags = SPLIT;
1971  slist = xaccTransGetSplitList (tnode->data);
1972  split = xaccTransGetSplit (tnode->data, n);
1973  snode = g_list_find (slist, split);
1974  }
1975  }
1976 
1977  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
1978  LEAVE("iter of child with index %u is %s", n, iter_to_string (iter));
1979  return TRUE;
1980  fail:
1981  LEAVE("iter has no child with index %u", n);
1982  iter->stamp = 0;
1983  return FALSE;
1984 }
1985 
1986 
1987 static gboolean
1988 gnc_tree_model_split_reg_iter_parent (GtkTreeModel *tree_model,
1989  GtkTreeIter *iter,
1990  GtkTreeIter *child)
1991 {
1992  /* Sets iter to be the parent of child. If child is at the toplevel,
1993  and doesn't have a parent, then iter is set to an invalid iterator
1994  and FALSE is returned. Child will remain a valid node after this
1995  function has been called. */
1996  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tree_model);
1997  GList *tnode, *snode;
1998  gint flags = TROW1;
1999 
2000  ENTER("model %p, child %s", tree_model, iter_to_string (child));
2001 
2002 /* g_assert(VALID_ITER(model, child)); */
2003 
2004  tnode = child->user_data2;
2005  snode = child->user_data3;
2006 
2007  if (IS_TROW1 (child))
2008  goto fail;
2009 
2010  if (IS_TROW2 (child))
2011  flags = TROW1;
2012 
2013  if (IS_SPLIT (child))
2014  flags = TROW2;
2015 
2016  if (tnode->data == model->priv->btrans)
2017  flags |= BLANK;
2018 
2019  *iter = gtm_sr_make_iter (model, flags, tnode, snode);
2020  LEAVE("parent iter is %s", iter_to_string (iter));
2021  return TRUE;
2022  fail:
2023  LEAVE("we have no parent");
2024  iter->stamp = 0;
2025  return FALSE;
2026 }
2027 
2028 
2029 /*##########################################################################*/
2030 /* increment the stamp of the model */
2031 static void
2032 gtm_sr_increment_stamp (GncTreeModelSplitReg *model)
2033 {
2034  do model->stamp++;
2035  while (model->stamp == 0);
2036 }
2037 
2038 
2039 /* Return these values based on the model and iter provided */
2040 gboolean
2041 gnc_tree_model_split_reg_get_split_and_trans (
2042  GncTreeModelSplitReg *model, GtkTreeIter *iter,
2043  gboolean *is_trow1, gboolean *is_trow2, gboolean *is_split,
2044  gboolean *is_blank, Split **split, Transaction **trans)
2045 {
2046  GList *node;
2047 
2048 /* g_return_val_if_fail(VALID_ITER(model, iter), FALSE); */
2049  //ENTER("model pointer is %p", model);
2050  if (is_trow1)
2051  *is_trow1 = !!IS_TROW1(iter);
2052  if (is_trow2)
2053  *is_trow2 = !!IS_TROW2(iter);
2054  if (is_split)
2055  *is_split = !!IS_SPLIT(iter);
2056  if (is_blank)
2057  *is_blank = !!IS_BLANK(iter);
2058 
2059  if (trans)
2060  {
2061  node = iter->user_data2;
2062  *trans = node ? (Transaction *) node->data : NULL;
2063  }
2064 
2065  if (split)
2066  {
2067  node = iter->user_data3;
2068  *split = node ? (Split *) node->data : NULL;
2069  }
2070  //LEAVE("");
2071  return TRUE;
2072 }
2073 
2074 /* Return TRUE if blank_split is on trans */
2075 gboolean
2076 gnc_tree_model_split_reg_is_blank_split_parent (GncTreeModelSplitReg *model, Transaction *trans)
2077 {
2079  GList *node;
2080 
2081  priv = model->priv;
2082 
2083  node = priv->bsplit_parent_node;
2084 
2085  if (node == NULL)
2086  return FALSE;
2087 
2088  if (trans == priv->bsplit_parent_node->data)
2089  return TRUE;
2090  else
2091  return FALSE;
2092 }
2093 
2094 
2095 /* Return the tree path of trans and split
2096  if trans and split NULL, return blank trans in list */
2097 GtkTreePath *
2098 gnc_tree_model_split_reg_get_path_to_split_and_trans (GncTreeModelSplitReg *model, Split *split, Transaction *trans)
2099 {
2100  GtkTreePath *path;
2101  gint tpos, spos, number;
2102 
2103  ENTER("transaction is %p, split is %p", trans, split);
2104 
2105  path = gtk_tree_path_new();
2106 
2107  number = gnc_tree_model_split_reg_iter_n_children (GTK_TREE_MODEL (model), NULL) - 1;
2108 
2109  if (trans == NULL && split == NULL)
2110  {
2111  gchar *path_string;
2112 
2113  /* Level 1 */
2114  tpos = g_list_index (model->priv->tlist, model->priv->btrans);
2115  if (tpos == -1)
2116  tpos = number;
2117  gtk_tree_path_append_index (path, tpos);
2118 
2119  path_string = gtk_tree_path_to_string (path);
2120  LEAVE("path is %s", path_string);
2121  g_free (path_string);
2122  return path;
2123  }
2124 
2125  if (trans == NULL && split != NULL)
2126  {
2127  if (split == model->priv->bsplit)
2128  trans = model->priv->bsplit_parent_node->data;
2129  else
2130  trans = xaccSplitGetParent (split);
2131  }
2132 
2133  if (trans != NULL)
2134  {
2135  /* Level 1 */
2136  tpos = g_list_index (model->priv->tlist, trans);
2137  if (tpos == -1)
2138  tpos = number;
2139  gtk_tree_path_append_index (path, tpos);
2140  }
2141 
2142  if (split != NULL)
2143  {
2144  /* Level 3 */
2145  spos = xaccTransGetSplitIndex (trans, split);
2146  if (spos == -1)
2147  {
2148  if (model->priv->bsplit == split) // test for blank split
2149  spos = xaccTransCountSplits (trans);
2150  else
2151  spos = -1;
2152  }
2153  gtk_tree_path_append_index (path, 0); /* Level 2 */
2154  if (spos != -1)
2155  gtk_tree_path_append_index (path, spos);
2156  }
2157 
2158  {
2159  gchar *path_string = gtk_tree_path_to_string (path);
2160  LEAVE("path is %s", path_string);
2161  g_free (path_string);
2162  }
2163  return path;
2164 }
2165 
2166 
2167 #define get_iter gnc_tree_model_split_reg_get_iter_from_trans_and_split
2168 gboolean
2169 gnc_tree_model_split_reg_get_iter_from_trans_and_split (
2170  GncTreeModelSplitReg *model, Transaction *trans, Split *split,
2171  GtkTreeIter *iter1, GtkTreeIter *iter2)
2172 {
2174  GList *tnode, *snode = NULL;
2175  gint flags1 = TROW1;
2176  gint flags2 = TROW2;
2177 
2178  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), FALSE);
2179  g_return_val_if_fail (iter1, FALSE);
2180  g_return_val_if_fail (iter2, FALSE);
2181  PINFO("get_iter model %p, trans %p, split %p\n", model, trans, split);
2182 
2183  priv = model->priv;
2184  if (split && !trans)
2185  trans = xaccSplitGetParent (split);
2186 
2187  if (trans && priv->book != xaccTransGetBook (trans)) return FALSE;
2188  if (split && priv->book != xaccSplitGetBook (split)) return FALSE;
2189  if (split && !xaccTransStillHasSplit (trans, split)) return FALSE;
2190 
2191  tnode = g_list_find (priv->tlist, trans);
2192  if (!tnode) return FALSE;
2193 
2194  if (trans == priv->btrans)
2195  {
2196  flags1 |= BLANK;
2197  flags2 |= BLANK;
2198  }
2199 
2200  if (split)
2201  {
2202  GList *slist = xaccTransGetSplitList (trans);
2203  snode = g_list_find (slist, split);
2204  flags1 = SPLIT;
2205  if (!snode && split == (Split *) ((GList *)priv->bsplit_node)->data)
2206  {
2207  snode = priv->bsplit_node;
2208  flags1 |= BLANK;
2209  }
2210  if (!snode) return FALSE;
2211  }
2212 
2213  *iter1 = gtm_sr_make_iter (model, flags1, tnode, snode);
2214  *iter2 = gtm_sr_make_iter (model, flags2, tnode, snode);
2215 
2216  return TRUE;
2217 }
2218 
2219 
2220 /* Return the blank split */
2221 Split *
2222 gnc_tree_model_split_get_blank_split (GncTreeModelSplitReg *model)
2223 {
2224  return model->priv->bsplit;
2225 }
2226 
2227 
2228 /* Return the blank transaction */
2229 Transaction *
2230 gnc_tree_model_split_get_blank_trans (GncTreeModelSplitReg *model)
2231 {
2232  return model->priv->btrans;
2233 }
2234 
2235 
2236 /* Dummy Sort function */
2237 gint
2238 gnc_tree_model_split_reg_sort_iter_compare_func (GtkTreeModel *tm,
2239  GtkTreeIter *a,
2240  GtkTreeIter *b,
2241  gpointer user_data)
2242 {
2243  GncTreeModelSplitReg *model = GNC_TREE_MODEL_SPLIT_REG (tm);
2244 
2245  /* This is really a dummy sort function, it leaves the list as is. */
2246 
2247  if (model->sort_direction == GTK_SORT_ASCENDING)
2248  return gtk_tree_path_compare (gnc_tree_model_split_reg_get_path (tm, a),
2249  gnc_tree_model_split_reg_get_path (tm, b));
2250  else
2251  return gtk_tree_path_compare (gnc_tree_model_split_reg_get_path (tm, b),
2252  gnc_tree_model_split_reg_get_path (tm, a));
2253 }
2254 
2255 /*##########################################################################*/
2256 
2257 /* Update the parent when row changes made */
2258 static void
2259 gtm_sr_update_parent (GncTreeModelSplitReg *model, GtkTreePath *path)
2260 {
2261  GList *tnode;
2262  GtkTreeIter iter;
2263 
2264  ENTER(" ");
2265  if (gtk_tree_path_up (path) && gnc_tree_model_split_reg_get_iter (GTK_TREE_MODEL (model), &iter, path))
2266  {
2267  gchar *path_string = gtk_tree_path_to_string (path);
2268  PINFO("row_changed - '%s'", path_string);
2269  g_free (path_string);
2270 
2271  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
2272 
2273  tnode = iter.user_data2;
2274 
2275  /* If this is the blank transaction, the only split will be deleted, hence toggle has child */
2276  if (IS_BLANK_TRANS (&iter) && (tnode->data == model->priv->btrans) && (xaccTransCountSplits (model->priv->btrans) == 0))
2277  {
2278  gchar *path_string;
2279  path_string = gtk_tree_path_to_string (path);
2280  PINFO("toggling has_child at row '%s'", path_string);
2281  g_free (path_string);
2282  gtm_sr_increment_stamp (model);
2283  gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
2284  }
2285  }
2286  LEAVE(" ");
2287 }
2288 
2289 
2290 /* Insert row at iter */
2291 static void
2292 gtm_sr_insert_row_at (GncTreeModelSplitReg *model, GtkTreeIter *iter)
2293 {
2294  GtkTreePath *path;
2295 
2296 // g_assert (VALID_ITER (model, iter));
2297  ENTER(" ");
2298  path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), iter);
2299  if (!path)
2300  PERR("Null path");
2301 
2302  gtm_sr_increment_stamp (model);
2303  if (gnc_tree_model_split_reg_get_iter (GTK_TREE_MODEL (model), iter, path))
2304  {
2305  gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, iter);
2306  }
2307  else
2308  PERR("Tried to insert with invalid iter.");
2309 
2310  gtm_sr_update_parent (model, path);
2311  gtk_tree_path_free (path);
2312  LEAVE(" ");
2313 }
2314 
2315 
2316 /* Delete row at path */
2317 static void
2318 gtm_sr_delete_row_at_path (GncTreeModelSplitReg *model, GtkTreePath *path)
2319 {
2320  gint depth;
2321 
2322  ENTER(" ");
2323 
2324  if (!path)
2325  PERR("Null path");
2326 
2327  gtm_sr_increment_stamp (model);
2328  gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
2329 
2330  depth = gtk_tree_path_get_depth (path);
2331 
2332  if (depth == 2)
2333  {
2334  gtm_sr_update_parent (model, path);
2335  }
2336  else if (depth == 3)
2337  {
2338  gtm_sr_update_parent (model, path);
2339  }
2340  else
2341  {
2342  GtkTreeIter iter;
2343  if (gnc_tree_model_split_reg_get_iter (GTK_TREE_MODEL (model), &iter, path))
2344  {
2345  GList *tnode = iter.user_data2;
2346  GncTreeModelSplitRegPrivate *priv = model->priv;
2347  if (tnode == priv->bsplit_parent_node)
2348  priv->bsplit_parent_node = NULL;
2349  }
2350  }
2351  LEAVE(" ");
2352 }
2353 
2354 
2355 /* Delete row at iter */
2356 static void
2357 gtm_sr_delete_row_at (GncTreeModelSplitReg *model, GtkTreeIter *iter)
2358 {
2359  GtkTreePath *path;
2360 // g_assert(VALID_ITER (model, iter));
2361 
2362  ENTER(" ");
2363  path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), iter);
2364  gtm_sr_delete_row_at_path (model, path);
2365  gtk_tree_path_free (path);
2366  LEAVE(" ");
2367 }
2368 
2369 
2370 /* Change row at iter */
2371 static void
2372 gtm_sr_changed_row_at (GncTreeModelSplitReg *model, GtkTreeIter *iter)
2373 {
2374  GtkTreePath *path;
2375 // g_assert(VALID_ITER (model, iter));
2376 
2377  ENTER(" ");
2378  path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), iter);
2379  if (!path)
2380  PERR ("Null path");
2381 
2382  gtm_sr_increment_stamp (model);
2383  if (gnc_tree_model_split_reg_get_iter (GTK_TREE_MODEL (model), iter, path))
2384  {
2385  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter);
2386  }
2387  else
2388  PERR ("Tried to change with invalid iter.");
2389 
2390  gtk_tree_path_free (path);
2391  LEAVE(" ");
2392 }
2393 
2394 
2395 /* Insert transaction into model */
2396 static void
2397 gtm_sr_insert_trans (GncTreeModelSplitReg *model, Transaction *trans, gboolean before)
2398 {
2399  GtkTreeIter iter;
2400  GtkTreePath *path;
2401  GList *tnode = NULL, *snode = NULL;
2402 
2403  ENTER("insert transaction %p into model %p", trans, model);
2404  if (before == TRUE)
2405  model->priv->tlist = g_list_prepend (model->priv->tlist, trans);
2406  else
2407  model->priv->tlist = g_list_append (model->priv->tlist, trans);
2408  tnode = g_list_find (model->priv->tlist, trans);
2409 
2410  iter = gtm_sr_make_iter (model, TROW1, tnode, NULL);
2411  gtm_sr_insert_row_at (model, &iter);
2412 
2413  iter = gtm_sr_make_iter (model, TROW2, tnode, NULL);
2414  gtm_sr_insert_row_at (model, &iter);
2415  path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), &iter);
2416 
2417  gtk_tree_path_up (path); // to TROW1
2418  gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
2419  gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
2420 
2421  DEBUG("insert %d splits for transaction %p", xaccTransCountSplits (trans), trans);
2422 
2423  for (snode = xaccTransGetSplitList (trans); snode; snode = snode->next)
2424  {
2425  if (xaccTransStillHasSplit (trans, snode->data))
2426  {
2427  iter = gtm_sr_make_iter (model, SPLIT, tnode, snode);
2428  gtm_sr_insert_row_at (model, &iter);
2429  }
2430  }
2431  gtk_tree_path_down (path); // to TROW2
2432  gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
2433  gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
2434  gtk_tree_path_free (path);
2435 
2436  LEAVE(" ");
2437 }
2438 
2439 
2440 /* Delete transaction from model */
2441 static void
2442 gtm_sr_delete_trans (GncTreeModelSplitReg *model, Transaction *trans)
2443 {
2444  GtkTreeIter iter;
2445  GList *tnode = NULL, *snode = NULL;
2446 
2447  ENTER("delete trans %p", trans);
2448  tnode = g_list_find (model->priv->tlist, trans);
2449 
2450  DEBUG("tlist length is %d and no of splits is %d", g_list_length (model->priv->tlist), xaccTransCountSplits (trans));
2451 
2452  if (tnode == model->priv->bsplit_parent_node)
2453  {
2454  /* Delete the row where the blank split is. */
2455  iter = gtm_sr_make_iter (model, SPLIT | BLANK, tnode, model->priv->bsplit_node);
2456  gtm_sr_delete_row_at (model, &iter);
2457  model->priv->bsplit_parent_node = NULL;
2458  }
2459 
2460  for (snode = xaccTransGetSplitList (trans); snode; snode = snode->next)
2461  {
2462  if (xaccTransStillHasSplit (trans, snode->data))
2463  {
2464  iter = gtm_sr_make_iter (model, SPLIT, tnode, snode);
2465  gtm_sr_delete_row_at (model, &iter);
2466  }
2467  }
2468 
2469  iter = gtm_sr_make_iter (model, TROW2, tnode, NULL);
2470  gtm_sr_delete_row_at (model, &iter);
2471 
2472  iter = gtm_sr_make_iter (model, TROW1, tnode, NULL);
2473  gtm_sr_delete_row_at (model, &iter);
2474 
2475  model->priv->tlist = g_list_delete_link (model->priv->tlist, tnode);
2476  LEAVE(" ");
2477 }
2478 
2479 
2480 /* Moves the blank split to 'trans' and remove old one. */
2481 gboolean
2482 gnc_tree_model_split_reg_set_blank_split_parent (GncTreeModelSplitReg *model, Transaction *trans, gboolean remove_only)
2483 {
2484  GList *tnode, *bs_parent_node;
2486  GtkTreeIter iter;
2487  gboolean moved;
2488 
2489  priv = model->priv;
2490 
2491  if (trans == NULL)
2492  tnode = g_list_last (priv->tlist);
2493  else
2494  tnode = g_list_find (priv->tlist, trans);
2495 
2496  ENTER("set blank split %p parent to trans %p and remove_only is %d", priv->bsplit, trans, remove_only);
2497 
2498  bs_parent_node = priv->bsplit_parent_node;
2499 
2500  if (tnode != bs_parent_node || remove_only == TRUE)
2501  {
2502  moved = (bs_parent_node != NULL || remove_only == TRUE);
2503  if (moved)
2504  {
2505  /* Delete the row where the blank split used to be. */
2506  iter = gtm_sr_make_iter (model, SPLIT | BLANK, bs_parent_node, priv->bsplit_node);
2507  gtm_sr_delete_row_at (model, &iter);
2508  priv->bsplit_parent_node = NULL;
2509 
2510  }
2511  if (remove_only == FALSE)
2512  {
2513  /* Create the row where the blank split will be. */
2514  priv->bsplit_parent_node = tnode;
2515  iter = gtm_sr_make_iter (model, SPLIT | BLANK, tnode, priv->bsplit_node);
2516  gtm_sr_insert_row_at (model, &iter);
2517  xaccSplitReinit (priv->bsplit); // set split back to default entries
2518  }
2519  }
2520  else
2521  moved = FALSE;
2522 
2523  LEAVE(" ");
2524  return moved;
2525 }
2526 
2527 
2528 /* Make a new blank split and insert at iter */
2529 static void
2530 gtm_sr_make_new_blank_split (GncTreeModelSplitReg *model)
2531 {
2532  GtkTreeIter iter;
2533  Split *split;
2534  GList *tnode = model->priv->bsplit_parent_node;
2535 
2536  ENTER("");
2537 
2538  split = xaccMallocSplit (model->priv->book);
2539  model->priv->bsplit = split;
2540  model->priv->bsplit_node->data = model->priv->bsplit;
2541 
2542  DEBUG("make new blank split %p and insert at trans %p", split, tnode->data);
2543 
2544  /* Insert the new blank split */
2545  iter = gtm_sr_make_iter (model, BLANK|SPLIT, tnode, model->priv->bsplit_node);
2546  gtm_sr_insert_row_at (model, &iter);
2547  LEAVE("");
2548 }
2549 
2550 
2551 /* Turn the current blank split into a real split. This function is
2552  * never called in response to an engine event. Instead, this
2553  * function is called from the treeview to tell the model to commit
2554  * the blank split.
2555  */
2556 void
2558 {
2559  Split *bsplit;
2560  GList *tnode, *snode;
2561  GtkTreeIter iter;
2562 
2563  ENTER(" ");
2564 
2565  tnode = model->priv->bsplit_parent_node;
2566  bsplit = model->priv->bsplit;
2567 
2568  if (!tnode || !tnode->data) {
2569  LEAVE("blank split has no trans");
2570  return;
2571  }
2572 
2573  if (xaccTransGetSplitIndex (tnode->data, bsplit) == -1) {
2574  LEAVE("blank split has been removed from this trans");
2575  return;
2576  }
2577 
2578  snode = g_list_find (xaccTransGetSplitList (tnode->data), bsplit);
2579  if (!snode) {
2580  LEAVE("Failed to turn blank split into real split");
2581  return;
2582  }
2583 
2584  /* If we haven't set an amount yet, and there's an imbalance, use that. */
2585  if (gnc_numeric_zero_p (xaccSplitGetAmount (bsplit)))
2586  {
2587  gnc_numeric imbal = gnc_numeric_neg (xaccTransGetImbalanceValue (tnode->data));
2588  if (!gnc_numeric_zero_p (imbal))
2589  {
2590  gnc_numeric amount, rate;
2591  Account *acct = xaccSplitGetAccount (bsplit);
2592  xaccSplitSetValue (bsplit, imbal);
2593 
2595  {
2596  amount = imbal;
2597  }
2598  else
2599  {
2600  rate = xaccTransGetAccountConvRate (tnode->data, acct);
2601  amount = gnc_numeric_mul (imbal, rate, xaccAccountGetCommoditySCU (acct), GNC_HOW_RND_ROUND);
2602  }
2603  if (gnc_numeric_check (amount) == GNC_ERROR_OK)
2604  {
2605  xaccSplitSetAmount (bsplit, amount);
2606  }
2607  }
2608  }
2609  /* Mark the old blank split as changed */
2610  iter = gtm_sr_make_iter (model, SPLIT, tnode, snode);
2611  gtm_sr_changed_row_at (model, &iter);
2612  gtm_sr_make_new_blank_split (model);
2613 
2614  LEAVE(" ");
2615 }
2616 
2617 
2618 /* Update the display sub account and general journal settings */
2619 void
2620 gnc_tree_model_split_reg_set_display (GncTreeModelSplitReg *model, gboolean subacc, gboolean gl)
2621 {
2622  GncTreeModelSplitRegPrivate *priv = model->priv;
2623 
2624  priv->display_subacc = subacc;
2625  priv->display_gl = gl;
2626 }
2627 
2628 
2629 /* Returns just the path to the transaction if idx_of_split is -1. */
2630 static GtkTreePath *
2631 gtm_sr_get_removal_path (GncTreeModelSplitReg *model, Transaction *trans,
2632  gint idx_of_split)
2633 {
2635  GList *tnode = NULL;
2636  GtkTreeIter iter;
2637  GtkTreePath *path;
2638 
2639  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2640  g_return_val_if_fail (trans, NULL);
2641 
2642  priv = model->priv;
2643  if (priv->book != xaccTransGetBook (trans))
2644  return FALSE;
2645 
2646  tnode = g_list_find (priv->tlist, trans);
2647  if (!tnode)
2648  return FALSE;
2649 
2650  iter = gtm_sr_make_iter (model, TROW1, tnode, NULL); // TROW1
2651  path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), &iter);
2652 
2653  if (idx_of_split >= 0)
2654  {
2655  gtk_tree_path_append_index (path, 0); // TROW2
2656  gtk_tree_path_append_index (path, idx_of_split); //SPLIT
2657  }
2658  else if (idx_of_split != -1)
2659  PERR("Invalid idx_of_split");
2660 
2661  return path;
2662 }
2663 
2664 
2665 /*##########################################################################*/
2666 /* Combo and Autocompletion ListStore functions */
2667 
2668 Account *
2670 {
2671  g_return_val_if_fail(GNC_IS_TREE_MODEL_SPLIT_REG(model), NULL);
2672  return model->priv->anchor;
2673 }
2674 
2675 GtkListStore *
2676 gnc_tree_model_split_reg_get_description_list (GncTreeModelSplitReg *model)
2677 {
2678  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2679  return model->priv->description_list;
2680 }
2681 
2682 GtkListStore *
2683 gnc_tree_model_split_reg_get_notes_list (GncTreeModelSplitReg *model)
2684 {
2685  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2686  return model->priv->notes_list;
2687 }
2688 
2689 GtkListStore *
2690 gnc_tree_model_split_reg_get_memo_list (GncTreeModelSplitReg *model)
2691 {
2692  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2693  return model->priv->memo_list;
2694 }
2695 
2696 GtkListStore *
2697 gnc_tree_model_split_reg_get_action_list (GncTreeModelSplitReg *model)
2698 {
2699  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2700  return model->priv->action_list;
2701 }
2702 
2703 GtkListStore *
2704 gnc_tree_model_split_reg_get_acct_list (GncTreeModelSplitReg *model)
2705 {
2706  g_return_val_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model), NULL);
2707  return model->priv->account_list;
2708 }
2709 
2710 //FIXME Is this the best way to check for duplicates ??
2711 
2712 /* Return TRUE if string already exists in the list */
2713 static gboolean
2714 gtm_sr_check_for_duplicates (GtkListStore *liststore, const gchar *string)
2715 {
2716  GtkTreeIter iter;
2717  gboolean valid;
2718 
2719  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (liststore), &iter);
2720  while (valid)
2721  {
2722  gchar *text;
2723  // Walk through the list, reading each row
2724  gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter, 0, &text, -1);
2725 
2726  if(!(g_strcmp0 (text, string)))
2727  {
2728  g_free(text);
2729  return TRUE;
2730  }
2731  g_free(text);
2732 
2733  valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (liststore), &iter);
2734  }
2735  return FALSE;
2736 }
2737 
2738 
2739 /* Update the Auto Complete List Stores.... */
2740 void
2741 gnc_tree_model_split_reg_update_completion (GncTreeModelSplitReg *model)
2742 {
2744  GtkTreeIter d_iter, n_iter, m_iter;
2745  GList *tlist_cpy, *tnode, *slist, *snode;
2746  int cnt, nSplits;
2747 
2748  ENTER(" ");
2749 
2750  priv = model->priv;
2751 
2752  // Copy the tlist, put it in date order and reverse it.
2753  tlist_cpy = g_list_copy (priv->tlist);
2754  tlist_cpy = g_list_sort (tlist_cpy, (GCompareFunc)xaccTransOrder );
2755  tlist_cpy = g_list_reverse (tlist_cpy);
2756 
2757  /* Clear the liststores */
2758  gtk_list_store_clear (priv->description_list);
2759  gtk_list_store_clear (priv->notes_list);
2760  gtk_list_store_clear (priv->memo_list);
2761 
2762  for (tnode = tlist_cpy; tnode; tnode = tnode->next)
2763  {
2764  Split *split;
2765  const gchar *string;
2766 
2767  nSplits = xaccTransCountSplits (tnode->data);
2768  slist = xaccTransGetSplitList (tnode->data);
2769 
2770  /* Add to the Description list */
2771  string = xaccTransGetDescription (tnode->data);
2772  if (g_strcmp0 (string, ""))
2773  {
2774  if (gtm_sr_check_for_duplicates (priv->description_list, string) == FALSE)
2775  {
2776  gtk_list_store_append (priv->description_list, &d_iter);
2777  gtk_list_store_set (priv->description_list, &d_iter, 0, string, 1, tnode->data, -1);
2778  }
2779  }
2780 
2781  /* Add to the Notes list */
2782  string = xaccTransGetNotes (tnode->data);
2783  if (g_strcmp0 (string, ""))
2784  {
2785  if (gtm_sr_check_for_duplicates (priv->notes_list, string) == FALSE)
2786  {
2787  gtk_list_store_append (priv->notes_list, &n_iter);
2788  gtk_list_store_set (priv->notes_list, &n_iter, 0, string, -1);
2789  }
2790  }
2791 
2792  /* Loop through the list of splits for each Transaction - **do not free the list** */
2793  snode = slist;
2794  cnt = 0;
2795  while (cnt < nSplits)
2796  {
2797  split = snode->data;
2798 
2799  /* Add to the Memo list */
2800  string = xaccSplitGetMemo (split);
2801  if (g_strcmp0 (string, ""))
2802  {
2803  if (gtm_sr_check_for_duplicates (priv->memo_list, string) == FALSE)
2804  {
2805  gtk_list_store_append (priv->memo_list, &m_iter);
2806  gtk_list_store_set (priv->memo_list, &m_iter, 0, string, -1);
2807  }
2808  }
2809  cnt++;
2810  snode = snode->next;
2811  }
2812  }
2813 
2814  g_list_free (tlist_cpy);
2815  PINFO("desc list is %d long", gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->description_list), NULL));
2816  PINFO("notes list is %d long", gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->notes_list), NULL));
2817  PINFO("memo list is %d long", gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->memo_list), NULL));
2818  LEAVE(" ");
2819 }
2820 
2821 
2822 /* Update the model with entries for the Action field */
2823 void
2824 gnc_tree_model_split_reg_update_action_list (GncTreeModelSplitReg *model)
2825 {
2827  GtkListStore *store;
2828  GtkTreeIter iter;
2829 
2830  priv = model->priv;
2831  store = priv->action_list;
2832 
2833 //FIXME This may need some more thought ???
2834 
2835  /* Clear the liststore */
2836  gtk_list_store_clear (store);
2837 
2838  /* setup strings in the action pull-down */
2839  switch (model->type)
2840  {
2841  case BANK_REGISTER2:
2842  /* broken ! FIXME bg ????????? What is broken */
2843  case SEARCH_LEDGER2:
2844 
2845  gtk_list_store_insert_with_values (store, &iter, 100, 0, C_("Action Column", "Deposit"), -1);
2846  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Withdraw"), -1);
2847  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Check"), -1);
2848  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2849  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("ATM Deposit"), -1);
2850  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("ATM Draw"), -1);
2851  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Teller"), -1);
2852  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Charge"), -1);
2853  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Payment"), -1);
2854  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Receipt"), -1);
2855  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Increase"), -1);
2856  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Decrease"), -1);
2857  /* Action: Point Of Sale */
2858  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("POS"), -1);
2859  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Phone"), -1);
2860  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Online"), -1);
2861  /* Action: Automatic Deposit */
2862  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("AutoDep"), -1);
2863  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Wire"), -1);
2864  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Credit"), -1);
2865  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Direct Debit"), -1);
2866  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Transfer"), -1);
2867  break;
2868  case CASH_REGISTER2:
2869  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Increase"), -1);
2870  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Decrease"), -1);
2871  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2872  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2873  break;
2874  case ASSET_REGISTER2:
2875  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2876  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2877  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Fee"), -1);
2878  break;
2879  case CREDIT_REGISTER2:
2880  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("ATM Deposit"), -1);
2881  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("ATM Withdraw"), -1);
2882  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2883  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Credit"), -1);
2884  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Fee"), -1);
2885  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2886  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Online"), -1);
2887  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2888  break;
2889  case LIABILITY_REGISTER2:
2890  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2891  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2892  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Loan"), -1);
2893  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2894  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Payment"), -1);
2895  break;
2896  case RECEIVABLE_REGISTER2:
2897  case PAYABLE_REGISTER2:
2898  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Invoice"), -1);
2899  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Payment"), -1);
2900  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2901  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Credit"), -1);
2902  break;
2903  case INCOME_LEDGER2:
2904  case INCOME_REGISTER2:
2905  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Increase"), -1);
2906  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Decrease"), -1);
2907  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2908  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2909  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2910  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Payment"), -1);
2911  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Rebate"), -1);
2912  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Paycheck"), -1);
2913  break;
2914  case EXPENSE_REGISTER2:
2915  case TRADING_REGISTER2:
2916  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Increase"), -1);
2917  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Decrease"), -1);
2918  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2919  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2920  break;
2921  case GENERAL_JOURNAL2:
2922  case EQUITY_REGISTER2:
2923  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2924  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2925  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Equity"), -1);
2926  break;
2927  case STOCK_REGISTER2:
2928  case PORTFOLIO_LEDGER2:
2929  case CURRENCY_REGISTER2:
2930  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2931  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2932  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Price"), -1);
2933  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Fee"), -1);
2934  /* Action: Dividend */
2935  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Dividend"), -1);
2936  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Interest"), -1);
2937  /* Action: Long Term Capital Gains */
2938  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("LTCG"), -1);
2939  /* Action: Short Term Capital Gains */
2940  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("STCG"), -1);
2941  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Income"), -1);
2942  /* Action: Distribution */
2943  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Dist"), -1);
2944  gtk_list_store_insert_with_values (store, &iter, 100, 0, C_("Action Column", "Split"), -1);
2945  break;
2946 
2947  default:
2948  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Increase"), -1);
2949  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Decrease"), -1);
2950  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Buy"), -1);
2951  gtk_list_store_insert_with_values (store, &iter, 100, 0, _("Sell"), -1);
2952  break;
2953  }
2954  priv->action_list = store;
2955 }
2956 
2957 static int
2958 gtm_sr_account_order_by_name (const Account *aa, const Account *ab)
2959 {
2960  const char *na, *nb;
2961  int retval;
2962 
2963  na = xaccAccountGetName (aa);
2964  nb = xaccAccountGetName (ab);
2965 
2966  retval = g_utf8_collate (na, nb);
2967  if (retval)
2968  return retval;
2969 
2970  return 0;
2971 }
2972 
2973 static int
2974 gtm_sr_account_order_by_full_name (const Account *aa, const Account *ab)
2975 {
2976  gchar *fna, *fnb;
2977  int retval;
2978 
2979  fna = gnc_account_get_full_name (aa);
2980  fnb = gnc_account_get_full_name (ab);
2981 
2982  retval = g_utf8_collate (fna, fnb);
2983 
2984  g_free (fna);
2985  g_free (fnb);
2986 
2987  if (retval)
2988  return retval;
2989 
2990  return 0;
2991 }
2992 
2993 /* Return the GtkListstore of Accounts */
2994 void
2995 gnc_tree_model_split_reg_update_account_list (GncTreeModelSplitReg *model)
2996 {
2998  Account *root;
2999  Account *acc;
3000  GtkTreeIter iter;
3001  GList *accts, *accts_cpy, *ptr;
3002  const gchar *name;
3003  gchar *fname;
3004  gint i;
3005 
3006  priv = model->priv;
3007 
3008  /* Clear the liststore, Store is short name, full name and account pointer */
3009  gtk_list_store_clear (priv->account_list);
3010 
3011  root = gnc_book_get_root_account (priv->book);
3012 
3013  // Get a list of accounts.
3014  accts = gnc_account_get_descendants (root);
3015 
3016  // Copy the accts, put it in full name order.
3017  accts_cpy = g_list_copy (accts);
3018 
3019  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_LEAF_ACCT_NAMES))
3020  accts_cpy = g_list_sort (accts_cpy, (GCompareFunc)gtm_sr_account_order_by_name);
3021  else
3022  accts_cpy = g_list_sort (accts_cpy, (GCompareFunc)gtm_sr_account_order_by_full_name);
3023 
3024  for (ptr = accts_cpy, i = 0; ptr; ptr = g_list_next (ptr), i++)
3025  {
3026  acc = ptr->data;
3027 
3028  if(!(acc == model->priv->anchor))
3029  {
3030  fname = gnc_account_get_full_name (acc);
3031  name = xaccAccountGetName (acc);
3032  gtk_list_store_append (priv->account_list, &iter);
3033  gtk_list_store_set (priv->account_list, &iter, 0, name, 1, fname, 2, acc, -1);
3034  g_free (fname);
3035  }
3036  }
3037  g_list_free (accts);
3038  g_list_free (accts_cpy);
3039 }
3040 
3041 
3042 /* Return the split for which ancestor is it's parent */
3043 Split *
3044 gnc_tree_model_split_reg_trans_get_split_equal_to_ancestor (const Transaction *trans, const Account *ancestor)
3045 {
3046  GList *node;
3047 
3048  for (node = xaccTransGetSplitList (trans); node; node = node->next)
3049  {
3050  Split *split = node->data;
3051  Account *split_acc = xaccSplitGetAccount (split);
3052 
3053  if (!xaccTransStillHasSplit (trans, split))
3054  continue;
3055 
3056  if (ancestor == split_acc)
3057  return split;
3058 
3059  if (ancestor && xaccAccountHasAncestor (split_acc, ancestor))
3060  return split;
3061  }
3062  return NULL;
3063 }
3064 
3065 
3066 /*******************************************************************/
3067 /* Split Register Tree Model - Engine Event Handling Functions */
3068 /*******************************************************************/
3069 
3098 static void
3099 gnc_tree_model_split_reg_event_handler (QofInstance *entity,
3100  QofEventId event_type,
3101  GncTreeModelSplitReg *model,
3102  GncEventData *event_data)
3103 {
3104  GncTreeModelSplitRegPrivate *priv = model->priv;
3105  GncEventData *ed = event_data;
3106  GtkTreeIter iter1, iter2;
3107  GtkTreePath *path;
3108  Transaction *trans;
3109  Split *split = NULL;
3110  QofIdType type;
3111  const gchar *name = NULL;
3112  GList *tnode;
3113 
3114  g_return_if_fail (GNC_IS_TREE_MODEL_SPLIT_REG (model));
3115 
3116  if (qof_instance_get_book (entity) != priv->book)
3117  return;
3118  type = entity->e_type;
3119 
3120  if (g_strcmp0 (type, GNC_ID_SPLIT) == 0)
3121  {
3122  /* Get the split.*/
3123  split = (Split *) entity;
3124  name = xaccSplitGetMemo (split);
3125 
3126  switch (event_type)
3127  {
3128  case QOF_EVENT_MODIFY:
3129  if (get_iter (model, NULL, split, &iter1, &iter2))
3130  {
3131  DEBUG ("change split %p (%s)", split, name);
3132  gtm_sr_changed_row_at (model, &iter1);
3133 
3134  /* If we change split to different account, remove from view */
3135  if (priv->anchor != NULL)
3136  {
3137  Split *find_split;
3138  Transaction *trans;
3139  trans = xaccSplitGetParent (split);
3140  if (priv->display_subacc) // Sub accounts
3141  find_split = gnc_tree_model_split_reg_trans_get_split_equal_to_ancestor (trans, priv->anchor);
3142  else
3143  find_split = xaccTransFindSplitByAccount (trans, priv->anchor);
3144 
3145  if (find_split == NULL)
3146  {
3147  g_signal_emit_by_name (model, "selection_move_delete", trans);
3148  gtm_sr_delete_trans (model, trans);
3149  }
3150  }
3151  }
3152  break;
3153  default:
3154  DEBUG ("ignored event for %p (%s)", split, name);
3155  }
3156  }
3157  else if (g_strcmp0 (type, GNC_ID_TRANS) == 0)
3158  {
3159  /* Get the trans.*/
3160  trans = (Transaction *) entity;
3161  name = xaccTransGetDescription (trans);
3162 
3163  switch (event_type)
3164  {
3165  case GNC_EVENT_ITEM_ADDED:
3166  split = (Split *) ed->node;
3167  /* The blank split will be added to the transaction when
3168  it's first edited. That will generate an event, but
3169  we don't want to emit row_inserted because we were
3170  already showing the blank split. */
3171  if (split == priv->bsplit) break;
3172 
3173  if (xaccTransCountSplits (trans) < 2) break;
3174 
3175  /* Tell the filters/views where the new row was added. */
3176  if (get_iter (model, trans, split, &iter1, &iter2))
3177  {
3178  DEBUG ("add split %p (%s)", split, name);
3179  gtm_sr_insert_row_at (model, &iter1);
3180  }
3181  break;
3182  case GNC_EVENT_ITEM_REMOVED:
3183  split = (Split *) ed->node;
3184 
3185  path = gtm_sr_get_removal_path (model, trans, ed->idx);
3186  if (path)
3187  {
3188  DEBUG ("remove split %p from trans %p (%s)", split, trans, name);
3189  if (ed->idx == -1)
3190  gtm_sr_delete_trans (model, trans); //Not sure when this would be so
3191  else
3192  gtm_sr_delete_row_at_path (model, path);
3193  gtk_tree_path_free (path);
3194  }
3195  if (split == priv->bsplit)
3196  gtm_sr_make_new_blank_split (model);
3197  break;
3198  case QOF_EVENT_MODIFY:
3199  /* The blank trans won't emit MODIFY until it's committed */
3200  if (priv->btrans == trans)
3201  {
3202  priv->btrans = xaccMallocTransaction (priv->book);
3203  priv->tlist = g_list_append (priv->tlist, priv->btrans);
3204 
3205  tnode = g_list_find (priv->tlist, priv->btrans);
3206  /* Insert a new blank trans */
3207  iter1 = gtm_sr_make_iter (model, TROW1 | BLANK, tnode, NULL);
3208  gtm_sr_insert_row_at (model, &iter1);
3209  iter2 = gtm_sr_make_iter (model, TROW2 | BLANK, tnode, NULL);
3210  gtm_sr_insert_row_at (model, &iter2);
3211  g_signal_emit_by_name (model, "refresh_trans", priv->btrans);
3212  }
3213 
3214  if (get_iter (model, trans, NULL, &iter1, &iter2))
3215  {
3216  DEBUG ("change trans %p (%s)", trans, name);
3217  gtm_sr_changed_row_at (model, &iter1);
3218  gtm_sr_changed_row_at (model, &iter2);
3219  g_signal_emit_by_name (model, "refresh_trans", trans);
3220  }
3221  break;
3222  case QOF_EVENT_DESTROY:
3223  if (priv->btrans == trans)
3224  {
3225  tnode = g_list_find (priv->tlist, priv->btrans);
3226  priv->btrans = xaccMallocTransaction (priv->book);
3227  tnode->data = priv->btrans;
3228  iter1 = gtm_sr_make_iter (model, TROW1 | BLANK, tnode, NULL);
3229  gtm_sr_changed_row_at (model, &iter1);
3230  iter2 = gtm_sr_make_iter (model, TROW2 | BLANK, tnode, NULL);
3231  gtm_sr_changed_row_at (model, &iter2);
3232  }
3233  else if (get_iter (model, trans, NULL, &iter1, &iter2))
3234  {
3235  DEBUG("destroy trans %p (%s)", trans, name);
3236  g_signal_emit_by_name (model, "selection_move_delete", trans);
3237  gtm_sr_delete_trans (model, trans);
3238  g_signal_emit_by_name (model, "refresh_trans", trans);
3239  }
3240  break;
3241  default:
3242  DEBUG("ignored event for %p (%s)", trans, name);
3243  }
3244  }
3245  else if (g_strcmp0 (type, GNC_ID_ACCOUNT) == 0)
3246  {
3247  switch (event_type)
3248  {
3249  Account *acc;
3250  case GNC_EVENT_ITEM_ADDED:
3251  split = (Split *) ed;
3252  acc = xaccSplitGetAccount (split);
3253  trans = xaccSplitGetParent (split);
3254 
3255  if (!g_list_find (priv->tlist, trans) && priv->display_gl)
3256  {
3257  gnc_commodity *split_com;
3258  split_com = xaccAccountGetCommodity (acc);
3259  if (g_strcmp0 (gnc_commodity_get_namespace (split_com), GNC_COMMODITY_NS_TEMPLATE) != 0)
3260  {
3261  DEBUG("Insert trans %p for gl (%s)", trans, name);
3262  gtm_sr_insert_trans (model, trans, TRUE);
3263  g_signal_emit_by_name (model, "refresh_trans", trans);
3264  }
3265  }
3266  else if (!g_list_find (priv->tlist, trans) && ((xaccAccountHasAncestor (acc, priv->anchor) && priv->display_subacc) || acc == priv->anchor ))
3267  {
3268  DEBUG("Insert trans %p (%s)", trans, name);
3269  gtm_sr_insert_trans (model, trans, TRUE);
3270  g_signal_emit_by_name (model, "refresh_trans", trans);
3271  }
3272  break;
3273  default:
3274  ;
3275  }
3276  /* Lets refresh the status bar */
3277  g_signal_emit_by_name (model, "refresh_status_bar", NULL);
3278  }
3279 }
3280 
3281 
3282 /* Returns the parent Window of the register */
3283 GtkWidget *
3285 {
3287  GtkWidget *parent = NULL;
3288 
3289  priv = model->priv;
3290 
3291  if (priv->get_parent)
3292  parent = priv->get_parent (priv->user_data);
3293 
3294  return parent;
3295 }
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
void gnc_tree_model_split_reg_config(GncTreeModelSplitReg *model, SplitRegisterType2 newtype, SplitRegisterStyle2 newstyle, gboolean use_double_line)
Set style and type for register.
gint number_of_trans_in_full_tlist
The total number of transactions in full_tlist.
gint position_of_trans_in_full_tlist
The position of current transaction in full_tlist.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:511
gboolean use_double_line
FIXME ? As above, whether to use two lines per transaction.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
SplitRegisterType2
Register types.
gint current_row
Current row in treeview.
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Definition: Transaction.c:2635
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
def find_split(split_list, search_string)
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:89
utility functions for the GnuCash UI
void gnc_tree_model_split_reg_set_display(GncTreeModelSplitReg *model, gboolean subacc, gboolean gl)
Set display general journal and show sub accounts.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *params1, QofQueryParamList *params2, QofQueryParamList *params3)
When a query is run, the results are sorted before being returned.
Definition: qofquery.cpp:1232
gboolean read_only
register is read only
gboolean is_template
Are we using a template.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2701
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
gint sort_col
This is the column the sort direction is based on.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
gboolean use_gnc_color_theme
whether to use the gnucash built-in color theme
SplitRegisterType2 type
FIXME ? This may be the wrong place for these, may be the view ?
GtkSortType sort_direction
This is the direction of sort.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Account * gnc_tree_model_split_reg_get_anchor(GncTreeModelSplitReg *model)
Return the default account for this register model.
void gnc_tm_get_today_start(struct tm *tm)
The gnc_tm_get_today_start() routine takes a pointer to a struct tm and fills it in with the first se...
Definition: gnc-date.cpp:1332
gboolean separator_changed
whether the separator has changed
const char * gnc_commodity_get_namespace(const gnc_commodity *cm)
Retrieve the namespace for the specified commodity.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
QofBook * xaccSplitGetBook(const Split *split)
Returns the book of this split, i.e.
Definition: gmock-Split.cpp:45
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean alt_colors_by_txn
whether to use alternative colors by transaction
gboolean gnc_tree_model_split_reg_get_template(GncTreeModelSplitReg *model)
Return TRUE if this is a template register.
#define VREC
split is void
Definition: Split.h:75
void gnc_tree_model_split_reg_commit_blank_split(GncTreeModelSplitReg *model)
Commit the blank split.
GncTreeModelSplitReg * gnc_tree_model_split_reg_new(SplitRegisterType2 reg_type, SplitRegisterStyle2 style, gboolean use_double_line, gboolean is_template, gboolean mismatched_commodities)
Create new model and set options for register.
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.cpp:73
Transaction * current_trans
Current transaction.
gboolean gnc_tree_model_split_reg_trans_is_in_view(GncTreeModelSplitReg *model, Transaction *trans)
Return TRUE if transaction is in the view list.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
const gchar * QofIdType
QofIdType declaration.
Definition: qofid.h:85
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
#define xaccAccountGetGUID(X)
Definition: Account.h:248
convert single-entry accounts to clean double-entry
GList SplitList
GList of Split.
Definition: gnc-engine.h:211
gboolean xaccTransHasSplitsInState(const Transaction *trans, const char state)
FIXME: document me.
Definition: Transaction.c:2753
void xaccSplitSetAmount(Split *split, gnc_numeric amt)
The xaccSplitSetAmount() method sets the amount in the account&#39;s commodity that the split should have...
Definition: gmock-Split.cpp:77
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3308
The class data structure for an account tree model.
gboolean use_accounting_labels
whether to use accounting Labels
gint QofEventId
Define the type of events allowed.
Definition: qofevent.h:45
Gobject helper routines.
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
The xaccTransGetImbalanceValue() method returns the total value of the transaction.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void gnc_tree_model_split_reg_move(GncTreeModelSplitReg *model, GncTreeModelSplitRegUpdate model_update)
Change transactions in the tlist based on view movement.
void gnc_tree_model_split_reg_set_data(GncTreeModelSplitReg *model, gpointer user_data, SRGetParentCallback2 get_parent)
Sets the user data and callback hooks for the register.
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2492
SplitRegisterStyle2 style
FIXME ? This may be the wrong place for these, may be the view ?
gint sort_depth
This is the row the sort direction is based on.
gboolean mismatched_commodities
Are there different commodities.
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.cpp:103
void gnc_tree_model_split_reg_update_query(GncTreeModelSplitReg *model, Query *query)
Update the query for the register.
Account * gnc_tree_model_split_reg_get_template_account(GncTreeModelSplitReg *model)
Returns the template account.
GtkWidget *(* SRGetParentCallback2)(gpointer user_data)
Callback function type - Used to get parent window.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Use unbiased ("banker&#39;s") rounding.
Definition: gnc-numeric.h:173
time64 gnc_mktime(struct tm *time)
calculate seconds from the epoch given a time struct
Definition: gnc-date.cpp:230
#define xaccTransGetBook(X)
Definition: Transaction.h:791
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition: gnc-date.h:114
Additional event handling code.
void gnc_tree_model_split_reg_load(GncTreeModelSplitReg *model, GList *slist, Account *default_account)
Load the model from a slist and set default account for register.
The instance private data for the split register tree model.
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2311
All type declarations for the whole Gnucash engine.
const GncGUID * qof_entity_get_guid(gconstpointer ent)
gint stamp
The state of the model.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
SplitRegisterStyle2
Register styles.
Generic api to store and retrieve preferences.
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition: Account.cpp:3036
Transaction * gnc_tree_model_split_reg_get_first_trans(GncTreeModelSplitReg *model)
Return the first transaction, opposite to blank transaction in the full list.
GType gnc_tree_model_split_reg_get_type(void)
Get the type of split register tree plugin.
gboolean qof_book_is_readonly(const QofBook *book)
Return whether the book is read only.
Definition: qofbook.cpp:580
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Returns true if the account is &#39;ancestor&#39; or has &#39;ancestor&#39; as an ancestor.
Definition: Account.cpp:4385
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1367
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_tree_model_split_reg_set_template_account(GncTreeModelSplitReg *model, Account *template_account)
Sets the template account.
#define QUERY_DEFAULT_SORT
Default sort object type.
Definition: qofquery.h:106
int xaccTransOrder(const Transaction *ta, const Transaction *tb)
The xaccTransOrder(ta,tb) method is useful for sorting.
Definition: Transaction.c:1896
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
The instance data structure for an account tree model.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
GtkWidget * gnc_tree_model_split_reg_get_parent(GncTreeModelSplitReg *model)
Returns the parent Window of the register.
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:1086
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
#define GNC_EVENT_ITEM_ADDED
These events are used when a split is added to an account.
Definition: gnc-event.h:45
No error.
Definition: gnc-numeric.h:224
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
size_t qof_print_date_buff(char *buff, size_t buflen, time64 secs)
Convenience: calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:581
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
Commodity handling public routines.
void gnc_tree_model_split_reg_destroy(GncTreeModelSplitReg *model)
Destroy the model.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2050