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