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