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 (>mits_buffer_key);
1101 if (string == NULL)
1102 {
1103 string = g_malloc (ITER_STRING_LEN + 1);
1104 g_private_set (>mits_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