GnuCash  4.12-11-g8193d7f23a+
gnc-tree-view-split-reg.c
1 /********************************************************************\
2  * gnc-tree-view-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 <stdlib.h>
32 #include <string.h>
33 #include <gdk/gdkkeysyms.h>
34 
35 #include "gnc-tree-view.h"
40 #include "gnc-ui.h"
41 #include "gnc-warnings.h"
42 #include "dialog-utils.h"
43 #include "gnc-prefs.h"
44 #include "Transaction.h"
45 #include "engine-helpers.h"
46 #include "Scrub.h"
47 #include "gnc-exp-parser.h"
48 #include "SchedXaction.h"
49 
50 #include "gnc-amount-edit.h"
51 
52 
53 /* Signal codes */
54 enum
55 {
56  UPDATE_SIGNAL,
57  HELP_SIGNAL,
58  LAST_SIGNAL
59 };
60 
61 typedef enum {
62  RESET, //0
63  ACCEPT, //1
64  DISCARD,//2
65  CANCEL //3
66 }TransConfirm;
67 
68 
70 static QofLogModule log_module = GNC_MOD_LEDGER;
71 
72 static void gnc_tree_view_split_reg_class_init (GncTreeViewSplitRegClass *klass);
73 static void gnc_tree_view_split_reg_init (GncTreeViewSplitReg *view);
74 static void gnc_tree_view_split_reg_dispose (GObject *object);
75 static void gnc_tree_view_split_reg_finalize (GObject *object);
76 
77 static guint gnc_tree_view_split_reg_signals[LAST_SIGNAL] = {0};
78 
79 static void gnc_tree_view_split_reg_pref_changed (gpointer prefs, gchar *pref, gpointer user_data);
80 
81 static void gtv_sr_cdf0 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *s_model,
82  GtkTreeIter *s_iter, gpointer user_data);
83 
84 static void gtv_sr_cdf1 (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *s_model,
85  GtkTreeIter *s_iter, gpointer user_data);
86 
87 static void gtv_sr_control_cdf0 (GtkTreeViewColumn *col, GtkCellRenderer *renderer,
88  GtkTreeModel *s_model, GtkTreeIter *s_iter, gpointer user_data);
89 
90 static void gtv_sr_titles (GncTreeViewSplitReg *view, RowDepth depth);
91 
92 static void gtv_sr_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
93  const gchar *new_text, gpointer user_data);
94 
95 static void gtv_sr_edited_normal_cb (GtkCellRendererText *cell, const gchar *path_string,
96  const gchar *new_text, gpointer user_data);
97 
98 static void gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
99  const gchar *new_text, gpointer user_data);
100 
101 //static void start_edit (GtkCellRenderer *cr, GtkCellEditable *editable,
102 // const gchar *path, gpointer user_data); //FIXME This may not be needed
103 
104 static void gtv_sr_begin_edit (GncTreeViewSplitReg *view, Transaction *trans);
105 
106 static void gtv_sr_finish_edit (GncTreeViewSplitReg *view);
107 
108 static void gtv_sr_editable_start_editing_cb (GtkCellRenderer *cr, GtkCellEditable *editable,
109  const gchar *path, gpointer user_data);
110 
111 static void gtv_sr_editing_canceled_cb (GtkCellRenderer *cr, gpointer user_data);
112 
113 //static void gtv_sr_match_selected_cb (GtkEntryCompletion *widget, GtkTreeModel *model,
114 // GtkTreeIter *iter, gpointer user_data); //FIXME This may not be needed
115 
116 //static void gtv_sr_changed_cb (GtkCellRendererCombo *widget, gchar *path_string,
117 // GtkTreeIter *iter, gpointer user_data); //FIXME This may not be needed
118 
119 static void gtv_sr_selection_move_delete_cb (GncTreeModelSplitReg *model, gpointer item, gpointer user_data);
120 
121 static gboolean gtv_sr_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
122 
123 static gboolean gtv_sr_ed_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data);
124 
125 static gboolean gtv_sr_button_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
126 
127 static gboolean gtv_sr_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, gpointer user_data);
128 
129 static void gtv_sr_motion_cb (GtkTreeSelection *sel, gpointer user_data);
130 
131 static void gtv_sr_refresh_view_cb (GncTreeModelSplitReg *model, gpointer user_data);
132 
133 static gboolean gtv_sr_transaction_changed_confirm (GncTreeViewSplitReg *view, Transaction *new_trans);
134 
135 
136 typedef struct {
137  ViewCol viewcol;
138  gint modelcol;
139  gchar *title;
140  gchar *pref_name;
141  gchar *sizer;
142  int visibility_model_col;
143  int always_visible_col;
144  void (*edited_cb)(GtkCellRendererText *, const gchar *,
145  const gchar *, gpointer);
146  void (*editing_started_cb)(GtkCellRenderer *, GtkCellEditable *,
147  const gchar *, gpointer);
148  GtkTreeIterCompareFunc sort_fn;
149 } ColDef;
150 
151 
152 static ColDef all_tree_view_split_reg_columns[] = {
153  {COL_DATE, GNC_TREE_MODEL_SPLIT_REG_COL_DATE,
154  "Date", "date", "00/00/0000",
155  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
156  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
157  gnc_tree_model_split_reg_sort_iter_compare_func},
158 
159  {COL_DUEDATE, -1,
160  "Due Date", "duedate", "00/00/0000",
161  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
162  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
163 
164  {COL_NUMACT, GNC_TREE_MODEL_SPLIT_REG_COL_NUMACT,
165  "Num / Act / Act", "numact", "0000",
166  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
167  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
168  gnc_tree_model_split_reg_sort_iter_compare_func},
169 
170  {COL_DESCNOTES, GNC_TREE_MODEL_SPLIT_REG_COL_DESCNOTES,
171  "Description / Notes / Memo", "descnotes", "xxxxxxxxxxxxxxxxxxx",
172  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
173  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
174  gnc_tree_model_split_reg_sort_iter_compare_func},
175 
176  {COL_TRANSFERVOID, -1,
177  "Transfer / Void", "transfervoid", "xxxxxxxxxxxxxxxxxxx",
178  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
179  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
180 
181  {COL_RECN, GNC_TREE_MODEL_SPLIT_REG_COL_RECN,
182  "R", "recn", "xx",
183  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
184  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
185  gnc_tree_model_split_reg_sort_iter_compare_func},
186 
187  {COL_TYPE, -1,
188  "Type", "type", "xx",
189  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
190  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
191 
192  {COL_VALUE, -1,
193  "Value", "value", "00000",
194  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
195  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
196 
197  {COL_AMOUNT, -1,
198  "Amount", "amount", "00000",
199  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
200  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
201 
202  {COL_AMTVAL, -1,
203  "Amount / Value", "amtval", "00000",
204  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
205  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
206 
207  {COL_RATE, -1,
208  "Rate", "rate", "00000",
209  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
210  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
211 
212  {COL_PRICE, -1,
213  "Price", "price", "00000",
214  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
215  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb, NULL},
216 
217  {COL_DEBIT, GNC_TREE_MODEL_SPLIT_REG_COL_DEBIT,
218  "Debit", "debit", "00000",
219  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
220  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
221  gnc_tree_model_split_reg_sort_iter_compare_func},
222 
223  {COL_CREDIT, GNC_TREE_MODEL_SPLIT_REG_COL_CREDIT,
224  "Credit", "credit", "00000",
225  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
226  gtv_sr_edited_cb, gtv_sr_editable_start_editing_cb,
227  gnc_tree_model_split_reg_sort_iter_compare_func},
228 
229  {COL_BALANCE, -1,
230  "Balance", "balance", "00000",
231  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
232  NULL, NULL, NULL},
233 
234  {COL_STATUS, -1,
235  " ", "status", "x",
236  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 1,
237  NULL, NULL, NULL},
238 
239  {COL_COMM, -1,
240  "Commodity", "commodity", "xxxxxxxx",
241  GNC_TREE_VIEW_COLUMN_VISIBLE_ALWAYS, 0,
242  NULL, NULL, NULL},
243 };
244 
245 
247 {
248  gboolean disposed;
249 
250  Account *anchor; // The register default Account
251  gnc_commodity *reg_comm; // The register commodity (which may be a non-currency)
252  gnc_commodity *reg_currency; // The currency for txns in this register (guaranteed to be a currency)
253 
254  Transaction *current_trans; // The current highlighted transaction
255  Split *current_split; // The current highlighted split
256  RowDepth current_depth; // The current depth 1=TROW1, 2=TROW2, 3=SPLIT3
257  GtkTreeRowReference *current_ref; // The current model path reference
258 
259  Transaction *dirty_trans; // Set when transaction is changed
260  TransConfirm trans_confirm; // This is the return value for gtv_sr_transaction_changed_confirm
261 
262  GtkCellRenderer *temp_cr; // Pointer to Temp Cell Renderer
263  gulong fo_handler_id; // Focus out callback id
264 
265  gboolean acct_short_names; // Use account short names
266  gboolean double_line; // Use double line mode
267  gboolean expanded; // Are we expanded to splits
268  gboolean auto_complete; // Whether auto complete has run
269  gboolean negative_in_red; // Display negative numbers in red
270  gboolean use_horizontal_lines;// Draw horizontal lines
271  gboolean use_vertical_lines; // Draw vertical lines
272 
273  gboolean show_calendar_buttons; // Show the calendar buttons
274  gboolean show_extra_dates_on_selection;// Show the above on the selected transaction
275  gboolean selection_to_blank_on_expand; // Move the selection to the blank split on expand
276 
277  gint key_length; // The number of characters before auto complete starts.
278  gint single_button_press; // Capture single button press.
279 
280  gchar *transfer_string; // The transfer account string.
281  gboolean stop_cell_move; // Stops the cursor moving to a different cell.
282 
283 };
284 
285 /* Define some cell colors */
286 #define PINKCELL "#F8BEC6"
287 #define REDCELL "#F34943"
288 #define BLUECELL "#1D80DF"
289 #define BLACKCELL "#CBCBD2"
290 #define YELLOWCELL "#FFEF98"
291 #define ORANGECELL "#F39536"
292 
293 
294 #define GNC_PREF_SHOW_EXTRA_DATES "show-extra-dates"
295 #define GNC_PREF_SHOW_EXTRA_DATES_ON_SEL "show-extra-dates-on-selection"
296 #define GNC_PREF_SHOW_CAL_BUTTONS "show-calendar-buttons"
297 #define GNC_PREF_SEL_TO_BLANK_ON_EXPAND "selection-to-blank-on-expand"
298 #define GNC_PREF_KEY_LENGTH "key-length"
299 
300 /* This could be a preference setting, show currency / commodity symbols */
301 #define SHOW_SYMBOL FALSE
302 
303 #define GNC_TREE_VIEW_SPLIT_REG_GET_PRIVATE(o) \
304  ((GncTreeViewSplitRegPrivate*)gnc_tree_view_split_reg_get_instance_private((GncTreeViewSplitReg*)o))
305 
306 static GObjectClass *parent_class = NULL;
307 
308 G_DEFINE_TYPE_WITH_PRIVATE(GncTreeViewSplitReg, gnc_tree_view_split_reg, GNC_TYPE_TREE_VIEW)
309 
310 static void
311 gnc_tree_view_split_reg_class_init (GncTreeViewSplitRegClass *klass)
312 {
313  GObjectClass *o_class;
314 
315  parent_class = g_type_class_peek_parent (klass);
316 
317  o_class = G_OBJECT_CLASS (klass);
318 
319  o_class->dispose = gnc_tree_view_split_reg_dispose;
320  o_class->finalize = gnc_tree_view_split_reg_finalize;
321 
322  gnc_tree_view_split_reg_signals[UPDATE_SIGNAL] =
323  g_signal_new("update_signal",
324  G_TYPE_FROM_CLASS (o_class),
325  G_SIGNAL_RUN_LAST,
326  G_STRUCT_OFFSET (GncTreeViewSplitRegClass, update_signal),
327  NULL, NULL,
328  g_cclosure_marshal_VOID__VOID,
329  G_TYPE_NONE, 0);
330 
331  gnc_tree_view_split_reg_signals[HELP_SIGNAL] =
332  g_signal_new("help_signal",
333  G_TYPE_FROM_CLASS (o_class),
334  G_SIGNAL_RUN_LAST,
335  G_STRUCT_OFFSET (GncTreeViewSplitRegClass, help_signal),
336  NULL, NULL,
337  g_cclosure_marshal_VOID__VOID,
338  G_TYPE_NONE, 0);
339 
340  klass->update_signal = NULL;
341  klass->help_signal = NULL;
342 }
343 
344 /*****************************************************************************/
345 
346 /* Return the tree model from the tree view */
348 gnc_tree_view_split_reg_get_model_from_view (GncTreeViewSplitReg *view)
349 {
350  GtkTreeModelSort *s_model = GTK_TREE_MODEL_SORT (gtk_tree_view_get_model (GTK_TREE_VIEW (view)));
351  return GNC_TREE_MODEL_SPLIT_REG (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (s_model)));
352 }
353 
354 /* Get the model iter from the view path string */
355 static gboolean
356 gtv_sr_get_model_iter_from_view_string (GncTreeViewSplitReg *view,
357  const gchar *path_string, GtkTreeIter *m_iter)
358 {
359  GtkTreeModel *s_model;
360  GtkTreeIter s_iter;
361 
362  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
363 
364  if (!gtk_tree_model_get_iter_from_string (s_model, &s_iter, path_string))
365  {
366  m_iter = NULL;
367  return FALSE;
368  }
369  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), m_iter, &s_iter);
370  return TRUE;
371 }
372 
373 /* Get the model iter from the selection */
374 static gboolean
375 gtv_sr_get_model_iter_from_selection (GncTreeViewSplitReg *view,
376  GtkTreeSelection *sel, GtkTreeIter *m_iter)
377 {
378  GtkTreeModel *s_model;
379  GtkTreeIter s_iter;
380 
381  if (gtk_tree_selection_get_selected (sel, &s_model, &s_iter))
382  {
383  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), m_iter, &s_iter);
384  return TRUE;
385  }
386  return FALSE;
387 }
388 
389 /* Get sort model path from the model path
390  *
391  * Return A newly allocated GtkTreePath, or NULL */
392 GtkTreePath *
393 gnc_tree_view_split_reg_get_sort_path_from_model_path (GncTreeViewSplitReg *view, GtkTreePath *mpath)
394 {
395  GtkTreeModel *s_model;
396  GtkTreePath *spath;
397 
398  g_return_val_if_fail (mpath, NULL);
399  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
400  spath = gtk_tree_model_sort_convert_child_path_to_path (GTK_TREE_MODEL_SORT (s_model), mpath);
401  if (!spath)
402  {
403  /* No parent path available */
404  return NULL;
405  }
406  return spath;
407 }
408 
409 /* Get model path from the sort model path
410  *
411  * Return A newly allocated GtkTreePath, or NULL. */
412 GtkTreePath *
413 gnc_tree_view_split_reg_get_model_path_from_sort_path (GncTreeViewSplitReg *view, GtkTreePath *spath)
414 {
415  GtkTreeModel *s_model;
416  GtkTreePath *mpath;
417 
418  g_return_val_if_fail (spath, NULL);
419  s_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
420  mpath = gtk_tree_model_sort_convert_path_to_child_path (GTK_TREE_MODEL_SORT (s_model), spath);
421  if (!mpath)
422  {
423  /* No child path available */
424  return NULL;
425  }
426  return mpath;
427 }
428 
429 /*****************************************************************************/
430 
431 static void
432 gnc_tree_view_split_reg_init (GncTreeViewSplitReg *view)
433 {
434  view->priv = g_new0 (GncTreeViewSplitRegPrivate, 1);
435 
436  view->priv->current_trans = NULL;
437  view->priv->current_split = NULL;
438  view->priv->current_depth = 0;
439  view->reg_closing = FALSE;
440  view->priv->fo_handler_id = 0;
441  view->priv->auto_complete = FALSE;
442  view->priv->trans_confirm = RESET;
443  view->priv->single_button_press = 0;
444 
445  view->priv->transfer_string = g_strdup ("Dummy");
446  view->priv->stop_cell_move = FALSE;
447 
448  view->priv->show_calendar_buttons = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_CAL_BUTTONS);
449  view->show_extra_dates = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_EXTRA_DATES);
450  view->priv->show_extra_dates_on_selection = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_EXTRA_DATES_ON_SEL);
451  view->priv->selection_to_blank_on_expand = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SEL_TO_BLANK_ON_EXPAND);
452  view->priv->key_length = gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_KEY_LENGTH);
453 
454  view->priv->acct_short_names = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_LEAF_ACCT_NAMES);
455  view->priv->negative_in_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL, GNC_PREF_NEGATIVE_IN_RED);
456  view->priv->use_horizontal_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
457  GNC_PREF_DRAW_HOR_LINES);
458 
459  view->priv->use_vertical_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
460  GNC_PREF_DRAW_VERT_LINES);
461 
462  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
463  GNC_PREF_DRAW_HOR_LINES,
464  gnc_tree_view_split_reg_pref_changed,
465  view);
466  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
467  GNC_PREF_DRAW_VERT_LINES,
468  gnc_tree_view_split_reg_pref_changed,
469  view);
470 }
471 
472 
473 static void
474 gnc_tree_view_split_reg_dispose (GObject *object)
475 {
476  GncTreeViewSplitReg *view;
478 
479  gnc_leave_return_if_fail (object != NULL);
480  gnc_leave_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (object));
481 
482  view = GNC_TREE_VIEW_SPLIT_REG (object);
483  priv = GNC_TREE_VIEW_SPLIT_REG_GET_PRIVATE (view);
484 
485  if (priv->disposed)
486  return;
487 
488  ENTER("split reg view %p", object);
489 
490  priv->disposed = TRUE;
491 
492  if(view->priv->current_ref != NULL)
493  {
494  gtk_tree_row_reference_free (view->priv->current_ref);
495  view->priv->current_ref = NULL;
496  }
497 
498  if (view->help_text)
499  g_free (view->help_text);
500 
501  if (view->priv->transfer_string)
502  g_free (view->priv->transfer_string);
503 
504  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
505  GNC_PREF_DRAW_HOR_LINES,
506  gnc_tree_view_split_reg_pref_changed,
507  view);
508  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
509  GNC_PREF_DRAW_VERT_LINES,
510  gnc_tree_view_split_reg_pref_changed,
511  view);
512 
513  if (G_OBJECT_CLASS (parent_class)->dispose)
514  (* G_OBJECT_CLASS (parent_class)->dispose) (object);
515 
516  LEAVE(" ");
517 }
518 
519 
520 static void
521 gnc_tree_view_split_reg_finalize (GObject *object)
522 {
523  gnc_leave_return_if_fail(object != NULL);
524  gnc_leave_return_if_fail(GNC_IS_TREE_VIEW_SPLIT_REG (object));
525 
526  ENTER("split reg view %p", object);
527 
528  if (G_OBJECT_CLASS(parent_class)->finalize)
529  (* G_OBJECT_CLASS(parent_class)->finalize) (object);
530 
531  LEAVE(" ");
532 }
533 
534 
535 /* Update internal settings based on preferences */
536 void
537 gnc_tree_view_split_reg_refresh_from_prefs (GncTreeViewSplitReg *view)
538 {
539  GncTreeModelSplitReg *model;
540 
541  model = gnc_tree_view_split_reg_get_model_from_view (view);
542 
543  model->use_gnc_color_theme = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
544  GNC_PREF_USE_GNUCASH_COLOR_THEME);
545  model->use_accounting_labels = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
546  GNC_PREF_ACCOUNTING_LABELS);
547 
548  model->alt_colors_by_txn = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
549  GNC_PREF_ALT_COLOR_BY_TRANS);
550 
551  view->priv->negative_in_red = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL,
552  GNC_PREF_NEGATIVE_IN_RED);
553 }
554 
555 
556 static void
557 gnc_tree_view_split_reg_pref_changed (gpointer prefs, gchar *pref, gpointer user_data)
558 {
559  GncTreeViewSplitReg *view = user_data;
560 
561  g_return_if_fail (pref);
562 
563  if (view == NULL)
564  return;
565 
566  if (g_str_has_suffix (pref, GNC_PREF_DRAW_HOR_LINES) || g_str_has_suffix (pref, GNC_PREF_DRAW_VERT_LINES))
567  {
568  view->priv->use_horizontal_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
569  GNC_PREF_DRAW_HOR_LINES);
570 
571  view->priv->use_vertical_lines = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
572  GNC_PREF_DRAW_VERT_LINES);
573 
574  if (view->priv->use_horizontal_lines)
575  {
576  if (view->priv->use_vertical_lines)
577  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH);
578  else
579  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
580  }
581  else if (view->priv->use_vertical_lines)
582  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_VERTICAL);
583  else
584  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_NONE);
585  }
586  else
587  {
588  g_warning("gnc_tree_view_split_reg_pref_changed: Unknown preference %s", pref);
589  }
590 }
591 
592 
593 /* Define which columns are in which views */
594 static ViewCol *
595 gnc_tree_view_split_reg_get_column_list (GncTreeModelSplitReg *model)
596 {
597  DEBUG("Model-type is %d", model->type);
598 
599  switch (model->type)
600  {
601  case BANK_REGISTER2:
602  case CASH_REGISTER2:
603  case ASSET_REGISTER2:
604  case CREDIT_REGISTER2:
605  case LIABILITY_REGISTER2:
606  case INCOME_REGISTER2:
607  case EXPENSE_REGISTER2:
608  case EQUITY_REGISTER2:
609  case TRADING_REGISTER2:
610  case INCOME_LEDGER2:
611  {
612  static ViewCol col_list[] = {
613  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
614  COL_STATUS, COL_DEBIT, COL_CREDIT, COL_BALANCE, -1};
615  return col_list;
616  }
617  break;
618 
619  case GENERAL_JOURNAL2:
620  {
621  static ViewCol col_list[] = {
622  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
623  COL_STATUS, COL_COMM, COL_VALUE, COL_RATE, COL_AMOUNT, COL_DEBIT, COL_CREDIT, -1};
624  return col_list;
625  }
626  break;
627 
628  case STOCK_REGISTER2:
629  case CURRENCY_REGISTER2:
630  {
631  static ViewCol col_list[] = {
632  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
633  COL_STATUS, COL_AMTVAL, COL_PRICE, COL_DEBIT, COL_CREDIT, COL_BALANCE, -1};
634  return col_list;
635  }
636  break;
637 
638  case RECEIVABLE_REGISTER2:
639  case PAYABLE_REGISTER2:
640  {
641  static ViewCol col_list[] = {
642  COL_DATE, COL_TYPE, COL_DUEDATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID,
643  COL_STATUS, COL_DEBIT, COL_CREDIT, COL_BALANCE, -1};
644  return col_list;
645  }
646 
647  case PORTFOLIO_LEDGER2:
648  {
649  static ViewCol col_list[] = {
650  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
651  COL_STATUS, COL_AMOUNT, COL_PRICE, COL_DEBIT, COL_CREDIT, -1};
652  return col_list;
653  }
654 
655  case SEARCH_LEDGER2:
656  {
657  static ViewCol col_list[] = {
658  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
659  COL_STATUS, COL_DEBIT, COL_CREDIT, -1};
660  return col_list;
661  }
662  break;
663 
664  default:
665  {
666  static ViewCol col_list[] = {
667  COL_DATE, COL_NUMACT, COL_DESCNOTES, COL_TRANSFERVOID, COL_RECN,
668  COL_STATUS,
669  COL_VALUE, COL_AMOUNT, COL_RATE, COL_PRICE, COL_DEBIT, COL_CREDIT,
670  COL_BALANCE, -1};
671  return col_list;
672  }
673  }
674 }
675 
676 
677 /* Creates a treeview with the list of fields */
678 static GncTreeViewSplitReg *
679 gnc_tree_view_split_reg_set_cols (GncTreeViewSplitReg *view,
680  GncTreeModelSplitReg *model,
681  ViewCol col_list[])
682 {
683  int i = 0;
684 
685  while (col_list && col_list[i] != -1) {
686  GList *renderers;
687  GtkCellRenderer *cr0;
688  GtkCellRenderer *cr1;
689  GtkTreeViewColumn *col;
690  ColDef def;
691 
692  int j, ncol = G_N_ELEMENTS (all_tree_view_split_reg_columns);
693 
694  for (j = 0; j < ncol; j++) {
695  if (col_list[i] == all_tree_view_split_reg_columns[j].viewcol) {
696  def = all_tree_view_split_reg_columns[j];
697  break;
698  }
699  }
700  if (j == ncol) {
701  PERR("Failed to find column definition.");
702  i++;
703  continue;
704  }
705  if (col_list[i] == COL_TRANSFERVOID) {
706 
708  GNC_TREE_VIEW (view), def.title, def.pref_name, def.sizer,
709  def.modelcol, def.visibility_model_col,
710  GTK_TREE_MODEL (gnc_tree_model_split_reg_get_acct_list (model)), 0, def.sort_fn);
711 
712  } else if (col_list[i] == COL_DATE) {
714  GNC_TREE_VIEW (view), def.title, def.pref_name, NULL, def.sizer,
715  def.modelcol, def.visibility_model_col, def.sort_fn);
716 
717  } else if (col_list[i] == COL_NUMACT) {
719  GNC_TREE_VIEW (view), def.title, def.pref_name, def.sizer,
720  def.modelcol, def.visibility_model_col,
721  GTK_TREE_MODEL (gnc_tree_model_split_reg_get_action_list (model)), 0, def.sort_fn);
722 
723  // Here we are adding a second renderer, we will use the model to switch between the
724  // two by hiding one so we endup with rows of text or combo renderers.
725  cr1 = gtk_cell_renderer_text_new ();
726  gtk_tree_view_column_pack_start (col, cr1, TRUE);
727  gtk_tree_view_column_add_attribute (col, cr1, "visible", GNC_TREE_MODEL_SPLIT_REG_COL_NUM_VIS);
728 
729  // Set all the same properties as the first renderer.
730  g_object_set (cr1, "xalign", 1.0, NULL);
731  g_object_set_data (G_OBJECT(cr1), "model_column", GINT_TO_POINTER (def.modelcol));
732  g_object_set_data (G_OBJECT(cr1), "column_name", GINT_TO_POINTER (def.pref_name));
733  g_signal_connect (G_OBJECT(cr1), "editing-started", (GCallback) def.editing_started_cb, view);
734  g_signal_connect (G_OBJECT(cr1), "editing-canceled", G_CALLBACK (gtv_sr_editing_canceled_cb), view);
735  g_object_set (G_OBJECT (cr1), "editable", TRUE, NULL);
736  g_signal_connect (G_OBJECT (cr1), "edited", (GCallback) def.edited_cb, view);
737  g_object_set_data (G_OBJECT (cr1), "view_column", GINT_TO_POINTER (def.viewcol));
738  gtk_tree_view_column_set_cell_data_func (col, cr1, gtv_sr_cdf1, view, NULL);
739 
740  } else {
742  GNC_TREE_VIEW (view), def.title, def.pref_name, NULL, def.sizer,
743  def.modelcol, def.visibility_model_col, def.sort_fn);
744  }
745 
746  g_object_set_data (G_OBJECT (col), DEFAULT_VISIBLE, GINT_TO_POINTER (1));
747  g_object_set_data (G_OBJECT (col), ALWAYS_VISIBLE, GINT_TO_POINTER (def.always_visible_col));
748 
749  // Set the properties for the first renderer.
750  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
751  cr0 = g_list_nth_data (renderers, 0);
752  g_list_free (renderers);
753 
754  /* Setup cell background color and default alignment */
755  g_object_set (cr0, "xalign", 1.0, NULL);
756 
757  if (col_list[i] == COL_NUMACT)
758  gtk_tree_view_column_add_attribute (col, cr0, "visible", GNC_TREE_MODEL_SPLIT_REG_COL_ACT_VIS);
759 
760  /* Add the full title for status column to the object for menu creation */
761  if (col_list[i] == COL_STATUS)
762  g_object_set_data_full (G_OBJECT(col), REAL_TITLE, g_strdup (_("Status Bar")), g_free);
763 
764  /* This sets the background of the treeview control columns */
765  gnc_tree_view_set_control_column_background (GNC_TREE_VIEW (view), 0, gtv_sr_control_cdf0);
766 
767  if (def.editing_started_cb)
768  {
769  //Store the position of the column in the model
770  g_object_set_data (G_OBJECT (cr0), "model_column", GINT_TO_POINTER (def.modelcol));
771  g_object_set_data (G_OBJECT (cr0), "column_name", GINT_TO_POINTER (def.pref_name));
772  g_signal_connect (G_OBJECT (cr0), "editing-started", (GCallback) def.editing_started_cb, view);
773  }
774 
775  // Connect editing-canceled signal so that edit-cancelled can be set appropriately
776  g_signal_connect (G_OBJECT (cr0), "editing-canceled", G_CALLBACK (gtv_sr_editing_canceled_cb), view);
777 
778  gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_FIXED);
779 
780 // gtk_tree_view_column_set_min_width (col, -1);
781 
782  // Set Columns to be resizable default.
783  g_object_set (G_OBJECT (col), "resizable", TRUE, NULL);
784 
785  // Allow the columns to be reorderable.
786  g_object_set (G_OBJECT (col), "reorderable", TRUE, NULL);
787 
788  if (def.edited_cb)
789  {
790  g_object_set (G_OBJECT (cr0), "editable", TRUE, NULL);
791  g_signal_connect (G_OBJECT (cr0), "edited", (GCallback) def.edited_cb, view);
792  }
793 
794  g_object_set_data (G_OBJECT (cr0), "view_column", GINT_TO_POINTER (def.viewcol));
795  gtk_tree_view_column_set_cell_data_func (col, cr0, gtv_sr_cdf0, view, NULL);
796 
797  i++;
798  }
799  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), GTK_SELECTION_BROWSE);
800 
801  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), "changed", G_CALLBACK (gtv_sr_motion_cb), view);
802 
803  //Add a data-edited property to keep track of transaction edits.
804  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
805 
806  // This is used to move the selected item if the selected transaction is deleted.
807  g_signal_connect (G_OBJECT (model), "selection_move_delete", G_CALLBACK (gtv_sr_selection_move_delete_cb), view);
808 
809  // This will refresh the view.
810  g_signal_connect (G_OBJECT (model), "refresh_view", G_CALLBACK (gtv_sr_refresh_view_cb), view);
811 
812  // This is for key navigation, tabbing...
813  g_signal_connect (G_OBJECT (view), "key-press-event", G_CALLBACK (gtv_sr_key_press_cb), NULL);
814 
815  // This is for mouse buttons...
816  g_signal_connect (G_OBJECT (view), "button_press_event", G_CALLBACK (gtv_sr_button_cb), NULL);
817 
818  return view;
819 }
820 
821 
822 /* Set up the view */
823 gboolean
824 gnc_tree_view_split_reg_set_format (GncTreeViewSplitReg *view)
825 {
827  GncTreeModelSplitReg *model;
828  GtkTreePath *mpath, *spath;
829  gint total_num = 0;
830 
831  ENTER(" #### Set View Format #### ");
832 
833  model = gnc_tree_view_split_reg_get_model_from_view (view);
834 
835  priv = view->priv;
836 
837  total_num = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
838 
839  mpath = gtk_tree_row_reference_get_path (view->priv->current_ref);
840 
841  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
842 
843  priv->expanded = FALSE;
844 
845  {
846  if (model->style == REG2_STYLE_JOURNAL)
847  {
848  gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
849 
850  priv->expanded = TRUE;
851 
852  gtk_tree_path_free (mpath);
853  gtk_tree_path_free (spath);
854 
855  /* This updates the plugin page gui */
857 
858  LEAVE("#### Journal format ####");
859  return (FALSE);
860  }
861 
862  if (!model->use_double_line)
863  {
864  gtk_tree_view_collapse_all (GTK_TREE_VIEW (view));
865 
866  priv->expanded = FALSE;
867 
868  LEAVE("#### Single line format ####");
869  }
870 
871  if (model->use_double_line)
872  {
873  gint index = 0;
874  GtkTreePath *path;
875 
876  path = gtk_tree_path_new_first ();
877  while (index < total_num)
878  {
879  gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), path);
880  gtk_tree_path_down (path);
881  gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), path);
882  gtk_tree_path_up (path);
883  gtk_tree_path_next (path); //Next Transaction
884  index = index + 1;
885  }
886  gtk_tree_path_free (path);
887  LEAVE("#### Double line format ####");
888  }
889 
890  /* This expands to split from top level auto.. */
891  if ((model->style == REG2_STYLE_AUTO_LEDGER) || (model->style == REG2_STYLE_JOURNAL))
892  {
893  gtk_tree_view_expand_row (GTK_TREE_VIEW (view), spath, TRUE);
894 
895  priv->expanded = TRUE;
896  LEAVE("#### Auto expand line format ####");
897  }
898  }
899 
900  gtk_tree_path_free (mpath);
901  gtk_tree_path_free (spath);
902 
903  /* This updates the plugin page gui */
905 
906  return (FALSE);
907 }
908 
909 
910 /* Set up the view for this transaction, used in transaction discard and cancel */
911 static gboolean
912 gnc_tree_view_split_reg_format_trans (GncTreeViewSplitReg *view, Transaction *trans)
913 {
915  GncTreeModelSplitReg *model;
916  GtkTreePath *mpath, *spath;
917 
918  ENTER(" ");
919 
920  model = gnc_tree_view_split_reg_get_model_from_view (view);
921 
922  priv = view->priv;
923 
924  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, trans);
925 
926  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
927 
928  if ((!model->use_double_line) && (model->style != REG2_STYLE_JOURNAL))
929  {
930  gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), spath);
931  priv->expanded = FALSE;
932  LEAVE("#### Single line transaction format ####");
933  }
934 
935  if ((model->use_double_line) && (model->style != REG2_STYLE_JOURNAL))
936  {
937  gtk_tree_view_expand_to_path (GTK_TREE_VIEW (view), spath);
938  gtk_tree_path_down (spath);
939  gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), spath);
940  gtk_tree_path_up (spath);
941  priv->expanded = FALSE;
942  LEAVE("#### Double line transaction format ####");
943  }
944 
945  /* This expands to split from top level auto.. */
946  if ((model->style == REG2_STYLE_AUTO_LEDGER) || (model->style == REG2_STYLE_JOURNAL))
947  {
948  gtk_tree_view_expand_row (GTK_TREE_VIEW (view), spath, TRUE);
949  priv->expanded = TRUE;
950  LEAVE("#### Auto expand line transaction format ####");
951  }
952 
953  gtk_tree_path_free (mpath);
954  gtk_tree_path_free (spath);
955 
956  /* This updates the plugin page gui */
958 
959  return (FALSE);
960 }
961 
962 
963 /* Callback to update the view after transactions are added or deleted */
964 static void
965 gtv_sr_refresh_view_cb (GncTreeModelSplitReg *model, gpointer user_data)
966 {
967  GncTreeViewSplitReg *view = user_data;
968 
969  gnc_tree_view_split_reg_set_format (view);
970 }
971 
972 
973 /* Create a tree view from a given model */
975 gnc_tree_view_split_reg_new_with_model (GncTreeModelSplitReg *model)
976 {
977  GtkTreeModel *s_model;
978  GncTreeViewSplitReg *view;
979  GtkTreeSelection *selection;
980 
981  view = g_object_new (gnc_tree_view_split_reg_get_type(), NULL);
982  g_object_set (view, "name", "gnc-id-split-reg-tree", NULL);
983 
984  view->priv->anchor = gnc_tree_model_split_reg_get_anchor (model);
985  view->priv->reg_comm = xaccAccountGetCommodity (view->priv->anchor);
986  view->priv->reg_currency = gnc_account_or_default_currency (view->priv->anchor, NULL);
987  g_assert (view->priv->reg_currency);
988  g_assert (gnc_commodity_is_currency (view->priv->reg_currency));
989  view->help_text = g_strdup ("Help Text");
990 
991  /* Set the grid lines to be solid */
992  gnc_widget_style_context_add_class (GTK_WIDGET(view), "gnc-class-register2-grid-lines");
993 
994  /* TreeView Grid lines */
995  if (view->priv->use_horizontal_lines)
996  {
997  if (view->priv->use_vertical_lines)
998  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_BOTH);
999  else
1000  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
1001  }
1002  else if (view->priv->use_vertical_lines)
1003  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_VERTICAL);
1004  else
1005  gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (view), GTK_TREE_VIEW_GRID_LINES_NONE);
1006 
1007  // Set the view to fixed height mode...
1008 // gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
1009 
1010  /* Expanders off */
1011  gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (view), FALSE);
1012 
1013  /* Tree Selection */
1014  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1015 
1016  gtk_tree_selection_unselect_all (selection);
1017 
1018  // Setup the sort model
1019  s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (model));
1020 
1021  PINFO("#### After Models are Setup ####");
1022 
1023  /* Set the user_data for the sort callback */
1024  gnc_tree_view_set_sort_user_data (GNC_TREE_VIEW (view), s_model);
1025 
1026  /* Set up the columns */
1027  gnc_tree_view_split_reg_set_cols (view, model, gnc_tree_view_split_reg_get_column_list (model));
1028 
1029  PINFO("#### Before View connected to Model ####");
1030 
1031  // Connect model to tree view
1032  gtk_tree_view_set_model (GTK_TREE_VIEW (view), s_model);
1033  g_object_unref (G_OBJECT (s_model));
1034 
1035  PINFO("#### After View connected to Model ####");
1036 
1037  // Default the sorting to date.
1038  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model),
1039  GNC_TREE_MODEL_SPLIT_REG_COL_DATE,
1040  GTK_SORT_ASCENDING);
1041 
1042  PINFO("#### After Set Default Sort Column ####");
1043 
1044  return view;
1045 }
1046 
1047 
1048 /* This allows the blocking / unblocking of selection */
1049 void
1050 gnc_tree_view_split_reg_block_selection (GncTreeViewSplitReg *view, gboolean block)
1051 {
1052  if (block)
1053  g_signal_handlers_block_by_func (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), gtv_sr_motion_cb, view);
1054  else
1055  g_signal_handlers_unblock_by_func (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), gtv_sr_motion_cb, view);
1056 }
1057 
1058 
1059 /* Set the default selection path */
1060 void
1061 gnc_tree_view_split_reg_default_selection (GncTreeViewSplitReg *view)
1062 {
1063  GncTreeModelSplitReg *model;
1064  GtkTreePath *new_mpath, *mpath, *spath;
1065  gint *indices;
1066 
1067  ENTER("#### Default Selection ####");
1068 
1069  model = gnc_tree_view_split_reg_get_model_from_view (view);
1070 
1071  /* Do we have a current transaction set on the model, use it */
1072  if (model->current_trans != NULL)
1073  view->priv->current_trans = model->current_trans;
1074 
1075  /* Set the default start position to end of list */
1076  if (view->priv->current_trans == NULL)
1077  {
1078  Transaction *btrans;
1079 
1080  btrans = gnc_tree_control_split_reg_get_blank_trans (view);
1081  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, btrans);
1082  view->priv->current_trans = btrans;
1083  }
1084  else
1085  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, view->priv->current_split, view->priv->current_trans);
1086 
1087  indices = gtk_tree_path_get_indices (mpath);
1088 
1089  if (view->priv->current_depth == 2)
1090  new_mpath = gtk_tree_path_new_from_indices (indices[0], indices[1], -1);
1091  else
1092  new_mpath = gtk_tree_path_new_from_indices (indices[0], -1);
1093 
1094  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, new_mpath);
1095 
1096  {
1097  gchar *mstring, *sstring, *tstring;
1098  mstring = gtk_tree_path_to_string (mpath);
1099  sstring = gtk_tree_path_to_string (spath);
1100  tstring = gtk_tree_path_to_string (new_mpath);
1101  DEBUG("default_selection mpath is %s, spath is %s, new path is %s", mstring, sstring, tstring);
1102  g_free (mstring);
1103  g_free (sstring);
1104  g_free (tstring);
1105  }
1106 
1107  if (view->priv->current_ref != NULL)
1108  {
1109  gtk_tree_row_reference_free (view->priv->current_ref);
1110  view->priv->current_ref = NULL;
1111  }
1112  view->priv->current_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), new_mpath);
1113 
1114  /* Update the titles */
1115  gtv_sr_titles (view, view->priv->current_depth);
1116 
1117  /* Make sure blank split is on current transaction */
1118  gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->current_trans, FALSE);
1119 
1120  PINFO("#### Default Selection - After Titles ####");
1121 
1122  /* Set the view format */
1123  gnc_tree_view_split_reg_set_format (view);
1124 
1125  PINFO("#### Default Selection - After View Format ####");
1126 
1127  /* scroll window to show selection */
1128  gnc_tree_view_split_reg_scroll_to_cell (view);
1129 
1130  /* Set cursor to new spath */
1131  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
1132 
1133  gtk_tree_path_free (mpath);
1134  gtk_tree_path_free (spath);
1135  gtk_tree_path_free (new_mpath);
1136 
1137  LEAVE("#### Leave Default Selection ####");
1138 }
1139 
1140 /*###########################################################################*/
1141 
1142 /* Sets read only flag */
1143 void
1144 gnc_tree_view_split_reg_set_read_only (GncTreeViewSplitReg *view, gboolean read_only)
1145 {
1146  GncTreeModelSplitReg *model;
1147 
1148  model = gnc_tree_view_split_reg_get_model_from_view (view);
1149 
1150  model->read_only = read_only;
1151 }
1152 
1153 
1154 /* Return the register commodity */
1155 gnc_commodity *
1156 gnc_tree_view_split_reg_get_reg_commodity (GncTreeViewSplitReg *view)
1157 {
1158  return view->priv->reg_comm;
1159 }
1160 
1161 
1162 /* Returns a Split that matches the current Account */
1163 static Split *
1164 gtv_sr_get_this_split (GncTreeViewSplitReg *view, Transaction *trans)
1165 {
1166  GncTreeModelSplitReg *model;
1167  Account *anchor;
1168 
1169  model = gnc_tree_view_split_reg_get_model_from_view (view);
1170 
1171  anchor = gnc_tree_model_split_reg_get_anchor (model);
1172 
1173  if (xaccTransCountSplits (trans) == 0) // this may be a blank or a reinit trans.
1174  {
1175  if (gnc_tree_model_split_reg_is_blank_split_parent (model, trans))
1176  return gnc_tree_model_split_get_blank_split (model);
1177  }
1178 
1179  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1180  {
1181  Split *split = n->data;
1182  if (anchor == xaccSplitGetAccount (split))
1183  return split;
1184  }
1185  return NULL;
1186 }
1187 
1188 
1189 /* The returned Splits may be newly created and not yet belong to trans. */
1190 static gboolean
1191 gtv_sr_get_split_pair (GncTreeViewSplitReg *view, Transaction *trans, Split **osplit, Split **split)
1192 {
1193  GncTreeModelSplitReg *model;
1194  QofBook *book;
1195 
1196  gint count = xaccTransCountSplits (trans);
1197  Account *anchor = view->priv->anchor;
1198 
1199  book = gnc_get_current_book();
1200 
1201  model = gnc_tree_view_split_reg_get_model_from_view (view);
1202 
1203  if (count == 0) // blank trans
1204  {
1205  *split = gnc_tree_model_split_get_blank_split (model);
1206  xaccSplitSetAccount (*split, anchor);
1207  xaccSplitSetParent (*split, trans);
1208  *osplit = xaccMallocSplit (book);
1209  xaccSplitSetParent (*osplit, trans);
1210  }
1211  else
1212  {
1213  Split *first_split;
1214 
1215  first_split = xaccTransGetSplit (trans, 0);
1216 
1217  if (gnc_tree_util_split_reg_is_multi (first_split)) // multi trans
1218  return FALSE;
1219  else // two split trans
1220  {
1221  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1222  {
1223  Split *s = n->data;
1224  if (anchor == xaccSplitGetAccount (s))
1225  {
1226  *split = s;
1227  break;
1228  }
1229  }
1230  g_assert (*split);
1231  *osplit = xaccSplitGetOtherSplit(*split);
1232  g_assert (*osplit);
1233  }
1234  }
1235  DEBUG("gtv_sr_get_split_pair return - trans is %p, osplit is %p and split %p is set to anchor %p", trans, *osplit, *split, anchor);
1236  return TRUE;
1237 }
1238 
1239 
1240 /* Does this transaction have any Imbalance splits */
1241 static gboolean
1242 gtv_sr_get_imbalance (Transaction *trans)
1243 {
1244  const gchar *acc_name;
1245  const gchar *prefix = _("Imbalance");
1246 
1247  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1248  {
1249  Split *split = n->data;
1250  if (xaccSplitGetAccount (split) != NULL)
1251  {
1252  acc_name = xaccAccountGetName (xaccSplitGetAccount (split));
1253 
1254  if (g_str_has_prefix (acc_name, prefix))
1255  return TRUE;
1256  }
1257  }
1258  return FALSE;
1259 }
1260 
1261 
1262 /* Only allow changes to values if we have valid split accounts */
1263 static gboolean
1264 gtv_sr_have_account (GncTreeViewSplitReg *view, RowDepth depth, gboolean expanded, gboolean is_template, Transaction *trans, Split *split)
1265 {
1266  gboolean gtv_sr_have_account = FALSE;
1267 
1268  DEBUG("gtv_sr_have_account trans %p, split %p, expanded %d, depth %d", trans, split, expanded, depth);
1269 
1270  if ((depth == TRANS1) && !expanded && !gnc_tree_util_split_reg_is_multi (split)) // normal trans
1271  {
1272  if (xaccSplitGetAccount (xaccSplitGetOtherSplit (split)) != NULL)
1273  gtv_sr_have_account = TRUE;
1274  }
1275 
1276  if ((depth == SPLIT3) && (xaccTransCountSplits (trans) == 0)) // blank trans, blank split
1277  gtv_sr_have_account = TRUE;
1278 
1279  if (depth == SPLIT3)
1280  {
1281  if (!is_template) // Are we using a template
1282  {
1283  Account *acc = xaccSplitGetAccount (split);
1284  if (acc != NULL)
1285  {
1287  gtv_sr_have_account = TRUE; // normal split
1288  else
1289  gtv_sr_have_account = FALSE; // trading split
1290  }
1291  }
1292  else
1293  {
1294  if (gnc_tree_util_split_reg_template_get_transfer_entry (split) != NULL)
1295  gtv_sr_have_account = TRUE;
1296  }
1297  }
1298  return gtv_sr_have_account;
1299 }
1300 
1301 /*###########################################################################*/
1302 
1303 /* This cellDataFunc is to set the cell-background property of the control columns. */
1304 static void
1305 gtv_sr_control_cdf0 (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *s_model,
1306  GtkTreeIter *s_iter, gpointer user_data)
1307 {
1308  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
1309  GncTreeModelSplitReg *model;
1310  GtkTreeIter m_iter;
1311  GtkTreePath *mpath;
1312  Transaction *trans;
1313  Split *split;
1314  gboolean is_split, is_blank, is_trow1, is_trow2;
1315  const gchar *row_color;
1316 
1317  gint *indices;
1318 
1319  ENTER("");
1320 
1321  model = gnc_tree_view_split_reg_get_model_from_view (view);
1322 
1323  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), &m_iter, s_iter);
1324 
1325  g_return_if_fail (gnc_tree_model_split_reg_get_split_and_trans (
1326  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1327  &is_trow1, &is_trow2, &is_split, &is_blank,
1328  &split, &trans));
1329 
1330  mpath = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &m_iter);
1331 
1332  indices = gtk_tree_path_get_indices (mpath);
1333 
1334  row_color = gnc_tree_model_split_reg_get_row_color (model, is_trow1, is_trow2, is_split, indices[0]);
1335 
1336  gtk_tree_path_free (mpath);
1337 
1338  /* Set the background color / this works for sorting and deleting transactions */
1339  g_object_set (cell, "cell-background", row_color, (gchar*)NULL);
1340 
1341  LEAVE("");
1342 }
1343 
1344 
1345 /* Instead of setting a different cellDataFunc for each column, we just
1346  collect everything here for the first cell renderer. */
1347 static void
1348 gtv_sr_cdf0 (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *s_model,
1349  GtkTreeIter *s_iter, gpointer user_data)
1350 {
1351  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
1352  GncTreeModelSplitReg *model;
1353  GtkTreeIter m_iter;
1354  GtkTreePath *spath;
1355  ViewCol viewcol;
1356  Transaction *trans;
1357  Split *split;
1358  gboolean is_split, is_blank, is_trow1, is_trow2;
1359  gboolean editable = FALSE, expanded = FALSE;
1360  gboolean read_only = FALSE;
1361  gboolean open_edited = FALSE;
1362  gboolean is_template = FALSE;
1363  gboolean negative_in_red = FALSE;
1364  gboolean show_extra_dates = FALSE;
1365  gnc_numeric num = gnc_numeric_zero();
1366  const gchar *s = "";
1367  const gchar *row_color;
1368  char datebuff[MAX_DATE_LENGTH + 1];
1369  RowDepth depth;
1370  gint *indices;
1371  Account *anchor = view->priv->anchor;
1372  char type;
1373 
1374  ENTER("");
1375 
1376  model = gnc_tree_view_split_reg_get_model_from_view (view);
1377 
1378  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), &m_iter, s_iter);
1379 
1380  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "view_column"));
1381 
1382  g_return_if_fail (gnc_tree_model_split_reg_get_split_and_trans (
1383  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1384  &is_trow1, &is_trow2, &is_split, &is_blank,
1385  &split, &trans));
1386 
1387  spath = gtk_tree_model_get_path (GTK_TREE_MODEL (s_model), s_iter);
1388 
1389  depth = gtk_tree_path_get_depth (spath);
1390 
1391  indices = gtk_tree_path_get_indices (spath);
1392 
1393  row_color = gnc_tree_model_split_reg_get_row_color (model, is_trow1, is_trow2, is_split, indices[0]);
1394 
1395  /* Lets see if the splits are expanded */
1396  if (is_trow1 || is_trow2) // transaction
1397  {
1398  if (is_trow1)
1399  gtk_tree_path_down (spath); /* Move the path down to trow2 */
1400  expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath);
1401  }
1402  else
1403  expanded = TRUE; // splits are always expanded
1404 
1405  gtk_tree_path_free (spath);
1406 
1407  /* Set the background color / this works for sorting and deleting of transactions */
1408  g_object_set (cell, "cell-background", row_color, (gchar*)NULL);
1409 
1410  /* Get the read only model setting */
1411  gtk_tree_model_get (GTK_TREE_MODEL (model), &m_iter, GNC_TREE_MODEL_SPLIT_REG_COL_RO, &read_only, -1);
1412 
1413  /* Are we being edited in other register */
1414  if (xaccTransIsOpen (trans) && (view->priv->dirty_trans != trans))
1415  {
1416  read_only = TRUE;
1417  open_edited = TRUE;
1418  }
1419 
1420  /* Test for a transaction type of invoice, always read only */
1421  type = xaccTransGetTxnType (trans);
1422  if (model->type == RECEIVABLE_REGISTER2 || model->type == PAYABLE_REGISTER2)
1423  {
1424  if (((type == TXN_TYPE_INVOICE) || (type == TXN_TYPE_NONE)) && (view->priv->dirty_trans != trans) && !is_blank)
1425  read_only = TRUE;
1426  }
1427 
1428  /* Is this a template */
1429  is_template = gnc_tree_model_split_reg_get_template (model);
1430 
1431  /* Show negative numbers in red */
1432  negative_in_red = view->priv->negative_in_red;
1433 
1434  switch (viewcol) {
1435  case COL_DATE:
1436  /* Column is DATE */
1437  memset (datebuff, 0, sizeof(datebuff));
1438  if (is_split)
1439  g_object_set (cell, "cell-background", "white", (gchar*)NULL);
1440 
1441  // Show the extra dates for selected transaction
1442  if ((view->priv->current_trans == trans) && view->priv->show_extra_dates_on_selection)
1443  show_extra_dates = TRUE;
1444 
1445  // Show the extra dates always
1446  if (view->show_extra_dates == TRUE)
1447  show_extra_dates = TRUE;
1448 
1449  if (is_trow1) {
1450  time64 t = xaccTransRetDatePosted (trans);
1451  //If the time returned by xaccTransGetDatePostedTS is 0 then assume it
1452  //is a new transaction and set the time to current time to show current
1453  //date on new transactions
1454  if (t == 0)
1455  t = gnc_time (NULL);
1456  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, t);
1457  editable = TRUE;
1458  }
1459  else if (is_trow2 && show_extra_dates) {
1460  time64 t = xaccTransRetDateEntered (trans);
1461  g_object_set (cell, "cell-background", YELLOWCELL, (gchar*)NULL);
1462  //If the time returned by xaccTransGetDateEnteredTS is 0 then assume it
1463  //is a new transaction and set the time to current time to show current
1464  //date on new transactions
1465  if (t == 0)
1466  t = gnc_time (NULL);
1467  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, t);
1468  editable = FALSE;
1469  }
1470  else if (is_split && show_extra_dates) {
1471 
1472  if (xaccSplitGetReconcile (split) == YREC)
1473  {
1474  time64 t = xaccSplitGetDateReconciled (split);
1475  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, t);
1476  }
1477  editable = FALSE;
1478  }
1479  else {
1480  editable = FALSE;
1481  }
1482 
1483  /* Is this a template */
1484  if (is_template && is_trow1)
1485  {
1486  /* Todo: Rethink the restriction. Greek message is "Προγραμματισμένη" */
1487  /* Translators: currently max 34 (ASCII) chars (= 17 or 8 UTF-8 chars depending on the block)
1488  See "MAX_DATE_LENGTH" in https://code.gnucash.org/docs/MAINT/group__Date.html */
1489  strncpy (datebuff, _(" Scheduled "), MAX_DATE_LENGTH);
1490  editable = FALSE;
1491  }
1492  else if (is_template && is_trow2 && show_extra_dates)
1493  {
1494  editable = FALSE;
1495  }
1496  else if (is_template && is_split && show_extra_dates)
1497  {
1498  editable = FALSE;
1499  }
1500 
1501  editable = (read_only == TRUE) ? FALSE : editable;
1502 
1503  /* This will remove the calendar buttons if FALSE */
1504  g_object_set (cell, "use_buttons", view->priv->show_calendar_buttons, NULL );
1505  g_object_set (cell, "text", datebuff, "editable", editable, NULL);
1506  break;
1507 
1508  case COL_DUEDATE:
1509  /* Column is DUE DATE */
1510  memset (datebuff, 0, sizeof(datebuff));
1511  if (is_split)
1512  g_object_set (cell, "cell-background", "white", (gchar*)NULL);
1513 
1514  if (is_trow1) {
1515  /* Only print the due date for invoice transactions */
1516  if (type == TXN_TYPE_INVOICE)
1517  {
1518  time64 t = xaccTransRetDateDue (trans);
1519  qof_print_date_buff (datebuff, MAX_DATE_LENGTH, t);
1520  editable = FALSE;
1521  }
1522  else {
1523  editable = FALSE;
1524  }
1525  }
1526  editable = (read_only == TRUE) ? FALSE : editable;
1527 
1528  g_object_set (cell, "text", datebuff, "editable", editable, NULL);
1529  break;
1530 
1531  case COL_NUMACT:
1532  /* Column is NUM / ACT but relates to ACT */
1533  /* Override default alignment */
1534  g_object_set (cell, "xalign", 0.0, NULL );
1535 
1536  editable = TRUE;
1537 
1538  if (is_trow1)
1539  /* Get per book option */
1540  s = gnc_get_num_action (trans, gtv_sr_get_this_split (view, trans));
1541 
1542  else if (is_trow2 && expanded)
1543  {
1544  /* Get per book option */
1545  if (qof_book_use_split_action_for_num_field (gnc_get_current_book()))
1546  s = gnc_get_action_num (trans, gtv_sr_get_this_split (view, trans));
1547  else
1548  s = "";
1549  editable = FALSE;
1550  }
1551  else if (is_trow2 && !expanded)
1552  {
1553  /* Get per book option */
1554  if (gtv_sr_get_this_split (view, trans) != NULL) // Blank split of blank trans is not child of trans yet.
1555  s = gnc_get_action_num (trans, gtv_sr_get_this_split (view, trans));
1556  else
1557  s = "";
1558  }
1559  else if (is_split)
1560  /* Get split-action with gnc_get_num_action which is the same as
1561  * xaccSplitGetAction with these arguments */
1562  s = gnc_get_num_action (NULL, split);
1563 
1564  editable = (read_only == TRUE) ? FALSE : editable;
1565 
1566  g_object_set (cell, "text", s, "editable", editable, NULL);
1567  break;
1568 
1569  case COL_DESCNOTES:
1570  /* Column is DESCRIPTION / NOTES */
1571  /* Override default alignment */
1572  g_object_set( cell, "xalign", 0.0, NULL );
1573  if (is_trow1)
1574  s = xaccTransGetDescription (trans);
1575  else if (is_trow2)
1576  s = xaccTransGetNotes (trans);
1577  else if (is_split)
1578  s = xaccSplitGetMemo (split);
1579  editable = TRUE;
1580 
1581  editable = (read_only == TRUE) ? FALSE : editable;
1582 
1583  g_object_set (cell, "text", s, "editable", editable, NULL);
1584  break;
1585 
1586  case COL_TRANSFERVOID:
1587  /* Column is TRANSFER / VOID */
1588  /* Not sure if this will stay here, this sets the combo column
1589  0 for short account names, 1 for long */
1590  if (view->priv->acct_short_names)
1591  g_object_set (G_OBJECT (cell), "text-column", 0, NULL );
1592  else
1593  g_object_set (G_OBJECT (cell), "text-column", 1, NULL );
1594 
1595  {
1596  gchar *string = NULL;
1597 
1598  if (is_trow1)
1599  {
1600  if (expanded)
1601  {
1602  string = g_strdup (" "); /* blank-out if splits are visible */
1603  editable = FALSE;
1604  }
1605  else
1606  {
1607  gboolean is_multi;
1608  string = g_strdup (gnc_tree_util_split_reg_get_transfer_entry (gtv_sr_get_this_split (view, trans), &is_multi));
1609 
1610  editable = anchor && !expanded && !is_multi;
1611  }
1612  }
1613  if (is_trow2)
1614  {
1615  string = g_strdup (xaccTransGetVoidReason (trans)); // This is the Void Reason
1616  editable = FALSE;
1617  }
1618  if (is_split)
1619  {
1620  if (!is_template) // Are we using a template
1621  {
1622  Account *acct = xaccSplitGetAccount (split);
1623 
1624  // This will be all but the General Journal which has anchor == NULL
1625  if ((xaccTransCountSplits (trans) == 0) && (anchor != NULL)) // First split on blank transaction
1626  acct = anchor;
1627 
1628  if (acct != NULL)
1629  {
1630  if (view->priv->acct_short_names)
1631  string = g_strdup (xaccAccountGetName (acct));
1632  else
1633  string = gnc_account_get_full_name (acct);
1634 
1635  }
1636  else
1637  string = g_strdup (" ");
1638 
1639  if (anchor == acct && model->type != GENERAL_JOURNAL2 && model->type != SEARCH_LEDGER2)
1640  editable = FALSE;
1641  else
1642  editable = TRUE;
1643  }
1644  else
1645  {
1646  string = g_strdup (gnc_tree_util_split_reg_template_get_transfer_entry (split));
1647  editable = TRUE;
1648  }
1649  }
1650  editable = (read_only == TRUE) ? FALSE : editable;
1651 
1652  g_object_set (cell, "text", string, "editable", editable, NULL);
1653  g_free (string);
1654  }
1655  break;
1656 
1657  case COL_RECN:
1658  /* Column is RECN */
1659  /* Override default alignment */
1660  g_object_set( cell, "xalign", 0.5, NULL );
1661  editable = FALSE;
1662  s = "";
1663  if (is_trow1 && !expanded)
1664  {
1665  Split *this_split;
1666  char rec;
1667 
1668  this_split = gtv_sr_get_this_split (view, trans);
1669 
1670  if (this_split != NULL) // this could be a blank trans
1671  {
1672  rec = xaccSplitGetReconcile (this_split);
1673  if (rec == VREC || rec == FREC)
1674  editable = FALSE;
1675  else
1676  editable = TRUE;
1677 
1678  if (rec != ' ')
1679  s = gnc_get_reconcile_str (rec);
1680  else
1681  s = gnc_get_reconcile_str (NREC);
1682  }
1683  }
1684 
1685  if (is_split)
1686  {
1687  char rec = xaccSplitGetReconcile (split);
1688  if (rec == VREC || rec == FREC)
1689  editable = FALSE;
1690  else
1691  editable = TRUE;
1692 
1693  if (rec != ' ')
1694  s = gnc_get_reconcile_str (rec);
1695  else
1696  s = gnc_get_reconcile_str (NREC);
1697  }
1698 
1699  editable = (read_only == TRUE) ? FALSE : editable;
1700 
1701  g_object_set (cell, "text", s, "editable", editable, NULL);
1702  break;
1703 
1704  case COL_TYPE:
1705  /* Column is TYPE */
1706  /* Override default alignment */
1707  g_object_set( cell, "xalign", 0.5, NULL );
1708  if (is_split)
1709  g_object_set (cell, "cell-background", "white", (gchar*)NULL);
1710 
1711  if (is_trow1) {
1712  static char ss[2];
1713  if (type == TXN_TYPE_NONE)
1714  type = '?';
1715 
1716  ss[0] = type;
1717  ss[1] = '\0';
1718  editable = TRUE;
1719  g_object_set (cell, "text", ss, NULL);
1720  }
1721  else
1722  {
1723  s = "";
1724  editable = FALSE;
1725  g_object_set (cell, "text", s, NULL);
1726  }
1727 
1728  editable = (read_only == TRUE) ? FALSE : editable;
1729 
1730  g_object_set (cell, "editable", editable, NULL);
1731  break;
1732 
1733  case COL_VALUE:
1734  /* Column is VALUE */
1735  if (is_split)
1736  {
1737  num = xaccSplitGetValue (split);
1738  s = xaccPrintAmount (num, gnc_commodity_print_info (xaccTransGetCurrency (trans), SHOW_SYMBOL));
1739  editable = FALSE;
1740 
1741  if (gtv_sr_get_imbalance (trans))
1742  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1743  }
1744  else
1745  {
1746  s = "";
1747  editable = FALSE;
1748  }
1749 
1750  editable = (read_only == TRUE) ? FALSE : editable;
1751 
1752  // Display negative numbers in red if requested in preferences
1753  if (gnc_numeric_negative_p (num) && negative_in_red)
1754  g_object_set (cell, "foreground", "red", (gchar*)NULL);
1755  else
1756  g_object_set (cell, "foreground", NULL, (gchar*)NULL);
1757 
1758  g_object_set (cell, "text", s, "editable", editable, NULL);
1759  break;
1760 
1761  case COL_RATE:
1762  /* Column is RATE */
1763  if ((is_trow1)||(is_trow2))
1764  {
1765  s = "";
1766  editable = FALSE;
1767  }
1768  else
1769  {
1770  GNCPrintAmountInfo print_info =
1771  gnc_default_price_print_info(xaccTransGetCurrency(trans));
1772  num = gnc_tree_util_get_rate_for (view, trans, split, is_blank);
1773 
1774  if (gnc_numeric_check (num) == GNC_ERROR_OK)
1775  s = xaccPrintAmount (num, print_info);
1776  else
1777  s = "";
1778 
1779  editable = FALSE;
1780 
1781  if (gtv_sr_get_imbalance (trans))
1782  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1783  }
1784 
1785  editable = (read_only == TRUE) ? FALSE : editable;
1786 
1787  g_object_set (cell, "text", s, "editable", editable, NULL);
1788  break;
1789 
1790  case COL_AMOUNT:
1791  /* Column is AMOUNT */
1792  if (is_split && (anchor == NULL))
1793  {
1794  num = xaccSplitGetAmount (split);
1795  s = xaccPrintAmount (num, gnc_account_print_info (xaccSplitGetAccount (split), SHOW_SYMBOL));
1796  editable = FALSE;
1797 
1798  if (gtv_sr_get_imbalance (trans))
1799  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1800  }
1801  else if (is_split && (anchor))
1802  {
1803  gnc_commodity *split_comm;
1804  split_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split));
1805 
1806  if (!gnc_commodity_is_currency (split_comm) || (is_blank))
1807  {
1808  num = xaccSplitGetAmount (split);
1809  s = xaccPrintAmount (num, gnc_account_print_info (xaccSplitGetAccount (split), SHOW_SYMBOL));
1810  editable = TRUE;
1811  }
1812 
1813  if (gtv_sr_get_imbalance (trans))
1814  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1815  }
1816  else
1817  {
1818  s = "";
1819  editable = FALSE;
1820  }
1821 
1822  editable = (read_only == TRUE) ? FALSE : editable;
1823 
1824  // Display negative numbers in red if requested in preferences
1825  if (gnc_numeric_negative_p (num) && negative_in_red)
1826  g_object_set (cell, "foreground", "red", (gchar*)NULL);
1827  else
1828  g_object_set (cell, "foreground", NULL, (gchar*)NULL);
1829 
1830  g_object_set (cell, "text", s, "editable", editable, NULL);
1831  break;
1832 
1833  case COL_AMTVAL:
1834  /* Column is AMOUNT / VALUE */
1835  if (is_trow2)
1836  {
1837  s = "";
1838  }
1839  else if (is_trow1) // Value
1840  {
1841  if (anchor)
1842  {
1843  Split *this_split;
1844 
1845  num = xaccTransGetAccountValue (trans, anchor);
1846 
1847  if (expanded)
1848  s = "";
1849  else
1850  s = xaccPrintAmount (num, gnc_commodity_print_info (xaccTransGetCurrency (trans), SHOW_SYMBOL));
1851  }
1852  else
1853  {
1854  s = "";
1855  }
1856  }
1857 
1858  if (is_split) // Amount
1859  {
1860  if (anchor == NULL)
1861  {
1862  num = xaccSplitGetAmount (split);
1863  s = xaccPrintAmount (num, gnc_account_print_info (xaccSplitGetAccount (split), SHOW_SYMBOL));
1864  }
1865  else if (anchor)
1866  {
1867  gnc_commodity *split_comm;
1868  split_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split));
1869 
1870  if (!gnc_commodity_is_currency (split_comm) || (is_blank))
1871  {
1872  num = xaccSplitGetAmount (split);
1873  s = xaccPrintAmount (num, gnc_account_print_info (xaccSplitGetAccount (split), SHOW_SYMBOL));
1874  }
1875  }
1876  else
1877  {
1878  s = "";
1879  }
1880 
1881  if (gtv_sr_get_imbalance (trans))
1882  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1883  }
1884 
1885  /* Only allow changes to entries if we have a valid split accounts */
1886  editable = gtv_sr_have_account (view, depth, expanded, is_template, trans, split);
1887 
1888  editable = (read_only == TRUE) ? FALSE : editable;
1889 
1890  // Display negative numbers in red if requested in preferences
1891  if (gnc_numeric_negative_p (num) && negative_in_red)
1892  g_object_set (cell, "foreground", "red", (gchar*)NULL);
1893  else
1894  g_object_set (cell, "foreground", NULL, (gchar*)NULL);
1895 
1896  g_object_set (cell, "text", s, "editable", editable, NULL);
1897  break;
1898 
1899  case COL_PRICE:
1900  /* Column is PRICE */
1901  if (is_trow2)
1902  {
1903  s = "";
1904  }
1905  else if (is_trow1)
1906  {
1907  if (expanded)
1908  {
1909  s = "";
1910  }
1911  else
1912  {
1913  if (anchor)
1914  {
1915  Split *this_split;
1916 
1917  this_split = gtv_sr_get_this_split (view, trans);
1918  if (this_split != NULL) // this could be a blank split
1919  {
1920  if (gnc_tree_util_split_reg_is_multi (this_split))
1921  num = gnc_numeric_zero();
1922  else
1923  num = xaccSplitGetSharePrice (this_split);
1924 
1925  if (gnc_numeric_check (num) == GNC_ERROR_OK)
1926  {
1927  s = xaccPrintAmount (num, gnc_split_amount_print_info (split, SHOW_SYMBOL));
1928  }
1929  else
1930  {
1931  s = "";
1932  }
1933  }
1934  else
1935  {
1936  s = "";
1937  }
1938  }
1939  }
1940  }
1941 
1942  if (is_split)
1943  {
1944  gnc_commodity *split_comm;
1945  split_comm = xaccAccountGetCommodity (xaccSplitGetAccount (split));
1946 
1947  if (!gnc_commodity_is_currency (split_comm) || (is_blank))
1948  {
1949  num = xaccSplitGetSharePrice (split);
1950 
1951  if (gnc_numeric_check (num) == GNC_ERROR_OK)
1952  {
1953  s = xaccPrintAmount (num, gnc_split_amount_print_info (split, SHOW_SYMBOL));
1954  }
1955  else
1956  {
1957  s = "";
1958  }
1959  }
1960  else
1961  {
1962  s = "";
1963  }
1964 
1965  if (gtv_sr_get_imbalance (trans))
1966  g_object_set(cell, "cell-background", PINKCELL, (gchar*)NULL);
1967  }
1968 
1969  /* Only allow changes to entries if we have a valid split accounts */
1970  editable = gtv_sr_have_account (view, depth, expanded, is_template, trans, split);
1971 
1972  editable = (read_only == TRUE) ? FALSE : editable;
1973 
1974  g_object_set (cell, "text", s, "editable", editable, NULL);
1975  break;
1976 
1977  case COL_DEBIT:
1978  case COL_CREDIT:
1979  /* Column is CREDIT and DEBIT */
1980  {
1981  if (!is_template) // Is this a template
1982  {
1983  GNCPrintAmountInfo print_info;
1984  print_info = gnc_account_print_info (anchor, SHOW_SYMBOL);
1985 
1986  if (is_split)
1987  {
1988  if (!gnc_tree_util_split_reg_get_debcred_entry (view, trans, split, is_blank, &num, &print_info))
1989  num = gnc_numeric_zero();
1990 
1991  if (gtv_sr_get_imbalance (trans))
1992  g_object_set (cell, "cell-background", PINKCELL, (gchar*)NULL);
1993  }
1994  else if (is_trow1)
1995  {
1996  if (anchor)
1997  {
1998  num = xaccTransGetAccountAmount (trans, anchor);
1999  }
2000  else
2001  {
2002  num = gnc_numeric_zero();
2003  }
2004  }
2005  else if (is_trow2)
2006  {
2007  num = gnc_numeric_zero();
2008  }
2009 
2010  if ((gnc_numeric_check(num) != GNC_ERROR_OK) ||
2011  gnc_numeric_zero_p(num) ||
2012  (gnc_numeric_negative_p(num) && viewcol == COL_DEBIT) ||
2013  (gnc_numeric_positive_p(num) && viewcol == COL_CREDIT))
2014  {
2015  s = "";
2016  }
2017  else
2018  {
2019  if ((is_trow1 || is_trow2) && expanded)
2020  s = "";
2021  else
2022  s = xaccPrintAmount (gnc_numeric_abs (num), print_info);
2023  }
2024  }
2025  else
2026  {
2027 
2028  if (is_trow1 || is_trow2)
2029  {
2030  s = "";
2031  }
2032  else if (is_split && viewcol == COL_DEBIT)
2033  s = gnc_tree_util_split_reg_template_get_fdebt_entry (split);
2034  else
2035  s = gnc_tree_util_split_reg_template_get_fcred_entry (split);
2036  }
2037 
2038  /* Only allow changes to entries if we have a valid split accounts */
2039  editable = gtv_sr_have_account (view, depth, expanded, is_template, trans, split);
2040  }
2041 
2042  editable = (read_only == TRUE) ? FALSE : editable;
2043 
2044  g_object_set (cell, "text", s, "editable", editable, NULL);
2045  break;
2046 
2047  case COL_BALANCE:
2048  /* Column is BALANCE */
2049  if (is_split)
2050  g_object_set(cell, "cell-background", "white", (gchar*)NULL);
2051 
2052  if (is_trow1 && anchor) {
2053  num = xaccTransGetAccountBalance (trans, anchor);
2054  if (gnc_reverse_balance (anchor))
2055  num = gnc_numeric_neg (num);
2056  s = xaccPrintAmount (num, gnc_account_print_info(anchor, FALSE));
2057 
2058  // Display negative numbers in red if requested in preferences
2059  if (gnc_numeric_negative_p (num) && negative_in_red)
2060  g_object_set (cell, "foreground", "red", (gchar*)NULL);
2061  else
2062  g_object_set (cell, "foreground", NULL, (gchar*)NULL);
2063  } else {
2064  s = "";
2065  }
2066  g_object_set (cell, "text", s, "editable", FALSE, NULL);
2067  break;
2068 
2069  case COL_STATUS:
2070  /* Column is STATUS */
2071  if (read_only && !open_edited)
2072  g_object_set(cell, "cell-background", REDCELL, (gchar*)NULL);
2073  else if (read_only && open_edited)
2074  g_object_set(cell, "cell-background", ORANGECELL, (gchar*)NULL);
2075  else if (xaccTransInFutureByPostedDate (trans))
2076  g_object_set(cell, "cell-background", BLUECELL, (gchar*)NULL);
2077  else
2078  g_object_set(cell, "cell-background", BLACKCELL, (gchar*)NULL);
2079  break;
2080 
2081  case COL_COMM:
2082  /* Column COMMODITY */
2083  {
2084  gchar *string = NULL;
2085  if (is_split)
2086  {
2087  gnc_commodity *split_com, *txn_com;
2088 
2089  split_com = xaccAccountGetCommodity (xaccSplitGetAccount(split));
2090  txn_com = xaccTransGetCurrency (trans);
2091  if (split_com == txn_com)
2092  string = g_strconcat (gnc_commodity_get_printname (split_com), "*", NULL);
2093  else
2094  string = g_strdup (gnc_commodity_get_printname (split_com));
2095  }
2096  else
2097  string = g_strdup ("");
2098 
2099  g_object_set (cell, "text", string, "editable", FALSE, NULL);
2100  g_free (string);
2101  }
2102  break;
2103 
2104  default:
2105  break;
2106  }
2107  LEAVE("");
2108 }
2109 
2110 
2111 /* Instead of setting a different cellDataFunc for each column, we just
2112  collect everything here for the second cell renderer. */
2113 static void
2114 gtv_sr_cdf1 (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *s_model,
2115  GtkTreeIter *s_iter, gpointer user_data)
2116 {
2117  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
2118  GncTreeModelSplitReg *model;
2119  GtkTreeIter m_iter;
2120  GtkTreePath *spath;
2121  ViewCol viewcol;
2122  Transaction *trans;
2123  Split *split;
2124  gboolean is_split, is_blank, is_trow1, is_trow2;
2125  gboolean editable = FALSE, expanded = FALSE;
2126  gboolean read_only = FALSE;
2127 // gboolean open_edited = FALSE;
2128  const gchar *s = "";
2129  const gchar *row_color;
2130 // RowDepth depth;
2131  gint *indices;
2132 // Account *anchor = view->priv->anchor;
2133  char type;
2134 
2135  ENTER("");
2136 
2137  model = gnc_tree_view_split_reg_get_model_from_view (view);
2138 
2139  gtk_tree_model_sort_convert_iter_to_child_iter (GTK_TREE_MODEL_SORT (s_model), &m_iter, s_iter);
2140 
2141  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "view_column"));
2142 
2143  g_return_if_fail (gnc_tree_model_split_reg_get_split_and_trans (
2144  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
2145  &is_trow1, &is_trow2, &is_split, &is_blank,
2146  &split, &trans));
2147 
2148  spath = gtk_tree_model_get_path (GTK_TREE_MODEL (s_model), s_iter);
2149 
2150 // depth = gtk_tree_path_get_depth (spath);
2151 
2152  indices = gtk_tree_path_get_indices (spath);
2153 
2154  row_color = gnc_tree_model_split_reg_get_row_color (model, is_trow1, is_trow2, is_split, indices[0]);
2155 
2156  /* Lets see if the splits are expanded */
2157  if (is_trow1 || is_trow2) // transaction
2158  {
2159  if (is_trow1)
2160  gtk_tree_path_down (spath); /* Move the path down to trow2 */
2161  expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath);
2162  }
2163  else
2164  expanded = TRUE; // splits are always expanded
2165 
2166  gtk_tree_path_free (spath);
2167 
2168  /* Set the background color / this works for sorting and deleting of transactions */
2169  g_object_set (cell, "cell-background", row_color, (gchar*)NULL);
2170 
2171  /* Get the read only model setting */
2172  gtk_tree_model_get (GTK_TREE_MODEL (model), &m_iter, GNC_TREE_MODEL_SPLIT_REG_COL_RO, &read_only, -1);
2173 
2174  /* Are we being edited in other register */
2175  if (xaccTransIsOpen (trans) && (view->priv->dirty_trans != trans))
2176  {
2177  read_only = TRUE;
2178 // open_edited = TRUE;
2179  }
2180 
2181  /* Test for a transaction type of invoice, always read only */
2182  type = xaccTransGetTxnType (trans);
2183  if (model->type == RECEIVABLE_REGISTER2 || model->type == PAYABLE_REGISTER2)
2184  {
2185  if (((type == TXN_TYPE_INVOICE) || (type == TXN_TYPE_NONE)) && (view->priv->dirty_trans != trans) && !is_blank)
2186  read_only = TRUE;
2187  }
2188 
2189  switch (viewcol) {
2190  case COL_DATE:
2191  /* Column is DATE */
2192  break;
2193 
2194  case COL_DUEDATE:
2195  /* Column is DUE DATE */
2196  break;
2197 
2198  case COL_NUMACT:
2199  /* Column is NUM / ACT but relates to NUM */
2200  /* Override default alignment */
2201  g_object_set (cell, "xalign", 0.0, NULL );
2202 
2203  editable = TRUE;
2204 
2205  if (is_trow1)
2206  {
2207  /* Get per book option */
2208  s = gnc_get_num_action (trans, gtv_sr_get_this_split (view, trans));
2209  }
2210  else if (is_trow2 && expanded)
2211  {
2212  /* Get per book option */
2213  if (qof_book_use_split_action_for_num_field (gnc_get_current_book()))
2214  s = gnc_get_action_num (trans, gtv_sr_get_this_split (view, trans));
2215  else
2216  s = "";
2217  editable = FALSE;
2218  }
2219  else if (is_trow2 && !expanded)
2220  {
2221  /* Get per book option */
2222  if (qof_book_use_split_action_for_num_field (gnc_get_current_book()))
2223  {
2224  if (gtv_sr_get_this_split (view, trans) != NULL) // Blank split of blank trans is not child of trans yet.
2225  s = gnc_get_action_num (trans, gtv_sr_get_this_split (view, trans));
2226  else
2227  s = "";
2228  }
2229  else
2230  {
2231  s = "XY";
2232  }
2233  }
2234  else if (is_split)
2235  {
2236  s = "XZ";
2237  }
2238 
2239  editable = (read_only == TRUE) ? FALSE : editable;
2240 
2241  g_object_set (cell, "text", s, "editable", editable, NULL);
2242  break;
2243 
2244  case COL_DESCNOTES:
2245  /* Column is DESCRIPTION / NOTES */
2246  break;
2247 
2248  case COL_TRANSFERVOID:
2249  /* Column is TRANSFER / VOID */
2250  break;
2251 
2252  case COL_RECN:
2253  /* Column is RECN */
2254  break;
2255 
2256  case COL_TYPE:
2257  /* Column is TYPE */
2258  break;
2259 
2260  case COL_VALUE:
2261  /* Column is VALUE */
2262  break;
2263 
2264  case COL_RATE:
2265  /* Column is RATE */
2266  break;
2267 
2268  case COL_AMOUNT:
2269  /* Column is AMOUNT */
2270  break;
2271 
2272  case COL_AMTVAL:
2273  /* Column is AMOUNT / VALUE */
2274  break;
2275 
2276  case COL_PRICE:
2277  /* Column is PRICE */
2278  break;
2279 
2280  case COL_DEBIT:
2281  case COL_CREDIT:
2282  /* Column is CREDIT and DEBIT */
2283  break;
2284 
2285  case COL_BALANCE:
2286  /* Column is BALANCE */
2287  break;
2288 
2289  case COL_STATUS:
2290  /* Column is STATUS */
2291  break;
2292 
2293  case COL_COMM:
2294  /* Column COMMODITY */
2295  break;
2296 
2297  default:
2298  break;
2299  }
2300  LEAVE("");
2301 }
2302 
2303 
2304 /*###########################################################################*/
2305 
2306 /* Returns TRUE if dialog was canceled or discarded.
2307  Does nothing if 'new_trans' is the dirty trans. */
2308 static gboolean
2309 gtv_sr_transaction_changed_confirm (GncTreeViewSplitReg *view,
2310  Transaction *new_trans)
2311 {
2312  GtkWidget *dialog, *window;
2313  GncTreeModelSplitReg *model;
2314  Split *split;
2315  gint response;
2316  const char *title = _("Save the changed transaction?");
2317  const char *message = _(
2318  "The current transaction has changed. Would you like to "
2319  "record the changes, or discard the changes?");
2320 
2321  // Look for dirty_trans not being new_trans.
2322  if (!view->priv->dirty_trans || view->priv->dirty_trans == new_trans)
2323  return FALSE;
2324 
2325  model = gnc_tree_view_split_reg_get_model_from_view (view);
2326 
2327  // If using trading accounts, lets scrub them to make them work.
2328  if (xaccTransUseTradingAccounts (view->priv->dirty_trans))
2329  {
2330  Account *default_account = gnc_tree_model_split_reg_get_anchor (model);
2331  if (default_account != NULL)
2332  xaccTransScrubImbalance (view->priv->dirty_trans, gnc_account_get_root(default_account), NULL);
2333  else
2334  {
2335  Account *root = gnc_book_get_root_account (gnc_get_current_book());
2336  xaccTransScrubImbalance (view->priv->dirty_trans, root, NULL);
2337  }
2338  }
2339 
2340  // Test if the transaction is balanced.
2341  if (gnc_tree_control_split_reg_balance_trans (view, view->priv->dirty_trans))
2342  {
2343  view->priv->trans_confirm = CANCEL;
2344  return TRUE;
2345  }
2346 
2347  window = gnc_tree_view_split_reg_get_parent (view);
2348  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
2349  GTK_DIALOG_DESTROY_WITH_PARENT,
2350  GTK_MESSAGE_QUESTION,
2351  GTK_BUTTONS_NONE,
2352  "%s", title);
2353  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2354  "%s", message);
2355 
2356  gtk_dialog_add_buttons (GTK_DIALOG(dialog),_("_Discard Changes"), GTK_RESPONSE_REJECT,
2357  _("_Cancel"), GTK_RESPONSE_CANCEL,
2358  _("_Record Changes"), GTK_RESPONSE_ACCEPT, NULL);
2359 
2360  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_TRANS_MOD);
2361  gtk_widget_destroy (dialog);
2362 
2363  switch (response)
2364  {
2365  case GTK_RESPONSE_ACCEPT:
2366  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
2367  xaccTransCommitEdit (view->priv->dirty_trans);
2368  split = gnc_tree_model_split_get_blank_split (model);
2369  xaccSplitReinit (split); // Clear the blank split
2370  view->priv->dirty_trans = NULL;
2371  view->change_allowed = FALSE;
2372  view->priv->auto_complete = FALSE;
2373  view->priv->trans_confirm = ACCEPT;
2374  return FALSE;
2375  break;
2376 
2377  case GTK_RESPONSE_REJECT:
2378  if (view->priv->dirty_trans && xaccTransIsOpen (view->priv->dirty_trans))
2379  {
2380  // Move selection to trans - selection is blocked
2381  gnc_tree_control_split_reg_goto_rel_trans_row (view, 0);
2382 
2383  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
2384  xaccTransRollbackEdit (view->priv->dirty_trans);
2385  split = gnc_tree_model_split_get_blank_split (model);
2386  xaccSplitReinit (split); // Clear the blank split
2387  view->change_allowed = FALSE;
2388  view->priv->auto_complete = FALSE;
2389  view->priv->trans_confirm = DISCARD;
2390  }
2391  return TRUE;
2392  break;
2393 
2394  case GTK_RESPONSE_CANCEL:
2395  view->priv->trans_confirm = CANCEL;
2396  return TRUE;
2397  break;
2398 
2399  default:
2400  return FALSE;
2401  }
2402  return FALSE;
2403 }
2404 
2405 
2406 /*###########################################################################
2407  vvvvv edit function call backs vvvvvv
2408 #############################################################################*/
2409 #ifdef skip
2410 static void
2411 start_edit (GtkCellRenderer *cr, GtkCellEditable *editable,
2412  const gchar *path_string, gpointer user_data)
2413 {
2414 // GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
2415 // GncTreeModelSplitReg *model;
2416  GtkTreePath *path;
2417 //g_print("\n\nstart_edit\n");
2418 /*FIXME Not sure if this is required, leave for now ? */
2419 
2420 // model = gnc_tree_view_split_reg_get_model_from_view (view);
2421 
2422  gtv_sr_editable_start_editing_cb (cr, editable, path_string, user_data);
2423 /* g_signal_connect(G_OBJECT(editable), "editing-done", (GCallback) editing_done_cb, view); */
2424 
2425 //FIXME this could be the sort path instead of model path / check !!
2426  path = gtk_tree_path_new_from_string (path_string);
2427 
2428 //FIXME stuff here...
2429 
2430  gtk_tree_path_free (path);
2431 
2432  return;
2433 }
2434 #endif
2435 
2436 /* Open Transaction for editing */
2437 static void
2438 gtv_sr_begin_edit (GncTreeViewSplitReg *view, Transaction *trans)
2439 {
2440  ENTER("gtv_sr_begin_edit trans %p", trans);
2441 
2442  if (trans != view->priv->dirty_trans)
2443  {
2444  time64 time = xaccTransRetDatePosted (trans);
2445  if (!xaccTransIsOpen (trans))
2446  xaccTransBeginEdit (trans);
2447  view->priv->dirty_trans = trans;
2448 
2449  if (!time)
2450  {
2451  //If the time returned by xaccTransGetDatePostedTS is 0 then assume it
2452  //is a new transaction and set the time to current time to show current
2453  //date on new transactions
2454  time = gnc_time (NULL);
2456  }
2457  }
2458  LEAVE(" ");
2459 }
2460 
2461 
2462 /* Call back to remove date widget */
2463 static void
2464 gtv_sr_remove_edit_date (GtkCellEditable *ce, gpointer user_data)
2465 {
2466  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
2467  GncPopupEntry *popup_entry;
2468  const gchar *new_string;
2469  const gchar *current_string;
2470  GDate date;
2471  gchar *date_string;
2472 
2473  ENTER("remove edit date and temp cell rend %p", view->priv->temp_cr);
2474 
2475  if (view->priv->temp_cr != NULL)
2476  {
2477  // These strings are used to determine if cell data was altered so that keynav works better
2478  popup_entry = GNC_POPUP_ENTRY (g_object_get_data (G_OBJECT (view->priv->temp_cr), "cell-editable"));
2479 
2480  new_string = gtk_entry_get_text (GTK_ENTRY (popup_entry->entry));
2481 
2482  current_string = g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-string");
2483 
2484  DEBUG("New string is %s and Current_string is %s", new_string, current_string);
2485 
2486  // If editing wasn't canceled and strings don't match then cell data was edited
2487  if (!GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view->priv->temp_cr), "edit-canceled"))
2488  && g_ascii_strcasecmp (new_string, current_string))
2489  {
2490  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (TRUE));
2491  }
2492 
2493  /* Lets update the help text */
2494  gnc_tree_util_split_reg_parse_date (&date, new_string);
2495  date_string = gnc_tree_util_split_reg_get_date_help (&date);
2496 
2497  if (view->help_text)
2498  g_free (view->help_text);
2499  view->help_text = g_strdup (date_string);
2500 
2501  g_signal_emit_by_name (view, "help_signal", NULL);
2502  g_free (date_string);
2503 
2504  g_object_set_data (G_OBJECT (view->priv->temp_cr), "cell-editable", NULL);
2505  view->priv->temp_cr = NULL;
2506  view->editing_now = FALSE;
2507  }
2508  LEAVE(" ");
2509 }
2510 
2511 
2512 /* Call back to remove combo widget */
2513 static void
2514 gtv_sr_remove_edit_combo (GtkCellEditable *ce, gpointer user_data)
2515 {
2516  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
2517  GtkEntry *entry;
2518  const gchar *new_string;
2519  const gchar *current_string;
2520 
2521  ENTER("remove edit combo and temp cell rend %p", view->priv->temp_cr);
2522 
2523  if (view->priv->temp_cr != NULL)
2524  {
2525  // These strings are used to determine if cell data was altered so that keynav works better
2526  entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (g_object_get_data (G_OBJECT (view->priv->temp_cr), "cell-editable"))));
2527 
2528  new_string = gtk_entry_get_text (GTK_ENTRY (entry));
2529 
2530  current_string = g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-string");
2531 
2532  DEBUG("New string is %s and Current_string is %s", new_string, current_string);
2533 
2534  // If editing wasn't canceled and strings don't match then cell data was edited
2535  if (!GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view->priv->temp_cr), "edit-canceled"))
2536  && g_ascii_strcasecmp (new_string, current_string))
2537  {
2538  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (TRUE));
2539  }
2540 
2541  g_object_set_data (G_OBJECT (view->priv->temp_cr), "cell-editable", NULL);
2542  view->priv->temp_cr = NULL;
2543  view->editing_now = FALSE;
2544  }
2545  LEAVE(" ");
2546 }
2547 
2548 
2549 /* Call back to remove entry widget */
2550 static void
2551 gtv_sr_remove_edit_entry (GtkCellEditable *ce, gpointer user_data)
2552 {
2553  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
2554  const gchar *new_string;
2555  const gchar *current_string;
2556 
2557  ENTER("remove edit entry and temp cell rend %p", view->priv->temp_cr);
2558 
2559  if (view->priv->temp_cr != NULL)
2560  {
2561  // These strings are used to determine if cell data was altered so that keynav works better
2562  new_string = gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (view->priv->temp_cr), "cell-editable")));
2563 
2564  current_string = g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-string");
2565 
2566  DEBUG("New string is %s and Current_string is %s", new_string, current_string);
2567 
2568  // If editing wasn't canceled and strings don't match then cell data was edited
2569  if (!GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view->priv->temp_cr), "edit-canceled"))
2570  && g_ascii_strcasecmp (new_string, current_string))
2571  {
2572  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (TRUE));
2573  }
2574  if (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-flag") != NULL) // flag
2575  g_object_set_data (G_OBJECT (view->priv->temp_cr), "current-flag", NULL);
2576 
2577  g_object_set_data (G_OBJECT (view->priv->temp_cr), "cell-editable", NULL);
2578  view->priv->temp_cr = NULL;
2579  view->editing_now = FALSE;
2580  }
2581  LEAVE(" ");
2582 }
2583 
2584 
2585 /* Explain: GtkEntry has a cursor that blinks upon
2586  g_timeout_dispatch(). It complains if it blinks after the GtkEntry
2587  loses focus. So, we can't pop up any dialogs while the blinking
2588  cursor is around. The solution is to force the editing to be
2589  finished before raising the dialog. That finalizes the
2590  gtkcelleditable. */
2591 static void
2592 gtv_sr_finish_edit (GncTreeViewSplitReg *view)
2593 {
2594  GtkCellEditable *ce;
2595 
2596  if (view->priv->temp_cr == NULL)
2597  return;
2598 
2599  DEBUG("gtv_sr_finish_edit temp_cr is %p", view->priv->temp_cr);
2600 
2601  if ((ce = GTK_CELL_EDITABLE (g_object_get_data (G_OBJECT (view->priv->temp_cr), "cell-editable"))))
2602  {
2603  DEBUG("gtv_sr_finish_edit - editing_done");
2604  gtk_cell_editable_editing_done (ce);
2605  gtk_cell_editable_remove_widget (ce);
2606  }
2607 }
2608 
2609 #ifdef skip
2610 //FIXME Not used yet
2611 /* This is used in g_idle_add to finish an edit */
2612 static gboolean
2613 gtv_sr_idle_finish_edit (GncTreeViewSplitReg *view)
2614 {
2615  gtv_sr_finish_edit (view);
2616  return FALSE;
2617 }
2618 
2619 
2620 /* This is used in g_idle_add to cancel an edit */
2621 static gboolean
2622 gtv_sr_idle_cancel_edit (GtkCellRenderer *cr)
2623 {
2624  GtkCellEditable *ce;
2625 
2626  gtk_cell_renderer_stop_editing (cr, TRUE);
2627 
2628  ce = GTK_CELL_EDITABLE (g_object_get_data (G_OBJECT (cr), "cell-editable"));
2629  gtk_cell_editable_editing_done (ce);
2630  gtk_cell_editable_remove_widget (ce);
2631 
2632  return FALSE;
2633 }
2634 #endif
2635 
2636 /* This is used in g_idle_add to repopulate the transfer cell */
2637 static gboolean
2638 gtv_sr_idle_transfer (GncTreeViewSplitReg *view)
2639 {
2640  GtkTreePath *spath;
2641  GList *columns;
2642  GList *column;
2643  gint i;
2644 
2645  spath = gnc_tree_view_split_reg_get_current_path (view);
2646  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
2647 
2648  for (column = columns, i = 1; column; column = g_list_next (column), i++)
2649  {
2650  GList *renderers;
2651  GtkCellRenderer *cr0;
2652  GtkTreeViewColumn *tvc;
2653  ViewCol viewcol;
2654 
2655  tvc = column->data;
2656 
2657  // Get the first renderer, it has the view-column value.
2658  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tvc));
2659  cr0 = g_list_nth_data (renderers, 0);
2660  g_list_free (renderers);
2661 
2662  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cr0), "view_column"));
2663 
2664  if (viewcol == COL_TRANSFERVOID)
2665  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, tvc, TRUE);
2666  }
2667  g_list_free (columns);
2668  gtk_tree_path_free (spath);
2669  return FALSE;
2670 }
2671 
2672 /*###########################################################################*/
2673 
2674 /* Set the column titles based on register type and depth */
2675 static void
2676 gtv_sr_titles (GncTreeViewSplitReg *view, RowDepth depth)
2677 {
2678  GncTreeModelSplitReg *model;
2679  GtkCellRenderer *cr0;
2680  GList *renderers;
2681  GList *columns;
2682  GList *column;
2683  gint i;
2684  gboolean is_template;
2685 
2686  model = gnc_tree_view_split_reg_get_model_from_view (view);
2687  ENTER("title depth is %d and sort_depth %d, sort_col is %d", depth, model->sort_depth, model->sort_col);
2688 
2689  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
2690 
2691  is_template = gnc_tree_model_split_reg_get_template (model);
2692 
2693  for (column = columns, i = 1; column; column = g_list_next (column), i++)
2694  {
2695  GtkTreeViewColumn *tvc;
2696  ViewCol viewcol;
2697 
2698  tvc = column->data;
2699 
2700  // Get the first renderer, it has the view-column value.
2701  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tvc));
2702  cr0 = g_list_nth_data (renderers, 0);
2703  g_list_free (renderers);
2704 
2705  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cr0), "view_column"));
2706 
2707  DEBUG("viewcol is %d", viewcol);
2708 
2709  switch (viewcol)
2710  {
2711  case COL_DATE:
2712  switch (model->type)
2713  {
2714  default: //FIXME These if statements may not be required
2715  /* Display arrows if we are sorting on this row */
2716  if (model->sort_depth == depth && model->sort_col == viewcol)
2717  gtk_tree_view_column_set_sort_indicator (tvc, TRUE);
2718  else
2719  gtk_tree_view_column_set_sort_indicator (tvc, FALSE);
2720 
2721  if (depth == TRANS1)
2722  gtk_tree_view_column_set_title (tvc, _("Date Posted"));
2723  else if (depth == TRANS2)
2724  gtk_tree_view_column_set_title (tvc, _("Date Entered"));
2725  else if (depth == SPLIT3)
2726  gtk_tree_view_column_set_title (tvc, _("Reconciled Date"));
2727  else
2728  gtk_tree_view_column_set_title (tvc, _("Date Posted / Entered / Reconciled"));
2729  break;
2730  }
2731  break;
2732 
2733  case COL_DUEDATE:
2734  switch (model->type)
2735  {
2736  default: //FIXME These if statements may not be required
2737  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2738  gtk_tree_view_column_set_title (tvc, _("Due Date"));
2739  break;
2740  }
2741  break;
2742 
2743  case COL_NUMACT:
2744  switch (model->type)
2745  {
2746  case RECEIVABLE_REGISTER2:
2747  case PAYABLE_REGISTER2:
2748  if (depth == TRANS1)
2749  gtk_tree_view_column_set_title (tvc, _("Reference"));
2750  else if (depth == TRANS2)
2751  gtk_tree_view_column_set_title (tvc, _("Action"));
2752  else if (depth == SPLIT3)
2753  gtk_tree_view_column_set_title (tvc, _("Action"));
2754  else
2755  gtk_tree_view_column_set_title (tvc, _("Reference / Action"));
2756  break;
2757 
2758 
2759  default:
2760  /* Display arrows if we are sorting on this row */
2761  if (model->sort_depth == depth && model->sort_col == viewcol)
2762  gtk_tree_view_column_set_sort_indicator (tvc, TRUE);
2763  else
2764  gtk_tree_view_column_set_sort_indicator (tvc, FALSE);
2765 
2766  if (depth == TRANS1)
2767  gtk_tree_view_column_set_title (tvc, _("Number"));
2768  else if (depth == TRANS2 && (qof_book_use_split_action_for_num_field (gnc_get_current_book())))
2769  gtk_tree_view_column_set_title (tvc, _("T-Number"));
2770  else if (depth == TRANS2 && (!qof_book_use_split_action_for_num_field (gnc_get_current_book())))
2771  gtk_tree_view_column_set_title (tvc, _("Action"));
2772  else if (depth == SPLIT3)
2773  gtk_tree_view_column_set_title (tvc, _("Action"));
2774  else
2775  gtk_tree_view_column_set_title (tvc, _("Number / Action"));
2776  break;
2777  }
2778  break;
2779 
2780  case COL_DESCNOTES:
2781  switch (model->type)
2782  {
2783  case RECEIVABLE_REGISTER2:
2784  if (depth == TRANS1)
2785  gtk_tree_view_column_set_title (tvc, _("Customer"));
2786  else if (depth == TRANS2)
2787  gtk_tree_view_column_set_title (tvc, _("Memo"));
2788  else if (depth == SPLIT3)
2789  gtk_tree_view_column_set_title (tvc, _("Memo"));
2790  else
2791  gtk_tree_view_column_set_title (tvc, _("Customer / Memo"));
2792  break;
2793 
2794  case PAYABLE_REGISTER2:
2795  if (depth == TRANS1)
2796  gtk_tree_view_column_set_title (tvc, _("Vendor"));
2797  else if (depth == TRANS2)
2798  gtk_tree_view_column_set_title (tvc, _("Memo"));
2799  else if (depth == SPLIT3)
2800  gtk_tree_view_column_set_title (tvc, _("Memo"));
2801  else
2802  gtk_tree_view_column_set_title (tvc, _("Vendor / Memo"));
2803  break;
2804 
2805 
2806  default:
2807  /* Display arrows if we are sorting on this row */
2808  if (model->sort_depth == depth && model->sort_col == viewcol)
2809  gtk_tree_view_column_set_sort_indicator (tvc, TRUE);
2810  else
2811  gtk_tree_view_column_set_sort_indicator (tvc, FALSE);
2812 
2813  if (depth == TRANS1)
2814  gtk_tree_view_column_set_title (tvc, _("Description"));
2815  else if (depth == TRANS2)
2816  gtk_tree_view_column_set_title (tvc, _("Notes"));
2817  else if (depth == SPLIT3)
2818  gtk_tree_view_column_set_title (tvc, _("Memo"));
2819  else
2820  gtk_tree_view_column_set_title (tvc, _("Description / Notes / Memo"));
2821  break;
2822  }
2823  break;
2824 
2825  case COL_TRANSFERVOID:
2826  switch (model->type)
2827  {
2828  case RECEIVABLE_REGISTER2:
2829  case PAYABLE_REGISTER2:
2830  if (depth == TRANS1)
2831  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2832  else if (depth == TRANS2)
2833  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2834  else if (depth == SPLIT3)
2835  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2836  else
2837  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2838  break;
2839 
2840  default:
2841  /* Display arrows if we are sorting on this row */
2842  if (model->sort_depth == depth && model->sort_col == viewcol)
2843  gtk_tree_view_column_set_sort_indicator (tvc, TRUE);
2844  else
2845  gtk_tree_view_column_set_sort_indicator (tvc, FALSE);
2846 
2847  if (depth == TRANS1)
2848  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2849  else if (depth == TRANS2)
2850  gtk_tree_view_column_set_title (tvc, _("Void Reason"));
2851  else if (depth == SPLIT3)
2852  gtk_tree_view_column_set_title (tvc, _("Accounts"));
2853  else
2854  gtk_tree_view_column_set_title (tvc, _("Accounts / Void Reason"));
2855  break;
2856  }
2857  break;
2858 
2859  case COL_RECN:
2860  switch (model->type)
2861  {
2862  default: //FIXME These if statements may not be required
2863  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2864  gtk_tree_view_column_set_title (tvc, _("R"));
2865  break;
2866  }
2867  break;
2868 
2869  case COL_TYPE:
2870  switch (model->type)
2871  {
2872  default: //FIXME These if statements may not be required
2873  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2874  gtk_tree_view_column_set_title (tvc, _("Type"));
2875  break;
2876  }
2877  break;
2878 
2879  case COL_VALUE:
2880  switch (model->type)
2881  {
2882  default: //FIXME These if statements may not be required
2883  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2884  gtk_tree_view_column_set_title (tvc, _("Value"));
2885  break;
2886  }
2887  break;
2888 
2889  case COL_AMOUNT:
2890  switch (model->type)
2891  {
2892  default: //FIXME These if statements may not be required
2893  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2894  gtk_tree_view_column_set_title (tvc, _("Amount"));
2895  break;
2896  }
2897  break;
2898 
2899  case COL_AMTVAL:
2900  switch (model->type)
2901  {
2902  default:
2903  if (depth == TRANS1 || depth == TRANS2)
2904  gtk_tree_view_column_set_title (tvc, _("Value"));
2905  else if (depth == SPLIT3)
2906  gtk_tree_view_column_set_title (tvc, _("Amount"));
2907  else
2908  gtk_tree_view_column_set_title (tvc, _("Amount / Value"));
2909  break;
2910  }
2911  break;
2912 
2913  case COL_COMM:
2914  switch (model->type)
2915  {
2916  default: //FIXME These if statements may not be required
2917  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2918  gtk_tree_view_column_set_title (tvc, _("Commodity"));
2919  break;
2920  }
2921  break;
2922 
2923  case COL_RATE:
2924  switch (model->type)
2925  {
2926  default: //FIXME These if statements may not be required
2927  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2928  gtk_tree_view_column_set_title (tvc, _("Rate"));
2929  break;
2930  }
2931  break;
2932 
2933  case COL_PRICE:
2934  switch (model->type)
2935  {
2936  default: //FIXME These if statements may not be required
2937  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2938  gtk_tree_view_column_set_title (tvc, _("Price"));
2939  break;
2940  }
2941  break;
2942 
2943  case COL_CREDIT:
2944  if(!(model->use_accounting_labels))
2945  {
2946  switch (model->type)
2947  {
2948  case BANK_REGISTER2: //FIXME These if statements may not be required
2949  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2950  gtk_tree_view_column_set_title (tvc, _("Withdrawal"));
2951  break;
2952 
2953  case CASH_REGISTER2:
2954  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2955  gtk_tree_view_column_set_title (tvc, _("Spend"));
2956  break;
2957 
2958  case ASSET_REGISTER2:
2959  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2960  gtk_tree_view_column_set_title (tvc, _("Decrease"));
2961  break;
2962 
2963  case LIABILITY_REGISTER2:
2964  case EQUITY_REGISTER2:
2965  case TRADING_REGISTER2:
2966  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2967  gtk_tree_view_column_set_title (tvc, _("Increase"));
2968  break;
2969 
2970  case CREDIT_REGISTER2:
2971  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2972  gtk_tree_view_column_set_title (tvc, _("Charge"));
2973  break;
2974 
2975  case INCOME_REGISTER2:
2976  case INCOME_LEDGER2:
2977  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2978  gtk_tree_view_column_set_title (tvc, _("Income"));
2979  break;
2980 
2981  case EXPENSE_REGISTER2:
2982  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2983  gtk_tree_view_column_set_title (tvc, _("Rebate"));
2984  break;
2985 
2986  case STOCK_REGISTER2:
2987  case CURRENCY_REGISTER2:
2988  case PORTFOLIO_LEDGER2:
2989  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2990  gtk_tree_view_column_set_title (tvc, _("Sell"));
2991  break;
2992 
2993  case RECEIVABLE_REGISTER2:
2994  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
2995  gtk_tree_view_column_set_title (tvc, _("Payment"));
2996  break;
2997 
2998  case PAYABLE_REGISTER2:
2999  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3000  gtk_tree_view_column_set_title (tvc, _("Bill"));
3001  break;
3002 
3003  case GENERAL_JOURNAL2:
3004  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3005  gtk_tree_view_column_set_title (tvc, _("Funds Out"));
3006  break;
3007 
3008  case SEARCH_LEDGER2:
3009  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3010  {
3011  if (!is_template)
3012  gtk_tree_view_column_set_title (tvc, _("Funds Out"));
3013  else
3014  gtk_tree_view_column_set_title (tvc, _("Credit Formula"));
3015  }
3016  break;
3017 
3018  default:
3019  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3020  gtk_tree_view_column_set_title (tvc, _("Credit"));
3021  break;
3022  }
3023  }
3024  else
3025  gtk_tree_view_column_set_title (tvc, _("Credit"));
3026  break;
3027 
3028  case COL_DEBIT:
3029  if(!(model->use_accounting_labels))
3030  {
3031  switch (model->type)
3032  {
3033  case BANK_REGISTER2: //FIXME These if statements may not be required
3034  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3035  gtk_tree_view_column_set_title (tvc, _("Deposit"));
3036  break;
3037 
3038  case CASH_REGISTER2:
3039  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3040  gtk_tree_view_column_set_title (tvc, _("Receive"));
3041  break;
3042 
3043  case ASSET_REGISTER2:
3044  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3045  gtk_tree_view_column_set_title (tvc, _("Increase"));
3046  break;
3047 
3048  case LIABILITY_REGISTER2:
3049  case EQUITY_REGISTER2:
3050  case TRADING_REGISTER2:
3051  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3052  gtk_tree_view_column_set_title (tvc, _("Decrease"));
3053  break;
3054 
3055  case INCOME_REGISTER2:
3056  case INCOME_LEDGER2:
3057  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3058  gtk_tree_view_column_set_title (tvc, _("Charge"));
3059  break;
3060 
3061  case EXPENSE_REGISTER2:
3062  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3063  gtk_tree_view_column_set_title (tvc, _("Expense"));
3064  break;
3065 
3066  case STOCK_REGISTER2:
3067  case CURRENCY_REGISTER2:
3068  case PORTFOLIO_LEDGER2:
3069  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3070  gtk_tree_view_column_set_title (tvc, _("Buy"));
3071  break;
3072 
3073  case RECEIVABLE_REGISTER2:
3074  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3075  gtk_tree_view_column_set_title (tvc, _("Invoice"));
3076  break;
3077 
3078  case CREDIT_REGISTER2:
3079  case PAYABLE_REGISTER2:
3080  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3081  gtk_tree_view_column_set_title (tvc, _("Payment"));
3082  break;
3083 
3084  case GENERAL_JOURNAL2:
3085  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3086  gtk_tree_view_column_set_title (tvc, _("Funds In"));
3087  break;
3088 
3089  case SEARCH_LEDGER2:
3090  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3091  {
3092  if (!is_template)
3093  gtk_tree_view_column_set_title (tvc, _("Funds In"));
3094  else
3095  gtk_tree_view_column_set_title (tvc, _("Debit Formula"));
3096  }
3097  break;
3098 
3099  default:
3100  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3101  gtk_tree_view_column_set_title (tvc, _("Debit"));
3102  break;
3103  }
3104  }
3105  else
3106  gtk_tree_view_column_set_title (tvc, _("Debit"));
3107  break;
3108 
3109  case COL_BALANCE:
3110  switch (model->type)
3111  {
3112  default: //FIXME These if statements may not be required
3113  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3114  gtk_tree_view_column_set_title (tvc, _("Balance"));
3115  break;
3116  }
3117  break;
3118 
3119  default:
3120  break;
3121  }
3122  }
3123  LEAVE(" ");
3124  g_list_free (columns);
3125 }
3126 
3127 
3128 /* Update the help text */
3129 static void
3130 gtv_sr_help (GncTreeViewSplitReg *view, GtkCellRenderer *cr, ViewCol viewcol, RowDepth depth)
3131 {
3132  GncTreeModelSplitReg *model;
3133  gchar *help = NULL;
3134  const gchar *current_string;
3135 
3136  ENTER("Help Viewcol is %d and depth is %d", viewcol, depth);
3137 
3138  model = gnc_tree_view_split_reg_get_model_from_view (view);
3139 
3140  switch (viewcol)
3141  {
3142  case COL_DATE:
3143  switch (model->type)
3144  {
3145  default: //FIXME These if statements may not be required
3146  if (depth == TRANS1)
3147  {
3148  GDate date;
3149 
3150  current_string = g_object_get_data (G_OBJECT (cr), "current-string");
3151  g_date_set_parse (&date, current_string);
3152  help = gnc_tree_util_split_reg_get_date_help (&date);
3153  }
3154  else
3155  help = g_strdup (" ");
3156  break;
3157  }
3158  break;
3159 
3160  case COL_DUEDATE:
3161  switch (model->type)
3162  {
3163  default: //FIXME These if statements may not be required
3164  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3165  help = g_strdup (_("Enter Due Date"));
3166  break;
3167  }
3168  break;
3169 
3170  case COL_NUMACT:
3171  switch (model->type)
3172  {
3173  case RECEIVABLE_REGISTER2:
3174  case PAYABLE_REGISTER2:
3175  if (depth == TRANS1)
3176  help = g_strdup (_("Enter the transaction reference, such as the invoice or check number"));
3177  else if (depth == TRANS2 || depth == SPLIT3)
3178  help = g_strdup (_("Enter the type of transaction, or choose one from the list"));
3179  break;
3180 
3181  default:
3182  if (depth == TRANS1)
3183  help = g_strdup (_("Enter the transaction number, such as the check number"));
3184  else if (depth == TRANS2 || depth == SPLIT3)
3185  help = g_strdup (_("Enter the type of transaction, or choose one from the list"));
3186  break;
3187  }
3188  break;
3189 
3190  case COL_DESCNOTES:
3191  switch (model->type)
3192  {
3193  case RECEIVABLE_REGISTER2:
3194  if (depth == TRANS1)
3195  help = g_strdup (_("Enter the name of the Customer"));
3196  else if (depth == TRANS2)
3197  help = g_strdup (_("Enter notes for the transaction"));
3198  else if (depth == SPLIT3)
3199  help = g_strdup (_("Enter a description of the split"));
3200  break;
3201 
3202  case PAYABLE_REGISTER2:
3203  if (depth == TRANS1)
3204  help = g_strdup (_("Enter the name of the Vendor"));
3205  else if (depth == TRANS2)
3206  help = g_strdup (_("Enter notes for the transaction"));
3207  else if (depth == SPLIT3)
3208  help = g_strdup (_("Enter a description of the split"));
3209  break;
3210 
3211  default:
3212  if (depth == TRANS1)
3213  help = g_strdup (_("Enter a description of the transaction"));
3214  else if (depth == TRANS2)
3215  help = g_strdup (_("Enter notes for the transaction"));
3216  else if (depth == SPLIT3)
3217  help = g_strdup (_("Enter a description of the split"));
3218  break;
3219  }
3220  break;
3221 
3222  case COL_TRANSFERVOID:
3223  switch (model->type)
3224  {
3225  default:
3226  if (depth == TRANS1)
3227  help = g_strdup (_("Enter the account to transfer from, or choose one from the list"));
3228  else if (depth == TRANS2)
3229  help = g_strdup (_("Reason the transaction was voided"));
3230  else if (depth == SPLIT3)
3231  help = g_strdup (_("Enter the account to transfer from, or choose one from the list"));
3232  break;
3233  }
3234  break;
3235 
3236  case COL_RECN:
3237  switch (model->type)
3238  {
3239  default: //FIXME These if statements may not be required
3240  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3241  help = g_strdup (_("Enter the reconcile type"));
3242  break;
3243  }
3244  break;
3245 
3246  case COL_TYPE:
3247  switch (model->type)
3248  {
3249  default: //FIXME These if statements may not be required
3250  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3251  help = g_strdup (_("Enter the type of transaction"));
3252  break;
3253  }
3254  break;
3255 
3256  case COL_VALUE:
3257  switch (model->type)
3258  {
3259  default: //FIXME These if statements may not be required
3260  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3261  help = g_strdup (_("Enter the value of shares bought or sold"));
3262  break;
3263  }
3264  break;
3265 
3266  case COL_AMOUNT:
3267  switch (model->type)
3268  {
3269  default: //FIXME These if statements may not be required
3270  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3271  help = g_strdup (_("Enter the number of shares bought or sold"));
3272  break;
3273  }
3274  break;
3275 
3276  case COL_AMTVAL:
3277  switch (model->type)
3278  {
3279  default:
3280  if ((depth == TRANS1) || (depth == TRANS2))
3281  help = g_strdup (_("Enter the value of shares bought or sold"));
3282  else if (depth == SPLIT3)
3283  help = g_strdup (_("Enter the number of shares bought or sold"));
3284  break;
3285  }
3286  break;
3287 
3288  case COL_COMM:
3289  switch (model->type)
3290  {
3291  default: //FIXME These if statements may not be required
3292  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3293  help = g_strdup (_("* Indicates the transaction Commodity."));
3294  break;
3295  }
3296  break;
3297 
3298  case COL_RATE:
3299  switch (model->type)
3300  {
3301  default: //FIXME These if statements may not be required
3302  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3303  help = g_strdup (_("Enter the rate"));
3304  break;
3305  }
3306  break;
3307 
3308  case COL_PRICE:
3309  switch (model->type)
3310  {
3311  default: //FIXME These if statements may not be required
3312  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3313  help = g_strdup (_("Enter the effective share price"));
3314  break;
3315  }
3316  break;
3317 
3318  case COL_CREDIT:
3319  switch (model->type)
3320  {
3321  default: //FIXME These if statements may not be required
3322  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3323  help = g_strdup (_("Enter credit formula for real transaction"));
3324  break;
3325  }
3326  break;
3327 
3328  case COL_DEBIT:
3329  switch (model->type)
3330  {
3331  default: //FIXME These if statements may not be required
3332  if (depth == TRANS1 || depth == TRANS2 || depth == SPLIT3)
3333  help = g_strdup (_("Enter debit formula for real transaction"));
3334  break;
3335  }
3336  break;
3337 
3338  default:
3339  help = g_strdup (" ");
3340  break;
3341  }
3342 
3343  LEAVE("Help text is - %s", help);
3344  if (view->help_text)
3345  g_free (view->help_text);
3346  view->help_text = g_strdup (help);
3347  g_free (help);
3348  g_signal_emit_by_name (view, "help_signal", NULL);
3349 }
3350 
3351 /*###########################################################################*/
3352 
3353 /* Move the selection to the blank split when expanded */
3354 static gboolean
3355 gtv_sr_selection_to_blank (GncTreeViewSplitReg *view)
3356 {
3357  GncTreeModelSplitReg *model;
3358  GtkTreePath *bpath, *spath;
3359  Split *bsplit;
3360 
3361  /* give gtk+ a chance to handle pending events */
3362  while (gtk_events_pending ())
3363  gtk_main_iteration ();
3364 
3365  /* Make sure we have expanded splits */
3366  if (view->priv->expanded == FALSE)
3367  return FALSE;
3368 
3369  model = gnc_tree_view_split_reg_get_model_from_view (view);
3370 
3371  bsplit = gnc_tree_model_split_get_blank_split (model);
3372  bpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, bsplit, NULL);
3373 
3374  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, bpath);
3375 
3376  /* Set cursor to new spath */
3377  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
3378 
3379  gtk_tree_path_free (bpath);
3380  gtk_tree_path_free (spath);
3381 
3382  return FALSE;
3383 }
3384 
3385 
3386 /* Call back for when a change to a Transaction requires the selection to get out of the way */
3387 static void
3388 gtv_sr_selection_move_delete_cb (GncTreeModelSplitReg *model, gpointer item, gpointer user_data)
3389 {
3390  GncTreeViewSplitReg *view = user_data;
3391  Transaction *trans = item;
3392 
3393  DEBUG("gtv_sr_selection_move_delete_cb view %p model %p trans %p", view, model, trans);
3394 
3395  DEBUG("gtv_sr_selection_move_delete_cb current_trans %p trans %p", view->priv->current_trans, trans);
3396 
3397  /* if same, lets get out of the way, so move */
3398  if (trans == view->priv->current_trans)
3399  gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
3400 
3401 }
3402 
3403 
3404 /* Call back for focus out event so we can finish edit */
3405 static gboolean
3406 gtv_sr_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
3407 {
3408  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
3409 
3410  gnc_tree_view_split_reg_finish_edit (view);
3411 
3412  return FALSE;
3413 }
3414 
3415 
3416 /* Reconcile column tests */
3417 static gboolean
3418 gtv_sr_recn_tests (GncTreeViewSplitReg *view, GtkTreeViewColumn *column, GtkTreePath *spath)
3419 {
3420  GtkCellRenderer *cr0;
3421  GList *renderers;
3422  ViewCol viewcol;
3423 
3424  ENTER(" ");
3425 
3426  // Get the first renderer, it has the view-column value.
3427  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
3428  cr0 = g_list_nth_data (renderers, 0);
3429  g_list_free (renderers);
3430 
3431  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cr0), "view_column"));
3432 
3433  /* Test for change of RECN COLUMN setting from reconciled */
3434  if (viewcol == COL_RECN)
3435  {
3436  /* Are we trying to change the reconcile setting */
3437  if (!gnc_tree_control_split_reg_recn_change (view, spath))
3438  {
3439  LEAVE("Not allowed to change reconciled transaction");
3440  return TRUE;
3441  }
3442  }
3443 
3444  /* Ask, are we allowed to change reconciled values other than 'description / notes / memo'
3445  which we can change always */
3446  if (viewcol != COL_DESCNOTES && viewcol != COL_RECN)
3447  {
3448  if (!gnc_tree_control_split_reg_recn_test (view, spath))
3449  {
3450  LEAVE("Not allowed to edit reconciled transaction");
3451  return TRUE;
3452  }
3453  }
3454  LEAVE(" ");
3455  return FALSE;
3456 }
3457 
3458 
3459 /* Test to see if we need to do a move */
3460 static void
3461 gtv_split_reg_test_for_move (GncTreeModelSplitReg *model, GtkTreePath *spath)
3462 {
3463  gint num_of_trans, trans_pos;
3464  gint *indices;
3465 
3466  indices = gtk_tree_path_get_indices (spath);
3467  num_of_trans = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
3468 
3469  trans_pos = indices[0];
3470 
3471  if (trans_pos < num_of_trans*1/3)
3472  gnc_tree_model_split_reg_move (model, VIEW_UP);
3473 
3474  if (trans_pos > num_of_trans*2/3)
3475  gnc_tree_model_split_reg_move (model, VIEW_DOWN);
3476 }
3477 
3478 /*###########################################################################*/
3479 
3480 /* This is the callback for the mouse click */
3481 static gboolean
3482 gtv_sr_button_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
3483 {
3484  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (widget);
3485  GncTreeModelSplitReg *model;
3486  GtkTreePath *mpath, *spath;
3487  GtkTreeViewColumn *col;
3488  GtkTreeIter m_iter;
3489  Split *split = NULL;
3490  Split *rotate_split = NULL;
3491  Transaction *trans = NULL;
3492  gboolean is_trow1, is_trow2, is_split, is_blank;
3493 
3494  model = gnc_tree_view_split_reg_get_model_from_view (view);
3495 
3496  /* This is for a single click */
3497  if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3498  {
3499  GdkWindow *window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (view));
3500 
3501  if (event->window != window)
3502  return FALSE;
3503 
3504  // Make sure we have stopped editing.
3505  gnc_tree_view_split_reg_finish_edit (view);
3506 
3507  // This prevents the cell changing.
3508  if (view->priv->stop_cell_move == TRUE)
3509  return TRUE;
3510 
3511  /* Get tree path for row that was clicked, true if row exists */
3512  if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view), (gint) event->x, (gint) event->y,
3513  &spath, &col, NULL, NULL))
3514  {
3515  DEBUG("event->x is %d and event->y is %d", (gint)event->x, (gint)event->y);
3516 
3517  mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath);
3518 
3519  /* This is to block the single click on a double click */
3520  if (view->priv->single_button_press > 0)
3521  {
3522  view->priv->single_button_press = view->priv->single_button_press -1;
3523  return TRUE;
3524  }
3525 
3526  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
3527  {
3528  gchar *mstring, *sstring;
3529  mstring = gtk_tree_path_to_string (mpath);
3530  sstring = gtk_tree_path_to_string (spath);
3531  DEBUG("Mouse Button Press - mpath is %s, spath is %s", mstring, sstring);
3532  g_free (mstring);
3533  g_free (sstring);
3534 
3535  // Reset the transaction confirm flag.
3536  view->priv->trans_confirm = RESET;
3537 
3538  gnc_tree_model_split_reg_get_split_and_trans (
3539  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
3540 
3541  // Ask for confirmation if data has been edited, gtv_sr_transaction_changed_confirm return TRUE if canceled
3542  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view), "data-edited")) && gtv_sr_transaction_changed_confirm (view, trans))
3543  {
3544  DEBUG("MB - Restore position - Cancel / Discard");
3545 
3546  /* Restore position - Cancel / Discard */
3547  if (view->priv->trans_confirm == CANCEL)
3548  {
3549  DEBUG("MB - Cancel");
3550 
3551  // Expand trans on split-trans (We only expand on cancel and more than two splits)
3552  if ((xaccTransCountSplits (view->priv->dirty_trans) > 2) && view->priv->dirty_trans != NULL)
3553  {
3554  // Jump to the first split of dirty_trans.
3555  gnc_tree_control_split_reg_jump_to (view, NULL, xaccTransGetSplit (view->priv->dirty_trans, 0), FALSE);
3556  }
3557  else
3558  // Jump to the dirty_trans.
3559  gnc_tree_control_split_reg_jump_to (view, view->priv->dirty_trans, NULL, FALSE);
3560 
3561  gtk_tree_path_free (spath);
3562  gtk_tree_path_free (mpath);
3563  return TRUE;
3564  }
3565 
3566  if (view->priv->trans_confirm == DISCARD)
3567  {
3568  DEBUG("MB - Discard");
3569  view->priv->dirty_trans = NULL;
3570  }
3571  }
3572  /* Skip */
3573 
3574  /* Test for change of transaction */
3575  if (view->priv->current_trans != trans)
3576  /* Reset allow changes for reconciled transactions */
3577  view->change_allowed = FALSE;
3578 
3579  // Reconcile tests
3580  if (gtv_sr_recn_tests (view, col, spath))
3581  {
3582  gtk_tree_path_free (spath);
3583  gtk_tree_path_free (mpath);
3584  return TRUE;
3585  }
3586 
3587  // Get the right split for rotate test
3588  if (is_split)
3589  rotate_split = split;
3590  else
3591  rotate_split = gtv_sr_get_this_split (view, trans);
3592 
3593  /* Set cursor to column */
3594  if (!gnc_tree_util_split_reg_rotate (view, col, trans, rotate_split))
3595  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, TRUE);
3596  else
3597  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, FALSE);
3598 
3599  /* Test to see if we need to do a move */
3600  gtv_split_reg_test_for_move (model, spath);
3601 
3602  gtk_tree_path_free (spath);
3603  gtk_tree_path_free (mpath);
3604  return TRUE;
3605  }
3606  gtk_tree_path_free (spath);
3607  gtk_tree_path_free (mpath);
3608  }
3609  }
3610 
3611  /* This is for a double click */
3612  if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
3613  {
3614  GdkWindow *window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (view));
3615 
3616  if (event->window != window)
3617  return FALSE;
3618 
3619  /* this works on non editable cells like void, balance */
3620  if (model->style != REG2_STYLE_JOURNAL)
3621  {
3622  /* This is to block the single click on a double click */
3623  view->priv->single_button_press = 1;
3624 
3625  if (view->priv->expanded)
3626  gnc_tree_view_split_reg_collapse_trans (view, NULL);
3627  else
3628  gnc_tree_view_split_reg_expand_trans (view, NULL);
3629 
3630  /* This updates the plugin page gui */
3632  }
3633  return TRUE;
3634  }
3635  return FALSE;
3636 }
3637 
3638 
3639 static gboolean
3640 gtv_sr_transaction_changed (GncTreeViewSplitReg *view)
3641 {
3642  GncTreeModelSplitReg *model;
3643  GtkTreeViewColumn *col;
3644  GtkTreePath *spath;
3645 
3646  model = gnc_tree_view_split_reg_get_model_from_view (view);
3647 
3648  // spath is where we are...
3649  gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &spath, &col);
3650 
3651  if (!spath)
3652  return FALSE;
3653 
3654  if (gtv_sr_recn_tests (view, col, spath))
3655  {
3656  gtk_tree_path_free (spath);
3657  return FALSE;
3658  }
3659  gtk_tree_path_free (spath);
3660 
3661  // Reset the transaction confirm flag.
3662  view->priv->trans_confirm = RESET;
3663 
3664  //Ask for confirmation if data has been edited, gtv_sr_transaction_changed_confirm return TRUE if canceled
3665  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view), "data-edited")) && gtv_sr_transaction_changed_confirm (view, NULL))
3666  {
3667  /* Restore position - Cancel / Discard */
3668  DEBUG("KB - Restore position - Cancel / Discard");
3669 
3670  if (view->priv->trans_confirm == CANCEL)
3671  {
3672  DEBUG("KB - Cancel");
3673 
3674  // Expand trans on split-trans (We only expand on cancel)
3675  if ((xaccTransCountSplits (view->priv->dirty_trans) > 2) && view->priv->dirty_trans != NULL)
3676  {
3677  // Jump to the first split of dirty_trans.
3678  gnc_tree_control_split_reg_jump_to (view, NULL, xaccTransGetSplit (view->priv->dirty_trans, 0), FALSE);
3679  }
3680  else
3681  // Jump to the dirty_trans.
3682  gnc_tree_control_split_reg_jump_to (view, view->priv->dirty_trans, NULL, FALSE);
3683 
3684  return TRUE;
3685  }
3686 
3687  if (view->priv->trans_confirm == DISCARD)
3688  {
3689  DEBUG("KB - Discard");
3690 
3691  gnc_tree_view_split_reg_block_selection (view, TRUE);
3692 
3693  // Check to see if dirty_trans expanded, collapse it.
3694  if (gnc_tree_view_split_reg_trans_expanded (view, view->priv->dirty_trans))
3695  gnc_tree_view_split_reg_collapse_trans (view, view->priv->dirty_trans);
3696 
3697  gnc_tree_view_split_reg_block_selection (view, FALSE);
3698 
3699  /* Remove the blank split and re-add - done so we keep it last in list */
3700  gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, TRUE);
3701  gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, FALSE);
3702 
3703  // Set the transaction to show correct view
3704  gnc_tree_view_split_reg_format_trans (view, view->priv->dirty_trans);
3705  view->priv->dirty_trans = NULL;
3706  }
3707  }
3708  return FALSE;
3709 }
3710 
3711 
3712 /* Return whether the cell is in editing mode */
3713 static gboolean
3714 gtv_sr_get_editing (GtkTreeViewColumn *col)
3715 {
3716  GtkCellRenderer *cr0 = NULL, *cr1 = NULL;
3717  GList *renderers;
3718  gboolean cell_editing0 = FALSE;
3719  gboolean cell_editing1 = FALSE;
3720  gboolean editing = FALSE;
3721 
3722  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (col));
3723  cr0 = g_list_nth_data (renderers, 0); // We always have one renderer
3724  if (g_list_length (renderers) == 2)
3725  cr1 = g_list_nth_data (renderers, 1); // There is only one column with two renderers
3726  g_list_free (renderers);
3727 
3728  if (gtk_cell_renderer_get_visible (cr0))
3729  g_object_get (G_OBJECT (cr0), "editing", &cell_editing0, NULL);
3730 
3731  if (cr1 && gtk_cell_renderer_get_visible (cr1))
3732  g_object_get (G_OBJECT (cr1), "editing", &cell_editing1, NULL);
3733 
3734  if (cell_editing0 || cell_editing1)
3735  editing = TRUE;
3736 
3737  DEBUG("editing is %d for column title %s", editing, gtk_tree_view_column_get_title (col));
3738 
3739  return editing;
3740 }
3741 
3742 
3743 /* For handling keynav */
3744 static gboolean
3745 gtv_sr_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
3746 {
3747  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (widget);
3748  GncTreeModelSplitReg *model;
3749  GtkTreeViewColumn *col;
3750  GtkTreePath *spath;
3751  GtkTreePath *start_path, *end_path;
3752  gboolean editing = FALSE;
3753  gboolean step_off = FALSE;
3754  gboolean trans_changed = FALSE;
3755  Transaction *btrans, *ctrans, *hetrans;
3756  gboolean goto_blank = FALSE;
3757  gboolean next_trans = TRUE;
3758 
3759  // spath is where we are, before key press...
3760  gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &spath, &col);
3761 
3762  if (event->type != GDK_KEY_PRESS)
3763  {
3764  if (spath)
3765  gtk_tree_path_free (spath);
3766  return FALSE;
3767  }
3768 
3769  switch (event->keyval)
3770  {
3771  case GDK_KEY_plus:
3772  case GDK_KEY_minus:
3773  case GDK_KEY_KP_Add:
3774  case GDK_KEY_KP_Subtract:
3775  case GDK_KEY_semicolon: // See https://bugs.gnucash.org/show_bug.cgi?id=798386
3776  if (!spath)
3777  return TRUE;
3778 
3779  gtk_tree_path_free (spath);
3780  return TRUE; //FIXME I may use these to expand / collapse to splits later...
3781  break;
3782 
3783  case GDK_KEY_Up:
3784  case GDK_KEY_Down:
3785 
3786  model = gnc_tree_view_split_reg_get_model_from_view (view);
3787 
3788  if (event->keyval == GDK_KEY_Up)
3789  {
3790  gnc_tree_model_split_reg_move (model, VIEW_UP);
3791  }
3792  else
3793  gnc_tree_model_split_reg_move (model, VIEW_DOWN);
3794 
3795  return FALSE;
3796  break;
3797 
3798  case GDK_KEY_Page_Up:
3799  case GDK_KEY_Page_Down:
3800 
3801  model = gnc_tree_view_split_reg_get_model_from_view (view);
3802 
3803  if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (view), &start_path, &end_path))
3804  {
3805  if (event->keyval == GDK_KEY_Page_Up)
3806  {
3807  GtkTreePath *new_start_path;
3808  gint *start_indices, *end_indices;
3809  gint new_start;
3810  gint num_of_trans;
3811 
3812  start_indices = gtk_tree_path_get_indices (start_path);
3813  end_indices = gtk_tree_path_get_indices (end_path);
3814  num_of_trans = end_indices[0] - start_indices[0];
3815 
3816  new_start = start_indices[0] - num_of_trans + 2;
3817 
3818  if (new_start < 0)
3819  new_start = 0;
3820 
3821  new_start_path = gtk_tree_path_new_from_indices (new_start, -1);
3822 
3823  /* Scroll to cell, top of view */
3824  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), new_start_path, NULL, TRUE, 0.0, 0.0);
3825 
3826  /* Set cursor to new top row */
3827  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), new_start_path, col, FALSE);
3828 
3829  gtk_tree_path_free (new_start_path);
3830 
3831  gnc_tree_model_split_reg_move (model, VIEW_UP);
3832  }
3833  else
3834  {
3835  GtkTreePath *new_end_path;
3836  gint *start_indices, *end_indices;
3837  gint new_end;
3838  gint num_of_trans, total_num;
3839 
3840  start_indices = gtk_tree_path_get_indices (start_path);
3841  end_indices = gtk_tree_path_get_indices (end_path);
3842  num_of_trans = end_indices[0] - start_indices[0];
3843 
3844  total_num = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
3845 
3846  new_end = end_indices[0] + num_of_trans - 1;
3847 
3848  if (new_end > (total_num - 1))
3849  new_end = total_num -1;
3850 
3851  new_end_path = gtk_tree_path_new_from_indices (new_end, -1);
3852 
3853  /* Scroll to cell, bottom of view */
3854  if (model->use_double_line == TRUE)
3855  {
3856  gtk_tree_path_down (new_end_path);
3857  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), new_end_path, NULL, TRUE, 1.0, 0.0);
3858  gtk_tree_path_up (new_end_path);
3859  }
3860  else
3861  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), new_end_path, NULL, TRUE, 1.0, 0.0);
3862 
3863  /* Set cursor to new bottom row */
3864  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), new_end_path, col, FALSE);
3865 
3866  gtk_tree_path_free (new_end_path);
3867 
3868  gnc_tree_model_split_reg_move (model, VIEW_DOWN);
3869  }
3870  gtk_tree_path_free (start_path);
3871  gtk_tree_path_free (end_path);
3872  }
3873  return TRUE;
3874  break;
3875 
3876  case GDK_KEY_Home:
3877  case GDK_KEY_End:
3878 
3879  model = gnc_tree_view_split_reg_get_model_from_view (view);
3880 
3881  if (event->keyval == GDK_KEY_Home)
3882  hetrans = gnc_tree_model_split_reg_get_first_trans (model);
3883  else
3884  hetrans = gnc_tree_model_split_get_blank_trans (model);
3885 
3886  model->current_trans = hetrans;
3887 
3888  if (!gnc_tree_model_split_reg_trans_is_in_view (model, hetrans))
3889  g_signal_emit_by_name (model, "refresh_trans");
3890  else
3891  gnc_tree_control_split_reg_jump_to (view, hetrans, NULL, FALSE);
3892 
3893  return TRUE;
3894  break;
3895 
3896  case GDK_KEY_Return:
3897  case GDK_KEY_space:
3898 
3899  if (!spath)
3900  return TRUE;
3901 
3902  // Do the reconcile tests.
3903  if (!gtv_sr_recn_tests (view, col, spath))
3904  {
3905  /* Set cursor to new column, open for editing */
3906  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, TRUE);
3907  }
3908 
3909  gtk_tree_path_free (spath);
3910  return TRUE;
3911  break;
3912 
3913  case GDK_KEY_KP_Enter:
3914 
3915  if (!spath)
3916  return TRUE;
3917 
3918  goto_blank = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
3919  GNC_PREF_ENTER_MOVES_TO_END);
3920 
3921  model = gnc_tree_view_split_reg_get_model_from_view (view);
3922  btrans = gnc_tree_model_split_get_blank_trans (model);
3923  ctrans = gnc_tree_view_split_reg_get_current_trans (view);
3924 
3925  /* Are we on the blank transaction */
3926  if (btrans == ctrans)
3927  next_trans = FALSE;
3928 
3929  /* First record the transaction */
3930  if (gnc_tree_view_split_reg_enter (view))
3931  {
3932  /* Now move. */
3933  if (goto_blank)
3934  g_idle_add ((GSourceFunc)gnc_tree_control_split_reg_jump_to_blank, view);
3935  else if (next_trans)
3936  gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
3937  }
3938  return TRUE;
3939  break;
3940 
3941  case GDK_KEY_Tab:
3942  case GDK_KEY_ISO_Left_Tab:
3943  case GDK_KEY_KP_Tab:
3944 
3945  if (!spath)
3946  return TRUE;
3947 
3948  // Bypass Auto-complete
3949  if (event->state & GDK_CONTROL_MASK)
3950  view->priv->auto_complete = TRUE;
3951 
3952  // Make sure we have stopped editing.
3953  gnc_tree_view_split_reg_finish_edit (view);
3954 
3955  // This prevents the cell changing.
3956  if (view->priv->stop_cell_move == TRUE)
3957  {
3958  gtk_tree_path_free (spath);
3959  return TRUE;
3960  }
3961 
3962  while (!editing && !step_off) // lets step over non editable columns
3963  {
3964  // Create a copy of the path we started with.
3965  GtkTreePath *start_spath = gtk_tree_path_copy (spath);
3966  gint *start_indices = gtk_tree_path_get_indices (start_spath);
3967  gint *next_indices;
3968 
3969  {
3970  gchar *string = gtk_tree_path_to_string (start_spath);
3971  DEBUG("Column title is %s and start path is %s", gtk_tree_view_column_get_title (col), string);
3972  g_free (string);
3973  }
3974 
3975  /* Step to the next column, we may wrap */
3976  gnc_tree_view_keynav (GNC_TREE_VIEW (view), &col, spath, event); // returns path and column
3977 
3978  {
3979  gchar *string = gtk_tree_path_to_string (spath);
3980  DEBUG("Column title is %s and spath is %s", gtk_tree_view_column_get_title (col), string);
3981  g_free (string);
3982  }
3983 
3984  // Have we changed transactions
3985  next_indices = gtk_tree_path_get_indices (spath);
3986  if (start_indices[0] != next_indices[0])
3987  {
3988  if (view->priv->dirty_trans != NULL) // from a dirty trans
3989  trans_changed = TRUE;
3990 
3991  /* Reset allow changes for reconciled transactions */
3992  view->change_allowed = FALSE;
3993  }
3994 
3995  // Do the reconcile tests.
3996  if (gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath))
3997  {
3998  if (gtv_sr_recn_tests (view, col, spath))
3999  {
4000  gtk_tree_path_free (start_spath);
4001  gtk_tree_path_free (spath);
4002  return TRUE;
4003  }
4004  }
4005 
4006  // Have we stepped off the end
4007  if (!spath || !gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath) || trans_changed) // We have stepped off the end / or changed trans
4008  {
4009  // Test for transaction changed.
4010  if (gtv_sr_transaction_changed (view))
4011  {
4012  gtk_tree_path_free (start_spath);
4013  gtk_tree_path_free (spath);
4014  return TRUE;
4015  }
4016  step_off = TRUE;
4017  }
4018  // This stops the cell activation on discard
4019  if (view->priv->trans_confirm != DISCARD)
4020  {
4021  // Set cursor to new column, open for editing
4022  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, TRUE);
4023  }
4024  // Is this an editable cell ?
4025  editing = gtv_sr_get_editing (col);
4026  gtk_tree_path_free (start_spath);
4027  }
4028  gtk_tree_path_free (spath);
4029  return TRUE;
4030  break;
4031 
4032  default:
4033  gtk_tree_path_free (spath);
4034  return FALSE;
4035  }
4036 }
4037 
4038 
4039 /*###########################################################################*/
4040 
4041 /* Callback for selection move */
4042 static void
4043 gtv_sr_motion_cb (GtkTreeSelection *sel, gpointer user_data)
4044 {
4045  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4046  GncTreeModelSplitReg *model;
4047  GtkTreePath *mpath, *spath;
4048  Split *split = NULL;
4049  Transaction *trans = NULL;
4050  Transaction *old_trans;
4051  gboolean is_trow1, is_trow2, is_split, is_blank;
4052  RowDepth depth = 0;
4053  GtkTreeIter m_iter;
4054  gint *indices;
4055 
4056  model = gnc_tree_view_split_reg_get_model_from_view (view);
4057 
4058  ENTER("View is %p and Model is %p", view, model);
4059 
4060  DEBUG("Current trans %p, Split %p, Depth %d and Dirty Trans %p", view->priv->current_trans, view->priv->current_split,
4061  view->priv->current_depth, view->priv->dirty_trans);
4062 
4063  /* Reset help text */
4064  if (view->help_text)
4065  g_free (view->help_text);
4066  view->help_text = g_strdup (" ");
4067  g_signal_emit_by_name (view, "help_signal", NULL);
4068 
4069  if (gtv_sr_get_model_iter_from_selection (view, sel, &m_iter))
4070  {
4071  gchar *mstring, *sstring;
4072 
4073  mpath = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &m_iter);
4074  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
4075 
4076  mstring = gtk_tree_path_to_string (mpath);
4077  sstring = gtk_tree_path_to_string (spath);
4078  DEBUG("Valid Selection - mpath is %s, spath is %s", mstring, sstring);
4079  g_free (mstring);
4080  g_free (sstring);
4081 
4082  /* save the current path */
4083  gnc_tree_view_split_reg_set_current_path (view, mpath);
4084 
4085  /* Use depth to determine if it is a split or transaction */
4086  depth = gtk_tree_path_get_depth (mpath);
4087 
4088  gtk_tree_path_free (mpath);
4089 
4090  gnc_tree_model_split_reg_get_split_and_trans (
4091  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
4092 
4093  DEBUG("Get model trans %p, split %p, is_split %d, is_blank %d\n", trans, split, is_split, is_blank);
4094 
4095  /* Update the titles if depth changes, we change rows */
4096  if (depth != view->priv->current_depth)
4097  gtv_sr_titles (view, depth);
4098 
4099  /* Move the blank split */
4100  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
4101 
4102  /* Save trans / split / depth to the current values */
4103  old_trans = view->priv->current_trans;
4104  view->priv->current_trans = trans;
4105  view->priv->current_split = split;
4106  view->priv->current_depth = depth;
4107 
4108  DEBUG("Current trans %p, split %p, depth %d and old_trans %p", view->priv->current_trans, view->priv->current_split,
4109  view->priv->current_depth, old_trans);
4110 
4111  /* Save trans and current row to model */
4112  model->current_trans = trans;
4113  indices = gtk_tree_path_get_indices (spath);
4114  model->current_row = indices[0];
4115  gnc_tree_model_split_reg_sync_scrollbar (model);
4116 
4117  /* Test for change of transaction and old transaction equals a dirty transaction */
4118  if ((trans != old_trans) && (old_trans == view->priv->dirty_trans))
4119  {
4120  if (gtv_sr_transaction_changed (view))
4121  {
4122  gtk_tree_path_free (spath);
4123  LEAVE("Leave Transaction Changed");
4124  return;
4125  }
4126  }
4127  if (view->priv->trans_confirm == CANCEL)
4128  {
4129  gtk_tree_path_free (spath);
4130  LEAVE("Leave Transaction Changed - Cancel");
4131  return;
4132  }
4133 
4134  /* Auto expand transaction and collapse previous transaction */
4135  if (old_trans != trans)
4136  {
4137  if (model->style != REG2_STYLE_JOURNAL)
4138  {
4139  gnc_tree_view_split_reg_block_selection (view, TRUE);
4140 
4141  if (gnc_tree_view_split_reg_trans_expanded (view, old_trans))
4142  gnc_tree_view_split_reg_collapse_trans (view, old_trans);
4143 
4144  gnc_tree_view_split_reg_block_selection (view, FALSE);
4145  }
4146  else
4147  gnc_tree_view_split_reg_expand_trans (view, NULL);
4148 
4149  if (model->style == REG2_STYLE_AUTO_LEDGER)
4150  {
4151  gtk_tree_view_expand_row (GTK_TREE_VIEW (view), spath, TRUE);
4152 
4153  view->priv->expanded = TRUE;
4154 
4155  if (view->priv->selection_to_blank_on_expand)
4156  gtv_sr_selection_to_blank (view);
4157  }
4158  }
4159  gtk_tree_path_free (spath);
4160 
4161  // Check to see if current trans is expanded and remember
4162  if (gnc_tree_view_split_reg_trans_expanded (view, trans))
4163  view->priv->expanded = TRUE;
4164  else
4165  view->priv->expanded = FALSE;
4166  }
4167  else
4168  {
4169  DEBUG("Not Valid Selection");
4170  /* We do not have a valid iter */
4171  gtv_sr_titles (view, 0);
4172 
4173  /* Move the blank split to the last transaction */
4174  gnc_tree_model_split_reg_set_blank_split_parent (model, NULL, FALSE);
4175 
4176  /* Set the default selection start position */
4177  gnc_tree_view_split_reg_default_selection (view);
4178  }
4179 
4180  /* This updates the plugin page gui */
4182 
4183  LEAVE(" ");
4184 }
4185 
4186 /*###########################################################################*/
4187 
4188 /* Connected to "edited" from cellrenderer. For reference, see
4189  split-register-model-save.c */
4190 static void
4191 gtv_sr_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
4192  const gchar *new_text, gpointer user_data)
4193 {
4194  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4195  GncTreeModelSplitReg *model;
4196  GtkCellEditable *editable;
4197 
4198  editable = g_object_get_data (G_OBJECT (cell), "cell-editable");
4199 
4200  DEBUG("cell is %p editable pointer is %p and id %lu", cell, editable, view->priv->fo_handler_id);
4201 
4202  /* Remove the focus out cb if one exists */
4203  if (view->priv->fo_handler_id != 0)
4204  {
4205  if (g_signal_handler_is_connected (G_OBJECT (editable), view->priv->fo_handler_id))
4206  g_signal_handler_disconnect (G_OBJECT (editable), view->priv->fo_handler_id);
4207  }
4208  view->priv->fo_handler_id = 0;
4209 
4210  /* Make sure we set focus to the tree view after cell editing */
4211  gtk_widget_grab_focus (GTK_WIDGET (view));
4212 
4213  if (g_strcmp0 (g_object_get_data (G_OBJECT (cell), "current-string"), new_text) == 0) // No change, return
4214  {
4215  if (view->priv->stop_cell_move == FALSE)
4216  return;
4217  }
4218 
4219  model = gnc_tree_view_split_reg_get_model_from_view (view);
4220  g_return_if_fail (model);
4221 
4222  /* Are we using a template or not */
4224  gtv_sr_edited_normal_cb (cell, path_string, new_text, view);
4225  else
4226  gtv_sr_edited_template_cb (cell, path_string, new_text, view);
4227 }
4228 
4229 
4230 /* This is used for the normal registers */
4231 static void
4232 gtv_sr_edited_normal_cb (GtkCellRendererText *cell, const gchar *path_string,
4233  const gchar *new_text, gpointer user_data)
4234 {
4235  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4236  GncTreeModelSplitReg *model;
4237  GtkCellEditable *editable;
4238  GtkTreeIter m_iter;
4239  Split *split;
4240  Transaction *trans;
4241  gboolean is_trow1, is_trow2, is_split, is_blank;
4242  ViewCol viewcol;
4243  char *error_loc = NULL;
4244  Account *anchor = view->priv->anchor;
4245 
4246  editable = g_object_get_data (G_OBJECT (cell), "cell-editable");
4247 
4248  DEBUG("cell is %p editable pointer is %p", cell, editable);
4249 
4250  g_return_if_fail (gtv_sr_get_model_iter_from_view_string (view, path_string, &m_iter));
4251 
4252  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "view_column"));
4253 
4254  model = gnc_tree_view_split_reg_get_model_from_view (view);
4255  g_return_if_fail (model);
4256 
4257  gnc_tree_model_split_reg_get_split_and_trans (
4258  model, &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
4259 
4260  switch (viewcol) {
4261  case COL_DATE:
4262  /* Column is DATE */
4263  if (is_trow1)
4264  {
4265  GDate parsed_date;
4266  gnc_tree_util_split_reg_parse_date (&parsed_date, new_text);
4267  if (g_date_valid (&parsed_date))
4268  {
4269  gtv_sr_begin_edit (view, trans);
4270  xaccTransSetDate (trans, g_date_get_day (&parsed_date), g_date_get_month (&parsed_date), g_date_get_year (&parsed_date));
4271  }
4272  else
4273  {
4274  // We should never get here
4275  PERR("invalid date '%s'", new_text);
4276  }
4277  }
4278  break;
4279 
4280  case COL_NUMACT:
4281  /* Column is NUM / ACT */
4282  gtv_sr_begin_edit (view, trans);
4283  if (is_trow1)
4284  {
4285  /* set per book option */
4286  gnc_set_num_action (trans, gtv_sr_get_this_split (view, trans),
4287  new_text, NULL);
4288 
4289  if (!qof_book_use_split_action_for_num_field (gnc_get_current_book()))
4290  {
4291  // Set the last number value for this account.
4292  if (gnc_strisnum (new_text) && anchor != NULL)
4293  xaccAccountSetLastNum (anchor, new_text);
4294  }
4295  }
4296  if (is_trow2)
4297  {
4298  /* set per book option */
4299  gnc_set_num_action (trans, gtv_sr_get_this_split (view, trans),
4300  NULL, new_text);
4301 
4302  if (qof_book_use_split_action_for_num_field (gnc_get_current_book()))
4303  {
4304  // Set the last number value for this account.
4305  if (gnc_strisnum (new_text) && anchor != NULL)
4306  xaccAccountSetLastNum (anchor, new_text);
4307  }
4308  }
4309  if (is_split)
4310  {
4311  /* Set split-action with gnc_set_num_action which is the same as
4312  * xaccSplitSetAction with these arguments */
4313  gnc_set_num_action (NULL, split, NULL, new_text);
4314  }
4315  break;
4316 
4317  case COL_DESCNOTES:
4318  /* Column is DESCRIPTION / NOTES / MEMO */
4319  gtv_sr_begin_edit (view, trans);
4320  if (is_trow1)
4321  {
4322  xaccTransSetDescription (trans, new_text);
4323  // This will potentially fill in the rest of the transaction.
4324  if (view->priv->auto_complete == FALSE)
4325  {
4326  gnc_tree_control_auto_complete (view, trans, new_text);
4327  view->priv->auto_complete = TRUE;
4328  }
4329  }
4330  if (is_trow2)
4331  xaccTransSetNotes (trans, new_text);
4332 
4333  if (is_split)
4334  xaccSplitSetMemo (split, new_text);
4335 
4336  break;
4337 
4338  case COL_RECN:
4339  /* Column is RECONCILE */
4340  gtv_sr_begin_edit (view, trans);
4341  {
4342  char rec = 'n';
4343 
4344  if (new_text != NULL)
4345  {
4346  const gchar *cflag = gnc_get_reconcile_str (CREC);
4347  const gchar *nflag = gnc_get_reconcile_str (NREC);
4348  const char recn_flags[] = {NREC, CREC, 0}; // List of reconciled flags
4349  const gchar *flags;
4350  gchar *this_flag;
4351  gint index = 0;
4352 
4353  flags = g_strconcat (nflag, cflag, NULL); // List of translated strings.
4354 
4355  /* Find the current flag in the list of flags */
4356  this_flag = strstr (flags, new_text);
4357 
4358  if (this_flag != NULL)
4359  {
4360  index = this_flag - flags;
4361  rec = recn_flags[index];
4362  }
4363  }
4364  if (is_trow1)
4365  xaccSplitSetReconcile (gtv_sr_get_this_split (view, trans), rec);
4366  if (is_split)
4367  xaccSplitSetReconcile (split, rec);
4368  }
4369  break;
4370 
4371  case COL_TYPE:
4372  /* Column is TYPE */
4373  gtv_sr_begin_edit (view, trans);
4374  {
4375  char type = TXN_TYPE_NONE;
4376  if (new_text != NULL)
4377  type = new_text[0];
4378 
4379  if (is_trow1)
4380  xaccTransSetTxnType (trans, type);
4381  }
4382  break;
4383 
4384  case COL_TRANSFERVOID:
4385  case COL_AMTVAL:
4386  case COL_AMOUNT:
4387  case COL_PRICE:
4388  case COL_DEBIT:
4389  case COL_CREDIT:
4390  {
4391  Account *acct, *old_acct;
4392  gnc_numeric input;
4393  Split *osplit = NULL;
4394  gboolean valid_input = FALSE;
4395  gboolean force = FALSE;
4396  gboolean input_used = FALSE;
4397 
4398  gtv_sr_begin_edit (view, trans);
4399 
4400  /* Get the split pair if anchored to a register */
4401  if (!is_split && anchor)
4402  {
4403  if (!gtv_sr_get_split_pair (view, trans, &osplit, &split))
4404  {
4405  DEBUG("couldn't get split pair");
4406  break;
4407  }
4408  }
4409 
4410  /* Setup the account field */
4411  if (viewcol == COL_TRANSFERVOID)
4412  {
4413  view->priv->stop_cell_move = FALSE;
4414  acct = gnc_tree_control_split_reg_get_account_by_name (view, new_text);
4415  if (acct == NULL)
4416  {
4417  DEBUG("Account is NULL");
4418  xaccSplitReinit(split);
4419  if (osplit)
4420  xaccSplitDestroy (osplit);
4421 
4422  g_free (view->priv->transfer_string);
4423  view->priv->transfer_string = g_strdup (new_text);
4424  view->priv->stop_cell_move = TRUE;
4425 
4426  /* this will populate cell with original value */
4427  g_idle_add ((GSourceFunc) gtv_sr_idle_transfer, view);
4428  break;
4429  }
4430 
4431  if (acct != NULL && is_split)
4432  {
4433  old_acct = xaccSplitGetAccount (split);
4434  xaccSplitSetAccount (split, acct);
4436  force = TRUE;
4437  }
4438  else
4439  {
4440  old_acct = xaccSplitGetAccount (osplit);
4441  xaccSplitSetAccount (osplit, acct);
4443  force = TRUE;
4444  }
4445  }
4446  else
4447  {
4448  if (!gnc_exp_parser_parse (new_text, &input, &error_loc))
4449  break;
4450  else
4451  valid_input = TRUE;
4452  }
4453 
4454  /* Get the account for this split */
4455  acct = xaccSplitGetAccount (split);
4456  if (!acct)
4457  {
4458  if (anchor)
4459  {
4460  xaccSplitSetAccount (split, anchor);
4461  acct = xaccSplitGetAccount (split);
4462  }
4463  else
4464  {
4465  break; //Well, what else is there to do?
4466  }
4467  }
4468 
4469  /* Set the transaction currency if not set */
4470  if (!xaccTransGetCurrency (trans))
4471  {
4472  // set transaction currency to that of register (which is guaranteed to be a currency)
4473  xaccTransSetCurrency (trans, view->priv->reg_currency);
4474 
4475  // We are on General ledger
4476  if (!anchor)
4477  {
4479  }
4480  }
4481 
4482  // No need to check for a non-currency register because that's what
4483  // was already checked when reg_currency was stored.
4484 
4485  /* This computes the value if we just commit the split after entering account */
4486  if (!valid_input)
4487  input = gnc_tree_util_split_reg_get_value_for (view, trans, split, is_blank);
4488 
4489  // Negate the input if COL_CREDIT
4490  if (viewcol == COL_CREDIT)
4491  input = gnc_numeric_neg (input);
4492 
4493  // Set the split parent trans
4494  xaccSplitSetParent (split, trans);
4495 
4496  // If we are at transaction level, column is value, split level is amount
4497  if (viewcol == COL_AMTVAL)
4498  {
4499  gnc_tree_util_set_number_for_input (view, trans, split, input, COL_AMTVAL);
4500  input_used = TRUE;
4501  }
4502 
4503  // The price of stock / shares, editable only when expanded and sub_account
4504  if (viewcol == COL_AMOUNT)
4505  {
4506  gnc_tree_util_set_number_for_input (view, trans, split, input, COL_AMTVAL);
4507  input_used = TRUE;
4508  }
4509 
4510  // The price of stock / shares
4511  if (viewcol == COL_PRICE)
4512  {
4513  gnc_tree_util_set_number_for_input (view, trans, split, input, COL_PRICE);
4514  input_used = TRUE;
4515  }
4516 
4517  // Check if this is a stock / share amount
4518  if (viewcol == COL_CREDIT || viewcol == COL_DEBIT)
4519  {
4521  {
4522  gnc_tree_util_set_number_for_input (view, trans, split, input, viewcol);
4523  input_used = TRUE;
4524  }
4525  }
4526 
4527  // This is used in transaction mode, two splits
4528  if (input_used == FALSE)
4529  {
4531  gnc_tree_util_split_reg_set_value_for (view, trans, split, input, force);
4532  else
4533  gnc_tree_util_set_value_for_amount (view, trans, split, input);
4534  }
4535 
4536  // If this is the blank split, promote it.
4537  if (is_blank)
4538  {
4539  /*FIXME May be this should be a signal - Promote the blank split to a real split */
4540  g_idle_add ((GSourceFunc) gnc_tree_model_split_reg_commit_blank_split, gnc_tree_view_split_reg_get_model_from_view (view));
4541 
4542  /* scroll when view idle */
4543  g_idle_add ((GSourceFunc) gnc_tree_view_split_reg_scroll_to_cell, view);
4544  }
4545 
4546  // In transaction mode, two splits only, set up the other split.
4547  if (osplit)
4548  {
4549  xaccSplitSetParent (osplit, trans);
4550 
4552  gnc_tree_util_split_reg_set_value_for (view, trans, osplit, gnc_numeric_neg (input), force);
4553  else
4554  gnc_tree_util_set_value_for_amount (view, trans, osplit, gnc_numeric_neg (xaccSplitGetValue (split)));
4555  }
4556  }
4557  break;
4558 
4559  default:
4560  //g_assert_not_reached();
4561  break;
4562  }
4563 }
4564 
4565 
4566 /* This is used for the template registers */
4567 static void
4568 gtv_sr_edited_template_cb (GtkCellRendererText *cell, const gchar *path_string,
4569  const gchar *new_text, gpointer user_data)
4570 {
4571  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4572  GncTreeModelSplitReg *model;
4573  GtkCellEditable *editable;
4574  GtkTreeIter m_iter;
4575  Split *split;
4576  Transaction *trans;
4577  gboolean is_trow1, is_trow2, is_split, is_blank;
4578  ViewCol viewcol;
4579  Account *anchor = view->priv->anchor;
4580 
4581  editable = g_object_get_data (G_OBJECT (cell), "cell-editable");
4582 
4583  DEBUG("cell is %p editable pointer is %p", cell, editable);
4584 
4585  g_return_if_fail (gtv_sr_get_model_iter_from_view_string (view, path_string, &m_iter));
4586 
4587  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "view_column"));
4588 
4589  model = gnc_tree_view_split_reg_get_model_from_view (view);
4590  g_return_if_fail (model);
4591 
4592  gnc_tree_model_split_reg_get_split_and_trans (
4593  model, &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
4594 
4595  switch (viewcol) {
4596  case COL_NUMACT:
4597  /* Column is NUM / ACT */
4598  gtv_sr_begin_edit (view, trans);
4599  if (is_trow1)
4600  {
4601  /* set per book option */
4602  gnc_set_num_action (trans, gtv_sr_get_this_split (view, trans),
4603  new_text, NULL);
4604 
4605  if (!qof_book_use_split_action_for_num_field (gnc_get_current_book()))
4606  {
4607  // Set the last number value for this account.
4608  if (gnc_strisnum (new_text) && anchor != NULL)
4609  xaccAccountSetLastNum (anchor, new_text);
4610  }
4611  }
4612  if (is_trow2)
4613  {
4614  /* set per book option */
4615  gnc_set_num_action (trans, gtv_sr_get_this_split (view, trans),
4616  NULL, new_text);
4617 
4618  if (qof_book_use_split_action_for_num_field (gnc_get_current_book()))
4619  {
4620  // Set the last number value for this account.
4621  if (gnc_strisnum (new_text) && anchor != NULL)
4622  xaccAccountSetLastNum (anchor, new_text);
4623  }
4624  }
4625  if (is_split)
4626  {
4627  /* Set split-action with gnc_set_num_action which is the same as
4628  * xaccSplitSetAction with these arguments */
4629  gnc_set_num_action (NULL, split, NULL, new_text);
4630  }
4631  break;
4632 
4633  case COL_DESCNOTES:
4634  /* Column is DESCRIPTION / NOTES / MEMO */
4635  gtv_sr_begin_edit (view, trans);
4636  if (is_trow1)
4637  {
4638  xaccTransSetDescription (trans, new_text);
4639  // This will potentially fill in the rest of the transaction.
4640  if (view->priv->auto_complete == FALSE)
4641  {
4642  gnc_tree_control_auto_complete (view, trans, new_text);
4643  view->priv->auto_complete = TRUE;
4644  }
4645  }
4646  if (is_trow2)
4647  xaccTransSetNotes (trans, new_text);
4648 
4649  if (is_split)
4650  xaccSplitSetMemo (split, new_text);
4651 
4652  break;
4653 
4654  case COL_RECN:
4655  /* Column is RECONCILE */
4656  gtv_sr_begin_edit (view, trans);
4657  {
4658  char rec = 'n';
4659 
4660  if (new_text != NULL)
4661  {
4662  const gchar *cflag = gnc_get_reconcile_str (CREC);
4663  const gchar *nflag = gnc_get_reconcile_str (NREC);
4664  const char recn_flags[] = {NREC, CREC, 0}; // List of reconciled flags
4665  const gchar *flags;
4666  gchar *this_flag;
4667  gint index = 0;
4668 
4669  flags = g_strconcat (nflag, cflag, NULL); // List of translated strings.
4670 
4671  /* Find the current flag in the list of flags */
4672  this_flag = strstr (flags, new_text);
4673 
4674  if (this_flag != NULL)
4675  {
4676  index = this_flag - flags;
4677  rec = recn_flags[index];
4678  }
4679  }
4680  if (is_trow1)
4681  xaccSplitSetReconcile (gtv_sr_get_this_split (view, trans), rec);
4682  if (is_split)
4683  xaccSplitSetReconcile (split, rec);
4684  }
4685  break;
4686 
4687  case COL_TRANSFERVOID:
4688  case COL_DEBIT:
4689  case COL_CREDIT:
4690  {
4691  gtv_sr_begin_edit (view, trans);
4692 
4693  /* Setup the account field */
4694  if (viewcol == COL_TRANSFERVOID)
4695  {
4696  Account *template_acc;
4697  Account *acct;
4698  const GncGUID *acctGUID;
4699 
4700  /* save the account GncGUID into the kvp_data. */
4701  view->priv->stop_cell_move = FALSE;
4702  acct = gnc_tree_control_split_reg_get_account_by_name (view, new_text);
4703  if (acct == NULL)
4704  {
4705  DEBUG("Template Account is NULL");
4706 
4707  g_free (view->priv->transfer_string);
4708  view->priv->transfer_string = g_strdup (new_text);
4709  view->priv->stop_cell_move = TRUE;
4710 
4711  /* this will populate cell with original value */
4712  g_idle_add ((GSourceFunc) gtv_sr_idle_transfer, view);
4713  break;
4714  }
4715 
4716  acctGUID = xaccAccountGetGUID (acct);
4717  qof_instance_set (QOF_INSTANCE (split),
4718  "sx-account", acctGUID,
4719  NULL);
4720 
4721  template_acc = gnc_tree_model_split_reg_get_template_account (model);
4722 
4723  /* set the actual account to the fake account for these templates */
4724  xaccAccountInsertSplit (template_acc, split);
4725  }
4726 
4727  /* Set the transaction currency if not set */
4728  if (!xaccTransGetCurrency (trans))
4729  {
4731  }
4732 
4733  // No need to check for a non-currency register because that's what
4734  // was already checked when reg_currency was stored.
4735 
4736  /* Setup the debit and credit fields */
4737  if (viewcol == COL_DEBIT)
4738  {
4739  char *error_loc;
4740  gnc_numeric new_value;
4741  gboolean parse_result;
4742 
4743  /* Setup the debit formula */
4744 
4745  /* If the value can be parsed into a numeric result, store that
4746  * numeric value additionally. See above comment.*/
4747  parse_result = gnc_exp_parser_parse_separate_vars (new_text, &new_value, &error_loc, NULL);
4748  if (!parse_result)
4749  {
4750  new_value = gnc_numeric_zero();
4751  }
4752  qof_instance_set (QOF_INSTANCE (split),
4753  "sx-debit-formula", new_text,
4754  "sx-debit-numeric", &new_value,
4755  "sx-credit-formula", NULL,
4756  "sx-credit-numeric", NULL,
4757  NULL);
4758  }
4759 
4760  /* Setup the debit and credit fields */
4761  if (viewcol == COL_CREDIT)
4762  {
4763  char *error_loc;
4764  gnc_numeric new_value;
4765  gboolean parse_result;
4766 
4767  /* If the value can be parsed into a numeric result (without any
4768  * further variable definitions), store that numeric value
4769  * additionally in the kvp. Otherwise store a zero numeric
4770  * there.*/
4771  parse_result = gnc_exp_parser_parse_separate_vars (new_text, &new_value, &error_loc, NULL);
4772  if (!parse_result)
4773  {
4774  new_value = gnc_numeric_zero();
4775  }
4776  qof_instance_set (QOF_INSTANCE (split),
4777  "sx-credit-formula", new_text,
4778  "sx-credit-numeric", &new_value,
4779  "sx-debit-formula", NULL,
4780  "sx-debit-numeric", NULL,
4781  NULL);
4782  }
4783  /* set the amount to an innocuous value */
4784  xaccSplitSetValue (split, gnc_numeric_create (0, 1));
4785 
4786  // Set the split parent trans
4787  xaccSplitSetParent (split, trans);
4788 
4789  // If this is the blank split, promote it.
4790  if (is_blank)
4791  {
4792  /*FIXME May be this should be a signal - Promote the blank split to a real split */
4793  g_idle_add ((GSourceFunc) gnc_tree_model_split_reg_commit_blank_split, gnc_tree_view_split_reg_get_model_from_view (view));
4794 
4795  /* scroll when view idle */
4796  g_idle_add ((GSourceFunc) gnc_tree_view_split_reg_scroll_to_cell, view);
4797  }
4798  }
4799  break;
4800 
4801  default:
4802  //g_assert_not_reached();
4803  break;
4804  }
4805 }
4806 
4807 /*###########################################################################*/
4808 
4809 /* Parses the string value and returns true if it is a
4810  * number. In that case, *num is set to the value parsed. */
4811 static gboolean
4812 gtv_sr_parse_num (const char *string, long int *num)
4813 {
4814  long int number;
4815 
4816  if (string == NULL)
4817  return FALSE;
4818 
4819  if (!gnc_strisnum (string))
4820  return FALSE;
4821 
4822  number = strtol (string, NULL, 10);
4823 
4824  if ((number == LONG_MIN) || (number == LONG_MAX))
4825  return FALSE;
4826 
4827  if (num != NULL)
4828  *num = number;
4829 
4830  return TRUE;
4831 }
4832 
4833 /* Callback for Number Accelerator key */
4834 static void
4835 gtv_sr_num_cb (GtkEntry *entry,
4836  const gchar *text,
4837  gint length,
4838  gint *position,
4839  gpointer user_data)
4840 {
4841  GtkEditable *editable = GTK_EDITABLE (entry);
4842  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4843  GncTreeModelSplitReg *model;
4844  RowDepth depth;
4845  Account *account;
4846  gchar *entered_string;
4847  gchar *leave_string = NULL;
4848 
4849  gboolean accel = FALSE;
4850  gboolean is_num;
4851  long int number = 0;
4852  gunichar uc;
4853 
4854  model = gnc_tree_view_split_reg_get_model_from_view (view);
4855 
4856  account = gnc_tree_model_split_reg_get_anchor (model);
4857 
4858  depth = gnc_tree_view_reg_get_selected_row_depth (view);
4859 
4860  // This only works on the number field.
4861  if ((depth == TRANS2 || depth == SPLIT3))
4862  return;
4863 
4864  // Get entered string
4865  entered_string = gtk_editable_get_chars (editable, 0, -1);
4866 
4867  // Test for number and return it.
4868  is_num = gtv_sr_parse_num (entered_string, &number);
4869 
4870  if (is_num && (number < 0))
4871  is_num = FALSE;
4872 
4873  // Test for accelerator keys.
4874  uc = g_utf8_get_char (text);
4875  switch (uc)
4876  {
4877  case '+':
4878  case '=':
4879  number++;
4880  accel = TRUE;
4881  break;
4882 
4883  case '_':
4884  case '-':
4885  number--;
4886  accel = TRUE;
4887  break;
4888 
4889  case '}':
4890  case ']':
4891  number += 10;
4892  accel = TRUE;
4893  break;
4894 
4895  case '{':
4896  case '[':
4897  number -= 10;
4898  accel = TRUE;
4899  break;
4900  }
4901 
4902  if (number < 0)
4903  number = 0;
4904 
4905  /* If there is already a non-number there, don't accelerate. */
4906  if (accel && !is_num && (g_strcmp0 (entered_string, "") != 0))
4907  accel = FALSE;
4908 
4909  // See if entered string is empty, try and get the last number.
4910  if (accel && (g_strcmp0 (entered_string, "") == 0))
4911  {
4912  if (account != NULL)
4913  {
4914  if (gtv_sr_parse_num (xaccAccountGetLastNum (account), &number))
4915  number = number + 1;
4916  else
4917  number = 1;
4918  }
4919  else
4920  number = 1;
4921 
4922  is_num = TRUE;
4923  }
4924 
4925  if (!accel)
4926  {
4927  leave_string = g_strconcat (entered_string, text, NULL);
4928  }
4929 
4930  if (accel && is_num)
4931  {
4932  char buff[128];
4933 
4934  strcpy (buff, "");
4935  snprintf (buff, sizeof(buff), "%ld", number);
4936 
4937  if (g_strcmp0 (buff, "") == 0)
4938  leave_string = g_strdup ("");
4939  else
4940  leave_string = g_strdup (buff);
4941  }
4942 
4943  g_signal_handlers_block_by_func (editable, (gpointer) gtv_sr_num_cb, user_data);
4944 
4945  gtk_editable_delete_text (editable, 0, -1);
4946  gtk_editable_set_position (editable, 0);
4947 
4948  if (leave_string != NULL)
4949  gtk_editable_insert_text (editable, leave_string, -1, position);
4950 
4951  g_signal_handlers_unblock_by_func (editable, (gpointer) gtv_sr_num_cb, user_data);
4952 
4953  g_signal_stop_emission_by_name (editable, "insert_text");
4954 
4955  if (leave_string)
4956  g_free (leave_string);
4957 
4958  g_free (entered_string);
4959 }
4960 
4961 
4962 /* Callback for Account separator key */
4963 static void
4964 gtv_sr_acct_cb (GtkEntry *entry,
4965  const gchar *text,
4966  gint length,
4967  gint *position,
4968  gpointer user_data)
4969 {
4970  GtkEditable *editable = GTK_EDITABLE (entry);
4971  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
4972  GtkEntryCompletion *completion;
4973  GtkTreeModel *model;
4974  GtkTreeIter iter;
4975 
4976  const gchar *sep_char;
4977  gchar *entered_string;
4978  gchar *acct_string = NULL;
4979 
4980  gint num_of_items = 0;
4981  gboolean valid;
4982  gboolean all_the_same = TRUE;
4983 
4984  sep_char = gnc_get_account_separator_string ();
4985 
4986  if (g_strcmp0 (text, sep_char) == 0)
4987  entered_string = g_strconcat (gtk_editable_get_chars (editable, 0, -1), NULL);
4988  else
4989  entered_string = g_strconcat (gtk_editable_get_chars (editable, 0, -1), text, NULL);
4990 
4991  // Get the completion and model
4992  completion = gtk_entry_get_completion (entry);
4993  model = gtk_entry_completion_get_model (completion);
4994 
4995  // Get the first item in the list
4996  valid = gtk_tree_model_get_iter_first (model, &iter);
4997  while (valid)
4998  {
4999  gchar *item, *item_string, *l_item, *l_entered_string, *l_acct_string;
5000 
5001  // Walk through the list, reading each row
5002  if (view->priv->acct_short_names)
5003  gtk_tree_model_get (model, &iter, 0, &item, -1);
5004  else
5005  gtk_tree_model_get (model, &iter, 1, &item, -1);
5006 
5007  item_string = g_strconcat (item, sep_char, NULL);
5008 
5009  l_item = g_utf8_strdown (item_string, -1);
5010  l_entered_string = g_utf8_strdown (entered_string, -1);
5011 
5012  if (g_str_has_prefix (l_item, l_entered_string))
5013  {
5014  if (num_of_items == 0)
5015  acct_string = g_strdup (item);
5016  else
5017  {
5018  l_acct_string = g_utf8_strdown (acct_string, -1);
5019  if (!g_str_has_prefix (g_utf8_strdown (l_item, -1), l_acct_string))
5020  all_the_same = FALSE;
5021  g_free (l_acct_string);
5022  }
5023  num_of_items = num_of_items + 1;
5024  }
5025  g_free (item);
5026  g_free (item_string);
5027  g_free (l_item);
5028  g_free (l_entered_string);
5029  valid = gtk_tree_model_iter_next (model, &iter);
5030  }
5031 
5032  g_signal_handlers_block_by_func (editable, (gpointer) gtv_sr_acct_cb, user_data);
5033 
5034  gtk_editable_delete_text (editable, 0, -1);
5035  gtk_editable_set_position (editable, 0);
5036 
5037  if (num_of_items == 0)
5038  gtk_editable_insert_text (editable, entered_string, -1, position);
5039  else
5040  {
5041  if (num_of_items == 1)
5042  gtk_editable_insert_text (editable, acct_string, -1, position);
5043  else
5044  {
5045  if (all_the_same)
5046  {
5047  if (g_strcmp0 (text, sep_char) == 0)
5048  gtk_editable_insert_text (editable, g_strconcat (acct_string, sep_char, NULL), -1, position);
5049  else
5050  gtk_editable_insert_text (editable, entered_string, -1, position);
5051  }
5052  else
5053  gtk_editable_insert_text (editable, entered_string, -1, position);
5054  }
5055  }
5056  g_signal_handlers_unblock_by_func (editable, (gpointer) gtv_sr_acct_cb, user_data);
5057 
5058  g_signal_stop_emission_by_name (editable, "insert_text");
5059  g_free (acct_string);
5060  g_free (entered_string);
5061 }
5062 
5063 
5064 /* Callback for changing reconcile setting with space bar */
5065 static void
5066 gtv_sr_recn_cb (GtkEntry *entry,
5067  const gchar *text,
5068  gint length,
5069  gint *position,
5070  gpointer user_data)
5071 {
5072  GtkEditable *editable = GTK_EDITABLE (entry);
5073  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5074 
5075  const gchar *cflag = gnc_get_reconcile_str (CREC);
5076  const gchar *nflag = gnc_get_reconcile_str (NREC);
5077 
5078  const gchar *flags;
5079  gchar *this_flag;
5080  gchar *result;
5081  static char ss[2];
5082  gint index = 0;
5083 
5084  result = g_ascii_strdown (text, length);
5085 
5086  if (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-flag") != NULL)
5087  index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-flag"));
5088  else
5089  {
5090  if (g_strcmp0 (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-string"), nflag) == 0)
5091  index = 0;
5092  }
5093 
5094  flags = g_strconcat (nflag, cflag, NULL);
5095 
5096  /* So we can test for space */
5097  ss[0] = ' ';
5098  ss[1] = '\0';
5099 
5100  /* Find the entered text in the list of flags */
5101  this_flag = strstr (flags, text);
5102 
5103  if (this_flag == NULL || *this_flag == '\0')
5104  {
5105  if (g_strcmp0 (text, ss) == 0) // test for space
5106  {
5107  /* In the list, choose the next item in the list
5108  (wrapping around as necessary). */
5109 
5110  if (flags[index + 1] != '\0')
5111  index = index + 1;
5112  else
5113  index = 0;
5114 
5115  g_free (result);
5116  result = g_strdup_printf("%c", flags[index]);
5117  }
5118  else
5119  {
5120  /* If it's not there (or the list is empty) use default_flag */
5121  g_free (result);
5122  result = g_strdup (gnc_get_reconcile_str (NREC));
5123  }
5124  }
5125  else
5126  {
5127  g_free (result);
5128  result = g_strdup (text);
5129  }
5130 
5131  /* save the index in the cellrenderer */
5132  g_object_set_data (G_OBJECT (view->priv->temp_cr), "current-flag", GINT_TO_POINTER (index));
5133 
5134  g_signal_handlers_block_by_func (editable, (gpointer) gtv_sr_recn_cb, user_data);
5135 
5136  gtk_editable_delete_text (editable, 0, -1);
5137  gtk_editable_insert_text (editable, result, length, position);
5138 
5139  g_signal_handlers_unblock_by_func (editable, (gpointer) gtv_sr_recn_cb, user_data);
5140 
5141  g_signal_stop_emission_by_name (editable, "insert_text");
5142 
5143  g_free (result);
5144 }
5145 
5146 
5147 /* Callback for changing type setting with space bar */
5148 static void
5149 gtv_sr_type_cb (GtkEntry *entry,
5150  const gchar *text,
5151  gint length,
5152  gint *position,
5153  gpointer user_data)
5154 {
5155  GtkEditable *editable = GTK_EDITABLE (entry);
5156  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5157  const gchar *flags;
5158  const char type_flags[] = {TXN_TYPE_INVOICE, TXN_TYPE_PAYMENT, 0};
5159  gchar *this_flag;
5160  gchar *result;
5161  static char ss[2];
5162  gint index = 0;
5163 
5164  flags = type_flags;
5165 
5166  result = g_ascii_strup (text, length);
5167 
5168  if (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-flag") != NULL)
5169  index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-flag"));
5170  else
5171  {
5172  if (g_strcmp0 (g_object_get_data (G_OBJECT (view->priv->temp_cr), "current-string"), "I") == 0)
5173  index = 0;
5174  }
5175 
5176  /* So we can test for space */
5177  ss[0] = ' ';
5178  ss[1] = '\0';
5179 
5180  /* Find the entered text in the list of flags */
5181  this_flag = strstr (flags, text);
5182 
5183  if (this_flag == NULL || *this_flag == '\0')
5184  {
5185  if (g_strcmp0 (text, ss) == 0) // test for space
5186  {
5187  /* In the list, choose the next item in the list
5188  (wrapping around as necessary). */
5189 
5190  if (flags[index + 1] != '\0')
5191  index = index + 1;
5192  else
5193  index = 0;
5194 
5195  g_free (result);
5196  result = g_strdup_printf("%c", flags[index]);
5197  }
5198  else
5199  {
5200  /* If it's not there (or the list is empty) use default_flag */
5201  g_free (result);
5202  result = NULL;
5203  }
5204  }
5205  else
5206  {
5207  g_free (result);
5208  result = g_strdup (text);
5209  }
5210 
5211  /* save the index in the cellrenderer */
5212  g_object_set_data (G_OBJECT (view->priv->temp_cr), "current-flag", GINT_TO_POINTER (index));
5213 
5214  g_signal_handlers_block_by_func (editable, (gpointer) gtv_sr_type_cb, user_data);
5215 
5216  gtk_editable_delete_text (editable, 0, -1);
5217  gtk_editable_insert_text (editable, result, length, position);
5218 
5219  g_signal_handlers_unblock_by_func (editable, (gpointer) gtv_sr_type_cb, user_data);
5220 
5221  g_signal_stop_emission_by_name (editable, "insert_text");
5222 
5223  g_free (result);
5224 }
5225 
5226 
5227 /* For handling keynav */
5228 static gboolean
5229 gtv_sr_ed_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
5230 {
5231  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5232  GncTreeModelSplitReg *model;
5233  GtkTreeViewColumn *col;
5234  GtkTreePath *spath;
5235  gboolean goto_blank = FALSE;
5236  gboolean next_trans = TRUE;
5237  Transaction *btrans, *ctrans;
5238  gint depth;
5239  gboolean auto_popped = FALSE;
5240 
5241  // spath is where we are, before key press...
5242  gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &spath, &col);
5243 
5244  if (event->type != GDK_KEY_PRESS)
5245  {
5246  if (spath)
5247  gtk_tree_path_free (spath);
5248  return FALSE;
5249  }
5250 
5251  switch (event->keyval)
5252  {
5253 
5254  case GDK_KEY_Up:
5255  case GDK_KEY_Down:
5256 
5257  if (!spath)
5258  return TRUE;
5259 
5260  // This is to test for the auto completion popup window
5261  {
5262  GtkWidget *toplevel;
5263  GtkWindowGroup *window_group;
5264  GList *win_list;
5265 
5266  toplevel = gtk_widget_get_toplevel (widget);
5267  if (GTK_IS_WINDOW (toplevel))
5268  {
5269  window_group = gtk_window_get_group (GTK_WINDOW (toplevel));
5270  win_list = gtk_window_group_list_windows (window_group);
5271  if (g_list_length (win_list) == 1 && gtk_widget_get_visible (GTK_WIDGET (win_list->data)))
5272  auto_popped = TRUE;
5273 
5274  g_list_free (win_list);
5275  }
5276  }
5277 
5278  // Auto complete window popped
5279  if (auto_popped == TRUE)
5280  {
5281  gtk_tree_path_free (spath);
5282  return FALSE;
5283  }
5284 
5285  model = gnc_tree_view_split_reg_get_model_from_view (view);
5286 
5287  // Make sure we have stopped editing.
5288  gnc_tree_view_split_reg_finish_edit (view);
5289 
5290  // This stops the cell changing.
5291  if (view->priv->stop_cell_move == TRUE)
5292  {
5293  gtk_tree_path_free (spath);
5294  return TRUE;
5295  }
5296 
5297  depth = gtk_tree_path_get_depth (spath);
5298  if (event->keyval == GDK_KEY_Up)
5299  {
5300  if (depth == 1)
5301  {
5302  if (gtk_tree_path_prev (spath))
5303  {
5304  if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath))
5305  {
5306  gtk_tree_path_down (spath);
5307 
5308  if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath) && model->type == GENERAL_JOURNAL2)
5309  {
5310  gtk_tree_path_down (spath);
5311 
5312  while (gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath))
5313  {
5314  gtk_tree_path_next (spath);
5315  }
5316  gtk_tree_path_prev (spath);
5317  }
5318  }
5319  }
5320  }
5321  else if (!gtk_tree_path_prev (spath) && depth > 1)
5322  {
5323  gtk_tree_path_up (spath);
5324  }
5325  }
5326  else if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath))
5327  {
5328  gtk_tree_path_down (spath);
5329  }
5330  else
5331  {
5332  gtk_tree_path_next (spath);
5333  if (!gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath) && depth > 2)
5334  {
5335  gtk_tree_path_prev (spath);
5336  gtk_tree_path_up (spath);
5337  gtk_tree_path_next (spath);
5338  }
5339  if (!gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath) && depth > 1)
5340  {
5341  gtk_tree_path_prev (spath);
5342  gtk_tree_path_up (spath);
5343  gtk_tree_path_next (spath);
5344  }
5345  }
5346 
5347  /* Set cursor to new column, open for editing */
5348  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, TRUE);
5349 
5350  if (event->keyval == GDK_KEY_Up)
5351  {
5352  gnc_tree_model_split_reg_move (model, VIEW_UP);
5353  }
5354  else
5355  gnc_tree_model_split_reg_move (model, VIEW_DOWN);
5356 
5357  return TRUE;
5358  break;
5359 
5360  case GDK_KEY_Return:
5361 
5362  if (!spath)
5363  return TRUE;
5364 
5365  // This stops the cell changing.
5366  if (view->priv->stop_cell_move == TRUE)
5367  {
5368  gtk_tree_path_free (spath);
5369  return TRUE;
5370  }
5371 
5372  // Do sums if we have ctrl key
5373  if (event->state & GDK_CONTROL_MASK)
5374  {
5375  // Make sure we have stopped editing.
5376  gnc_tree_view_split_reg_finish_edit (view);
5377 
5378  /* Set cursor to the column, open for editing */
5379  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, col, TRUE);
5380  gtk_tree_path_free (spath);
5381  return TRUE;
5382  }
5383  return FALSE;
5384  break;
5385 
5386  case GDK_KEY_KP_Enter:
5387 
5388  if (!spath)
5389  return TRUE;
5390 
5391  // This stops the cell changing.
5392  if (view->priv->stop_cell_move == TRUE)
5393  {
5394  gtk_tree_path_free (spath);
5395  return TRUE;
5396  }
5397 
5398  goto_blank = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
5399  GNC_PREF_ENTER_MOVES_TO_END);
5400 
5401  model = gnc_tree_view_split_reg_get_model_from_view (view);
5402  btrans = gnc_tree_model_split_get_blank_trans (model);
5403  ctrans = gnc_tree_view_split_reg_get_current_trans (view);
5404 
5405  /* Are we on the blank transaction */
5406  if (btrans == ctrans)
5407  next_trans = FALSE;
5408 
5409  /* First record the transaction */
5410  if (gnc_tree_view_split_reg_enter (view))
5411  {
5412  /* Now move. */
5413  if (goto_blank)
5414  g_idle_add ((GSourceFunc)gnc_tree_control_split_reg_jump_to_blank, view);
5415  else if (next_trans)
5416  gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
5417  }
5418  return TRUE;
5419  break;
5420 
5421  default:
5422  gtk_tree_path_free (spath);
5423  return FALSE;
5424  }
5425 }
5426 
5427 /*###########################################################################*/
5428 
5429 /* The main Start Editing Call back for the TEXT columns */
5430 static void
5431 gtv_sr_editable_start_editing_cb (GtkCellRenderer *cr, GtkCellEditable *editable,
5432  const gchar *path_string, gpointer user_data)
5433 {
5434  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5435  GncTreeModelSplitReg *model;
5436  GtkTreePath *spath;
5437  GtkEntry *entry = NULL;
5438  ViewCol viewcol;
5439  RowDepth depth;
5440  gint *indices;
5441 
5442  GtkListStore *description_list;
5443  GtkListStore *memo_list;
5444  GtkListStore *notes_list;
5445  GtkListStore *account_list;
5446 
5447  GtkEntryCompletion *completion = gtk_entry_completion_new();
5448 
5449  ENTER("gtv_sr_editable_start_editing_cb Path string is '%s'", path_string);
5450 
5451  model = gnc_tree_view_split_reg_get_model_from_view (view);
5452 
5453  /* Description / Notes / Memo / Accounts Completion Lists */
5454  description_list = gnc_tree_model_split_reg_get_description_list (model);
5455  notes_list = gnc_tree_model_split_reg_get_notes_list (model);
5456  memo_list = gnc_tree_model_split_reg_get_memo_list (model);
5457  account_list = gnc_tree_model_split_reg_get_acct_list (model);
5458 
5459  // Use depth to determine if it is a split or transaction
5460  spath = gtk_tree_path_new_from_string (path_string);
5461  depth = gtk_tree_path_get_depth (spath);
5462  indices = gtk_tree_path_get_indices (spath);
5463 
5464  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(cr), "view_column"));
5465 
5466  DEBUG("editable Depth is %u and ViewCol is %d", depth, viewcol);
5467 
5468  g_object_set_data (G_OBJECT (cr), "cell-editable", editable);
5469 
5470  // This is for key navigation...
5471  g_signal_connect (G_OBJECT (editable), "key-press-event", G_CALLBACK (gtv_sr_ed_key_press_cb), view);
5472 
5473  /* DATE COLUMN */
5474  if (viewcol == COL_DATE)
5475  {
5476  entry = GTK_ENTRY (GNC_POPUP_ENTRY (editable)->entry);
5477 
5478  //Copy the string in the GtkEntry for later comparison
5479  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5480 
5481  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_date, view);
5482 
5483  DEBUG("Current String date is '%s'", gtk_entry_get_text (entry));
5484  }
5485 
5486  /* TRANSFER / VOID COLUMN */
5487  else if (viewcol == COL_TRANSFERVOID)
5488  {
5489  entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (editable)));
5490 
5491  // This is for key navigation...
5492  g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (gtv_sr_ed_key_press_cb), view);
5493 
5494  {
5495  GtkEditable *editable = GTK_EDITABLE (entry);
5496 
5497  if (view->priv->stop_cell_move == TRUE)
5498  {
5499  gint textPosition = 0;
5500  gtk_editable_insert_text (GTK_EDITABLE (editable), view->priv->transfer_string, -1, &textPosition);
5501  gtk_editable_set_position (GTK_EDITABLE (editable), -1);
5502  }
5503  }
5504 
5505  // Update the Account list combo.
5506  gnc_tree_model_split_reg_update_account_list (model);
5507 
5508  gtk_entry_set_completion (entry, completion);
5509  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (account_list));
5510 
5511  /* This sets which text column to use, 0 for short names, 1 for long */
5512  if (view->priv->acct_short_names)
5513  gtk_entry_completion_set_text_column (completion, 0);
5514  else
5515  gtk_entry_completion_set_text_column (completion, 1);
5516 
5517  gtk_entry_completion_set_popup_completion (completion, TRUE);
5518  gtk_entry_completion_set_inline_selection (completion, TRUE);
5519  gtk_entry_completion_set_popup_set_width (completion, FALSE);
5520  gtk_entry_completion_set_minimum_key_length (completion, 1);
5521 //?? g_signal_connect(G_OBJECT(completion), "match-selected", (GCallback) gtv_sr_match_selected_cb, view);
5522  g_object_unref (completion);
5523 
5524  //Copy the string in the GtkEntry for later comparison
5525  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5526 
5527  g_signal_connect (G_OBJECT (entry), "insert_text", (GCallback) gtv_sr_acct_cb, view);
5528 
5529 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback) gtv_sr_changed_cb, view);
5530  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_combo, view);
5531 
5532  DEBUG("Current String tv is '%s'", gtk_entry_get_text (entry));
5533  }
5534 
5535  /* NUMBER / ACTION COLUMN */
5536  else if (viewcol == COL_NUMACT)
5537  {
5538  if ((depth == TRANS1) || ((depth == TRANS2) && (qof_book_use_split_action_for_num_field (gnc_get_current_book()))))
5539  {
5540  entry = GTK_ENTRY (editable);
5541 
5542  //Copy the string in the GtkEntry for later comparison
5543  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5544 
5545  g_signal_connect (G_OBJECT (GTK_ENTRY (entry)), "insert_text", (GCallback) gtv_sr_num_cb, view);
5546 
5547  view->priv->fo_handler_id = g_signal_connect (G_OBJECT (editable), "focus-out-event", (GCallback) gtv_sr_focus_out_cb, view);
5548 
5549  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_entry, view);
5550 
5551 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback)gtv_sr_changed_cb, view);
5552  DEBUG("Current String num is '%s'", gtk_entry_get_text (entry));
5553  }
5554 
5555  if ((depth == SPLIT3) || ((depth == TRANS2) && (!qof_book_use_split_action_for_num_field (gnc_get_current_book()))))
5556  {
5557  gnc_tree_model_split_reg_update_action_list (model);
5558 
5559  entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (editable)));
5560 
5561  //Copy the string in the GtkEntry for later comparison
5562  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5563 
5564 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback) gtv_sr_changed_cb, view);
5565  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_combo, view);
5566 
5567  DEBUG("Current String action is '%s'", gtk_entry_get_text (entry));
5568  }
5569  }
5570 
5571  /* DESCRIPTION / NOTES / MEMO COLUMN */
5572  else if (viewcol == COL_DESCNOTES)
5573  {
5574  entry = GTK_ENTRY (editable);
5575 
5576  // Update the auto completion lists.
5577  gnc_tree_model_split_reg_update_completion (model);
5578 
5579  //Data used for completion is set based on if editing split or not
5580  if (depth == TRANS1)
5581  {
5582  gtk_entry_set_completion (entry, completion);
5583  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (description_list));
5584  gtk_entry_completion_set_text_column (completion, 0);
5585  }
5586  else if (depth == TRANS2)
5587  {
5588  gtk_entry_set_completion (entry, completion);
5589  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (notes_list));
5590  gtk_entry_completion_set_text_column (completion, 0);
5591  }
5592  else if (depth == SPLIT3)
5593  {
5594  gtk_entry_set_completion (entry, completion);
5595  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (memo_list));
5596  gtk_entry_completion_set_text_column (completion, 0);
5597  }
5598 
5599  //To emit "match-selected" signal we need to have a list of matches to
5600  //select from instead of using inline autocompletion
5601  gtk_entry_completion_set_popup_completion (completion, TRUE);
5602  gtk_entry_completion_set_inline_selection (completion, TRUE);
5603  gtk_entry_completion_set_minimum_key_length (completion, view->priv->key_length);
5604 //?? g_signal_connect (G_OBJECT (completion), "match-selected", (GCallback) gtv_sr_match_selected_cb, view);
5605 
5606  g_object_unref (completion);
5607 
5608  //Copy the string in the GtkEntry for later comparison
5609  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5610 
5611  view->priv->fo_handler_id = g_signal_connect (G_OBJECT (editable), "focus-out-event", (GCallback) gtv_sr_focus_out_cb, view);
5612 
5613  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_entry, view);
5614 
5615  DEBUG("Current String dnm is '%s'", gtk_entry_get_text (entry));
5616  }
5617 
5618  /* RECN COLUMN */
5619  else if (viewcol == COL_RECN)
5620  {
5621  entry = GTK_ENTRY (editable);
5622 
5623  //Copy the string in the GtkEntry for later comparison
5624  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5625 
5626  g_signal_connect (G_OBJECT (GTK_ENTRY (editable)), "insert_text", (GCallback)gtv_sr_recn_cb, view);
5627 
5628  view->priv->fo_handler_id = g_signal_connect (G_OBJECT (editable), "focus-out-event", (GCallback) gtv_sr_focus_out_cb, view);
5629 
5630  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_entry, view);
5631 
5632 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback) gtv_sr_changed_cb, view);
5633  DEBUG("Current String recn is '%s'", gtk_entry_get_text (entry));
5634  }
5635 
5636  /* TYPE COLUMN */
5637  else if (viewcol == COL_TYPE)
5638  {
5639  entry = GTK_ENTRY (editable);
5640 
5641  //Copy the string in the GtkEntry for later comparison
5642  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5643 
5644  g_signal_connect (G_OBJECT (GTK_ENTRY (editable)), "insert_text", (GCallback)gtv_sr_type_cb, view);
5645 
5646  view->priv->fo_handler_id = g_signal_connect (G_OBJECT (editable), "focus-out-event", (GCallback) gtv_sr_focus_out_cb, view);
5647 
5648  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_entry, view);
5649 
5650 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback) gtv_sr_changed_cb, view);
5651  DEBUG("Current String type is '%s'", gtk_entry_get_text (entry));
5652  }
5653 
5654  /* THE REST OF THE COLUMNS */
5655  else
5656  {
5657  entry = GTK_ENTRY (editable);
5658 
5659  //Copy the string in the GtkEntry for later comparison
5660  g_object_set_data_full (G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)), g_free);
5661 
5662  view->priv->fo_handler_id = g_signal_connect (G_OBJECT (editable), "focus-out-event", (GCallback) gtv_sr_focus_out_cb, view);
5663 
5664  g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) gtv_sr_remove_edit_entry, view);
5665 
5666 //?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback)gtv_sr_changed_cb, view);
5667  DEBUG("Current String rest is '%s'", gtk_entry_get_text (entry));
5668  }
5669 
5670  /* Lets change the background of the entry widgets */
5671  {
5672  GdkRGBA color;
5673  const gchar *row_color;
5674  gboolean is_trow1 = FALSE;
5675  gboolean is_trow2 = FALSE;
5676  gboolean is_split = FALSE;
5677 
5678  if (depth == TRANS1)
5679  is_trow1 = TRUE;
5680  if (depth == TRANS2)
5681  is_trow2 = TRUE;
5682  if (depth == SPLIT3)
5683  is_split = TRUE;
5684 
5685  row_color = gnc_tree_model_split_reg_get_row_color (model, is_trow1, is_trow2, is_split, indices[0]);
5686 
5687  if (gdk_rgba_parse (&color, row_color))
5688  {
5689  if (entry != NULL)
5690  {
5691  GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET (entry));
5692  GtkCssProvider *provider = gtk_css_provider_new();
5693  gchar *col_str = gdk_rgba_to_string (&color);
5694  gchar *widget_css = g_strconcat ("*{\n background-color:", col_str, ";\n}\n", NULL);
5695 
5696  gtk_css_provider_load_from_data (provider, widget_css, -1, NULL);
5697  gtk_style_context_add_provider (stylectxt, GTK_STYLE_PROVIDER (provider),
5698  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
5699  g_object_unref (provider);
5700  g_free (col_str);
5701  g_free (widget_css);
5702  }
5703  }
5704  }
5705 
5706  gtv_sr_help (view, cr, viewcol, depth);
5707  gtk_tree_path_free (spath);
5708 
5709  view->priv->temp_cr = cr;
5710  view->editing_now = TRUE;
5711 
5712  DEBUG("Temp Cell Rend %p", view->priv->temp_cr);
5713 
5714  //Add edit-canceled property to cr so we can distinguish between
5715  //cancelled and actual changes
5716  g_object_set_data (G_OBJECT (cr), "edit-canceled", GINT_TO_POINTER (FALSE));
5717  LEAVE(" ");
5718 }
5719 
5720 #ifdef skip
5721 // Handle the "match-selected" signal
5722 static void
5723 gtv_sr_match_selected_cb (GtkEntryCompletion *widget, GtkTreeModel *model,
5724  GtkTreeIter *iter, gpointer user_data)
5725 {
5726 // GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5727 
5728 //FIXME g_print("gtv_sr_match_selected_cb\n\n");
5729 
5730 /* Not sure what I am going to put in here yet if anything */
5731 }
5732 #endif
5733 
5734 #ifdef skip
5735 // Handle the "changed" signal
5736 static void
5737 gtv_sr_changed_cb (GtkCellRendererCombo *widget, gchar *path_string,
5738  GtkTreeIter *iter, gpointer user_data)
5739 {
5740 // GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5741 
5742 //FIXME g_print("gtv_sr_changed_cb path string is '%s'\n\n", path_string);
5743 
5744 /* Not sure what I am going to put in here yet if anything */
5745 
5746 }
5747 #endif
5748 
5749 // Handle the "editing-canceled" signal
5750 static void
5751 gtv_sr_editing_canceled_cb (GtkCellRenderer *cr, gpointer user_data)
5752 {
5753  GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
5754 
5755  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view), "data-edited")) == FALSE) // Not edited, reset edit path
5756  {
5757  view->priv->dirty_trans = NULL;
5758  }
5759 
5760  /* Reset stop_cell_move */
5761  if (view->priv->stop_cell_move == TRUE)
5762  {
5763  view->priv->stop_cell_move = FALSE;
5764 
5765  /* this will populate cell with original value */
5766  g_idle_add ((GSourceFunc) gtv_sr_idle_transfer, view);
5767  }
5768 
5769  /* Reset Help text */
5770  if (view->help_text)
5771  g_free (view->help_text);
5772  view->help_text = g_strdup (" ");
5773  g_signal_emit_by_name (view, "help_signal", NULL);
5774 
5775  //Set edit-canceled property
5776  g_object_set_data (G_OBJECT (cr), "edit-canceled", GINT_TO_POINTER (TRUE));
5777 }
5778 
5779 /*####################################################################
5780  ^^^^ gtv function call backs ^^^^
5781 #####################################################################*/
5782 
5783 /* Scroll the view to show selected row based on sort direction */
5784 gboolean
5785 gnc_tree_view_split_reg_scroll_to_cell (GncTreeViewSplitReg *view)
5786 {
5787  GncTreeModelSplitReg *model;
5788  GtkTreePath *mpath, *spath;
5789 
5790  PINFO("#### Start Scroll to Cell ####");
5791 
5792  model = gnc_tree_view_split_reg_get_model_from_view (view);
5793 
5794  mpath = gnc_tree_view_split_reg_get_current_path (view);
5795  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
5796 
5797  if (model->sort_direction == GTK_SORT_DESCENDING)
5798  {
5799  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), spath, NULL, TRUE, 0.5, 0.0); //0.0
5800  }
5801  else
5802  {
5803  if (model->use_double_line)
5804  {
5805  gtk_tree_path_down (spath); // move to the second row of transaction
5806  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), spath, NULL, TRUE, 1.0, 0.0); //1.0
5807  }
5808  else
5809  {
5810  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), spath, NULL, TRUE, 1.0, 0.0); //1.0
5811  }
5812  }
5813 
5814  gtk_tree_path_free (mpath);
5815  gtk_tree_path_free (spath);
5816 
5817  PINFO("#### End Scroll to Cell ####");
5818 
5819  return (FALSE);
5820 }
5821 
5822 
5823 /* Scroll the view to show the blank split with least movement */
5824 gboolean
5825 gnc_tree_view_split_reg_scroll_to_bsplit (GncTreeViewSplitReg *view)
5826 {
5827  GncTreeModelSplitReg *model;
5828  GtkTreePath *bsplit_mpath, *bsplit_spath;
5829  Split *bsplit;
5830 
5831  model = gnc_tree_view_split_reg_get_model_from_view (view);
5832 
5833  /* Get the blank split spath */
5834  bsplit = gnc_tree_model_split_get_blank_split (model);
5835  bsplit_mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, bsplit, NULL);
5836  bsplit_spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, bsplit_mpath);
5837 
5838  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), bsplit_spath, NULL, FALSE, 1.0, 0.0);
5839 
5840  gtk_tree_path_free (bsplit_mpath);
5841  gtk_tree_path_free (bsplit_spath);
5842  return (FALSE);
5843 }
5844 
5845 
5846 /* Returns the Transaction at the current selected position */
5847 Transaction *
5848 gnc_tree_view_split_reg_get_current_trans (GncTreeViewSplitReg *view)
5849 {
5850  return view->priv->current_trans;
5851 }
5852 
5853 
5854 /* Returns the Split at the current selected position or NULL */
5855 Split *
5856 gnc_tree_view_split_reg_get_current_split (GncTreeViewSplitReg *view)
5857 {
5858  return view->priv->current_split;
5859 }
5860 
5861 
5862 /* Returns the depth of the selected row */
5863 RowDepth
5864 gnc_tree_view_reg_get_selected_row_depth (GncTreeViewSplitReg *view)
5865 {
5866  return view->priv->current_depth;
5867 }
5868 
5869 
5870 /* Returns the dirty_trans or NULL */
5871 Transaction *
5872 gnc_tree_view_split_reg_get_dirty_trans (GncTreeViewSplitReg *view)
5873 {
5874  return view->priv->dirty_trans;
5875 }
5876 
5877 
5878 /* Sets dirty_trans to trans or NULL to clear */
5879 void
5880 gnc_tree_view_split_reg_set_dirty_trans (GncTreeViewSplitReg *view, Transaction *trans)
5881 {
5882  if (trans == NULL)
5883  {
5884  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
5885  view->priv->dirty_trans = NULL;
5886  }
5887  else
5888  {
5889  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (TRUE));
5890  view->priv->dirty_trans = trans;
5891  }
5892 }
5893 
5894 
5895 /* Returns the current path, or NULL if the current path is the blank split. */
5896 GtkTreePath *
5897 gnc_tree_view_split_reg_get_current_path (GncTreeViewSplitReg *view)
5898 {
5899  if (!view->priv->current_ref)
5900  return NULL;
5901  return gtk_tree_row_reference_get_path (view->priv->current_ref);
5902 }
5903 
5904 
5905 /* Sets the current path reference to path */
5906 void
5907 gnc_tree_view_split_reg_set_current_path (GncTreeViewSplitReg *view, GtkTreePath *mpath)
5908 {
5909  GncTreeModelSplitReg *model;
5910 
5911  model = gnc_tree_view_split_reg_get_model_from_view (view);
5912 
5913  if (view->priv->current_ref != NULL)
5914  {
5915  gtk_tree_row_reference_free (view->priv->current_ref);
5916  view->priv->current_ref = NULL;
5917  }
5918  view->priv->current_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (model), mpath);
5919 }
5920 
5921 
5922 /* Reinit transaction / delete the splits */
5923 void
5924 gnc_tree_view_split_reg_reinit_trans (GncTreeViewSplitReg *view)
5925 {
5926  Transaction *trans;
5927  RowDepth depth;
5928 
5929  /* Make sure we have stopped editing */
5930  gnc_tree_view_split_reg_finish_edit (view);
5931 
5932  trans = view->priv->current_trans;
5933 
5934  // Lets get out of the way, move selection to trans - selection is blocked
5935  gnc_tree_control_split_reg_goto_rel_trans_row (view, 0);
5936 
5937  depth = view->priv->current_depth;
5938 
5939  if (trans && (depth != SPLIT3))
5940  {
5941  Split *s;
5942  int i = 0;
5943 
5944  if (!xaccTransIsOpen (trans))
5945  xaccTransBeginEdit (trans);
5946 
5947  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
5948 
5949  while ((s = xaccTransGetSplit (trans, i)) != NULL)
5950  {
5951  if (xaccTransGetRateForCommodity (trans, view->priv->reg_comm, s, NULL))
5952  xaccSplitDestroy (s);
5953  else i++;
5954  }
5955  }
5956 }
5957 
5958 
5959 /* Delete the current split */
5960 void
5961 gnc_tree_view_split_reg_delete_current_split (GncTreeViewSplitReg *view)
5962 {
5963  Transaction *trans;
5964  Split *split;
5965 
5966  /* Make sure we have stopped editing */
5967  gnc_tree_view_split_reg_finish_edit (view);
5968 
5969  trans = view->priv->current_trans;
5970  split = view->priv->current_split;
5971 
5972  if (!xaccTransIsOpen (trans))
5973  xaccTransBeginEdit (trans);
5974 
5975  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
5976 
5977  // Lets get out of the way, move selection to trans - selection is blocked
5978  gnc_tree_control_split_reg_goto_rel_trans_row (view, 0);
5979 
5980  xaccSplitDestroy (split);
5981 }
5982 
5983 
5984 /* Delete the current transaction */
5985 void
5986 gnc_tree_view_split_reg_delete_current_trans (GncTreeViewSplitReg *view)
5987 {
5988  Transaction *trans;
5989 
5990  /* We do not use the normal confirmation with this one as we have
5991  all ready asked the user to confirm delete */
5992 
5993  /* Make sure we have stopped editing */
5994  gnc_tree_view_split_reg_finish_edit (view);
5995 
5996  trans = view->priv->current_trans;
5997 
5998  /* We need to go back one to select the next transaction */
5999  gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
6000 
6001  if (!xaccTransIsOpen (trans))
6002  xaccTransBeginEdit (trans);
6003  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
6004 
6005  xaccTransDestroy (trans);
6006  xaccTransCommitEdit (trans);
6007 
6008  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
6009 }
6010 
6011 
6012 /* Record changes */
6013 gboolean
6014 gnc_tree_view_split_reg_enter (GncTreeViewSplitReg *view)
6015 {
6016  /* Make sure we have stopped editing */
6017  gnc_tree_view_split_reg_finish_edit (view);
6018 
6019  // Test for transaction changed
6020  if (gtv_sr_transaction_changed (view))
6021  return FALSE;
6022 
6023  // Return FALSE on discard
6024  if (view->priv->trans_confirm == DISCARD)
6025  return FALSE;
6026 
6027  return TRUE;
6028 }
6029 
6030 
6031 /* Cancel the edit and rollback changes */
6032 void
6033 gnc_tree_view_split_reg_cancel_edit (GncTreeViewSplitReg *view, gboolean reg_closing)
6034 {
6035  GncTreeModelSplitReg *model;
6036  Transaction *trans = view->priv->dirty_trans;
6037  Split *split;
6038 
6039  ENTER("gnc_tree_view_split_reg_cancel_edit view is %p and reg_closing is %d", view, reg_closing);
6040 
6041  model = gnc_tree_view_split_reg_get_model_from_view (view);
6042 
6043  if (trans && xaccTransIsOpen (trans))
6044  {
6045  // Move selection to trans - selection is blocked
6046  gnc_tree_control_split_reg_goto_rel_trans_row (view, 0);
6047 
6048  // Remove the split before rollback.
6049  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, TRUE);
6050 
6051  g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
6052  xaccTransRollbackEdit (view->priv->dirty_trans);
6053 
6054  // Add the split after rollback so it is last in list.
6055  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
6056 
6057  // Set the transaction to show correct view
6058  gnc_tree_view_split_reg_format_trans (view, view->priv->dirty_trans);
6059 
6060  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
6061 
6062  split = gnc_tree_model_split_get_blank_split (model);
6063  xaccSplitReinit (split); // Clear the blank split
6064  }
6065  /* Reset allow changes for reconciled transactions */
6066  view->change_allowed = FALSE;
6067 
6068  view->priv->auto_complete = FALSE; // reset auto_complete has run flag
6069 
6070  /* This updates the plugin page gui */
6072 
6073  LEAVE(" ");
6074 }
6075 
6076 
6077 /* Make sure we have stopped editing */
6078 void
6079 gnc_tree_view_split_reg_finish_edit (GncTreeViewSplitReg *view)
6080 {
6081  gtv_sr_finish_edit (view);
6082 
6083  /* give gtk+ a chance to handle pending events */
6084  while (gtk_events_pending ())
6085  gtk_main_iteration ();
6086 }
6087 
6088 
6089 /* Returns whether the splits are revealed for the transaction or current position
6090  if transaction is NULL */
6091 gboolean
6092 gnc_tree_view_split_reg_trans_expanded (GncTreeViewSplitReg *view, Transaction *trans)
6093 {
6094  GncTreeModelSplitReg *model;
6095  GtkTreePath *mpath, *spath;
6096  gboolean expanded;
6097 
6098  /* if trans is NULL use priv->expanded */
6099  if (trans == NULL)
6100  expanded = view->priv->expanded;
6101  else
6102  {
6103  model = gnc_tree_view_split_reg_get_model_from_view (view);
6104 
6105  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, trans);
6106 
6107  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
6108 
6109  gtk_tree_path_down (spath); /* Move the path down to trow2 */
6110 
6111  expanded = gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), spath);
6112 
6113  gtk_tree_path_free (mpath);
6114  gtk_tree_path_free (spath);
6115  }
6116  return expanded;
6117 }
6118 
6119 
6120 /* Collapse the transaction, if trans is NULL, use current_ref */
6121 void
6122 gnc_tree_view_split_reg_collapse_trans (GncTreeViewSplitReg *view, Transaction *trans)
6123 {
6124  GncTreeModelSplitReg *model;
6125  GtkTreePath *temp_spath, *mpath, *spath;
6126  GtkTreeIter m_iter;
6127  gint *indices;
6128  RowDepth depth;
6129 
6130  ENTER("gnc_tree_view_split_reg_collapse_trans and trans is %p", trans);
6131 
6132  model = gnc_tree_view_split_reg_get_model_from_view (view);
6133 
6134  /* Make sure we have stopped editing */
6135  gnc_tree_view_split_reg_finish_edit (view);
6136 
6137  /* if trans is NULL use current_ref */
6138  if (trans == NULL)
6139  mpath = gtk_tree_row_reference_get_path (view->priv->current_ref);
6140  else
6141  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, trans);
6142 
6143  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
6144 
6145  /* Collapse the view back to the transaction */
6146  indices = gtk_tree_path_get_indices (spath);
6147  depth = gtk_tree_path_get_depth (spath);
6148 
6149  if (model->use_double_line)
6150  temp_spath = gtk_tree_path_new_from_indices (indices[0], 0, -1);
6151  else
6152  temp_spath = gtk_tree_path_new_from_indices (indices[0], -1);
6153 
6154  /* if trans is NULL, collapse and update current_ref */
6155  if (trans == NULL)
6156  {
6157  GtkTreePath *temp_mpath;
6158 
6159  gnc_tree_view_split_reg_block_selection (view, TRUE);
6160 
6161  /* Change the selection to last available row of transaction - double */
6162  if ((model->use_double_line) && (depth == SPLIT3))
6163  gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), temp_spath);
6164 
6165  /* Change the selection to last available row of transaction - single */
6166  if ((!model->use_double_line) && (depth != TRANS1))
6167  gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), temp_spath);
6168 
6169  gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), temp_spath);
6170 
6171  /* Get the selection */
6172  if (gtv_sr_get_model_iter_from_selection (view, gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), &m_iter))
6173  {
6174  temp_mpath = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &m_iter);
6175 
6176  /* Update the tree view titles */
6177  gtv_sr_titles (view, gtk_tree_path_get_depth (temp_mpath));
6178 
6179  /* Save the new model path to path ref */
6180  gnc_tree_view_split_reg_set_current_path (view, temp_mpath);
6181 
6182  gtk_tree_path_free (temp_mpath);
6183  }
6184  gnc_tree_view_split_reg_block_selection (view, FALSE);
6185  }
6186  else
6187  gtk_tree_view_collapse_row (GTK_TREE_VIEW (view), temp_spath);
6188 
6189  gtk_tree_path_free (temp_spath);
6190  gtk_tree_path_free (mpath);
6191  gtk_tree_path_free (spath);
6192 
6193  view->priv->expanded = FALSE;
6194 
6195  /* This updates the plugin page gui */
6197 
6198  LEAVE(" ");
6199 }
6200 
6201 
6202 /* Expands the transaction or the current transaction if NULL */
6203 void
6204 gnc_tree_view_split_reg_expand_trans (GncTreeViewSplitReg *view, Transaction *trans)
6205 {
6206  GncTreeModelSplitReg *model;
6207  GtkTreePath *mpath, *spath;
6208  GtkTreePath *start_path, *end_path;
6209  gint *indices_spath;
6210  gint num_splits;
6211 
6212  ENTER("gnc_tree_view_split_reg_expand_trans and trans is %p", trans);
6213 
6214  model = gnc_tree_view_split_reg_get_model_from_view (view);
6215 
6216  /* Make sure we have stopped editing */
6217  gnc_tree_view_split_reg_finish_edit (view);
6218 
6219  if (trans == NULL)
6220  mpath = gtk_tree_row_reference_get_path (view->priv->current_ref);
6221  else
6222  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, trans);
6223 
6224  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
6225 
6226  gtk_tree_view_expand_row (GTK_TREE_VIEW (view), spath, TRUE);
6227 
6228  view->priv->expanded = TRUE;
6229 
6230  if (view->priv->selection_to_blank_on_expand && (model->style != REG2_STYLE_JOURNAL))
6231  gtv_sr_selection_to_blank (view);
6232 
6233  /* Get spath indices and the number of splits */
6234  indices_spath = gtk_tree_path_get_indices (spath);
6235  num_splits = xaccTransCountSplits (view->priv->current_trans);
6236 
6237  if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (view), &start_path, &end_path))
6238  {
6239 // gint *indices_start;
6240  gint *indices_end;
6241  gint lines = 0;
6242 
6243  /* The first and last visible path */
6244 // indices_start = gtk_tree_path_get_indices (start_path);
6245  indices_end = gtk_tree_path_get_indices (end_path);
6246 
6247  if (model->use_double_line)
6248  lines = (indices_end[0] - indices_spath[0])*2;
6249  else
6250  lines = indices_end[0] - indices_spath[0];
6251 
6252  if ((num_splits + 1) > lines)
6253  {
6254  /* scroll window to show selection when view is idle */
6255  g_idle_add ((GSourceFunc) gnc_tree_view_split_reg_scroll_to_bsplit, view );
6256  }
6257  gtk_tree_path_free (start_path);
6258  gtk_tree_path_free (end_path);
6259  }
6260  gtk_tree_path_free (mpath);
6261  gtk_tree_path_free (spath);
6262 
6263  /* This updates the plugin page gui */
6265 
6266  LEAVE(" ");
6267 }
6268 
6269 
6270 /* Return the credit and debit titles of those columns */
6271 const char *
6272 gnc_tree_view_split_reg_get_credit_debit_string (GncTreeViewSplitReg *view, gboolean credit)
6273 {
6274  GtkCellRenderer *cr0;
6275  GList *renderers;
6276  GList *columns;
6277  GList *column;
6278  gint i;
6279  const char *title = NULL;
6280 
6281  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
6282 
6283  for ( column = columns, i = 1; column; column = g_list_next (column), i++)
6284  {
6285  GtkTreeViewColumn *tvc;
6286  ViewCol viewcol;
6287 
6288  tvc = column->data;
6289 
6290  // Get the first renderer, it has the view-column value.
6291  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tvc));
6292  cr0 = g_list_nth_data (renderers, 0);
6293  g_list_free (renderers);
6294 
6295  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT(cr0), "view_column"));
6296 
6297  DEBUG("viewcol is %d", viewcol);
6298 
6299  if (viewcol == COL_CREDIT && credit)
6300  title = gtk_tree_view_column_get_title (tvc);
6301 
6302  if (viewcol == COL_DEBIT && !credit)
6303  title = gtk_tree_view_column_get_title (tvc);
6304  }
6305  g_list_free (columns);
6306  return title;
6307 }
6308 
6309 
6310 /* Returns the parent Window */
6311 GtkWidget *
6312 gnc_tree_view_split_reg_get_parent (GncTreeViewSplitReg *view)
6313 {
6314  GncTreeModelSplitReg *model;
6315  model = gnc_tree_view_split_reg_get_model_from_view (view);
6316  return gnc_tree_model_split_reg_get_parent (model);
6317 }
6318 
6319 
6320 /* This sets up the page gui update from the tree view motion callback */
6321 void
6322 gnc_tree_view_split_reg_set_uiupdate_cb (GncTreeViewSplitReg *view, GFunc cb, gpointer cb_data)
6323 {
6324  view->uiupdate_cb = cb;
6325  view->uiupdate_cb_data = cb_data;
6326 }
6327 
6333 {
6334  g_assert(view);
6335  if (view->uiupdate_cb)
6336  (view->uiupdate_cb)(view, view->uiupdate_cb_data);
6337  return FALSE;
6338 }
6339 
void xaccSplitSetValue(Split *split, gnc_numeric val)
The xaccSplitSetValue() method sets the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:92
void gnc_tree_view_set_sort_user_data(GncTreeView *view, GtkTreeModel *s_model)
This allows the columns to be setup without the model connected.
gboolean gnc_tree_view_split_reg_call_uiupdate_cb(GncTreeViewSplitReg *view)
Call the moved_cb callback that is used to update the page ui, if it is set.
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4933
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gboolean use_double_line
FIXME ? As above, whether to use two lines per transaction.
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gint current_row
Current row in treeview.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Definition: Transaction.c:1034
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gnc_numeric xaccTransGetAccountBalance(const Transaction *trans, const Account *account)
Get the account balance for the specified account after the last split in the specified transaction...
Definition: Transaction.c:1329
char xaccTransGetTxnType(Transaction *trans)
Returns the Transaction Type: note this type will be derived from the transaction splits...
Definition: Transaction.c:2556
#define TXN_TYPE_INVOICE
Transaction is an invoice.
Definition: Transaction.h:126
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3279
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1466
gboolean read_only
register is read only
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
const char * xaccTransGetVoidReason(const Transaction *trans)
Returns the user supplied textual reason why a transaction was voided.
Definition: Transaction.c:2835
gint sort_col
This is the column the sort direction is based on.
common utilities for manipulating a GtkTreeView within gnucash
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void qof_instance_set(QofInstance *inst, const gchar *first_prop,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
gboolean use_gnc_color_theme
whether to use the gnucash built-in color theme
GtkTreeViewColumn * gnc_tree_view_add_date_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new date column to a GncTreeView base view.
const char * xaccPrintAmount(gnc_numeric val, GNCPrintAmountInfo info)
Make a string representation of a gnc_numeric.
Definition: gnc-ui-util.c:1859
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
SplitRegisterType2 type
FIXME ? This may be the wrong place for these, may be the view ?
GtkSortType sort_direction
This is the direction of sort.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
GtkTreeViewColumn * gnc_tree_view_add_combo_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeModel *combo_tree_model, gint combo_model_text_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new combobox column to a GncTreeView base view.
Account * gnc_tree_model_split_reg_get_anchor(GncTreeModelSplitReg *model)
Return the default account for this register model.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition: qofutil.cpp:187
gboolean alt_colors_by_txn
whether to use alternative colors by transaction
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition: Account.cpp:4945
gboolean gnc_tree_model_split_reg_get_template(GncTreeModelSplitReg *model)
Return TRUE if this is a template register.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
#define VREC
split is void
Definition: Split.h:75
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Definition: Transaction.c:1426
void gnc_tree_model_split_reg_commit_blank_split(GncTreeModelSplitReg *model)
Commit the blank split.
Account used to record multiple commodity transactions.
Definition: Account.h:158
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Transaction * current_trans
Current transaction.
gboolean gnc_tree_model_split_reg_trans_is_in_view(GncTreeModelSplitReg *model, Transaction *trans)
Return TRUE if transaction is in the view list.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
#define xaccAccountGetGUID(X)
Definition: Account.h:248
void xaccTransSetTxnType(Transaction *trans, char type)
Set the Transaction Type: note the type will be saved into the Transaction kvp property as a backward...
Definition: Transaction.c:2111
#define TXN_TYPE_NONE
No transaction type.
Definition: Transaction.h:125
convert single-entry accounts to clean double-entry
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3308
gboolean use_accounting_labels
whether to use accounting Labels
#define YREC
The Split has been reconciled.
Definition: Split.h:72
void xaccSplitSetMemo(Split *split, const char *memo)
The memo is an arbitrary string associated with a split.
Definition: Split.c:1724
void gnc_tree_model_split_reg_move(GncTreeModelSplitReg *model, GncTreeModelSplitRegUpdate model_update)
Change transactions in the tlist based on view movement.
#define FREC
frozen into accounting period
Definition: Split.h:73
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
Definition: Scrub.c:794
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2492
void gnc_tree_view_set_control_column_background(GncTreeView *view, gint column, GtkTreeCellDataFunc func)
This function links the cell backgrounds of the two control columns to a column in the model that has...
SplitRegisterStyle2 style
FIXME ? This may be the wrong place for these, may be the view ?
gint sort_depth
This is the row the sort direction is based on.
gboolean xaccTransInFutureByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction&#39;s posted-date is in the future.
Definition: Transaction.c:2675
Account * gnc_tree_model_split_reg_get_template_account(GncTreeModelSplitReg *model)
Returns the template account.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
gnc_numeric gnc_numeric_abs(gnc_numeric a)
Returns a newly created gnc_numeric that is the absolute value of the given gnc_numeric value...
void xaccTransSetDate(Transaction *trans, int day, int mon, int year)
The xaccTransSetDate() method does the same thing as xaccTransSetDate[Posted]Secs(), but takes a convenient day-month-year format.
Definition: Transaction.c:2080
#define MAX_DATE_LENGTH
The maximum length of a string created by the date printers.
Definition: gnc-date.h:114
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition: Split.c:1923
#define TXN_TYPE_PAYMENT
Transaction is a payment.
Definition: Transaction.h:127
#define CREC
The Split has been cleared.
Definition: Split.h:71
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
Generic api to store and retrieve preferences.
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: gnc-ui-util.c:1202
const char * gnc_commodity_get_printname(const gnc_commodity *cm)
Retrieve the &#39;print&#39; name for the specified commodity.
Transaction * gnc_tree_model_split_reg_get_first_trans(GncTreeModelSplitReg *model)
Return the first transaction, opposite to blank transaction in the full list.
time64 xaccSplitGetDateReconciled(const Split *split)
Retrieve the date when the Split was reconciled.
Definition: Split.c:1816
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1367
#define xaccAccountInsertSplit(acc, s)
The xaccAccountInsertSplit() method will insert the indicated split into the indicated account...
Definition: Account.h:1038
#define gnc_leave_return_if_fail(test)
Replacement for g_return_if_fail, but calls LEAVE if the test fails.
Definition: qoflog.h:300
GtkTreeViewColumn * gnc_tree_view_add_text_column(GncTreeView *view, const gchar *column_title, const gchar *pref_name, const gchar *icon_name, const gchar *sizing_text, gint model_data_column, gint model_visibility_column, GtkTreeIterCompareFunc column_sort_fn)
This function adds a new text column to a GncTreeView base view.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
GNCNumericErrorCode gnc_numeric_check(gnc_numeric in)
Check for error signal in value.
The instance data structure for an account tree model.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
GtkWidget * gnc_tree_model_split_reg_get_parent(GncTreeModelSplitReg *model)
Returns the parent Window of the register.
time64 xaccTransRetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
Definition: Transaction.c:2533
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to...
Definition: Account.cpp:2906
const char * xaccAccountGetName(const Account *acc)
Get the account&#39;s name.
Definition: Account.cpp:3301
Scheduled Transactions public handling routines.
No error.
Definition: gnc-numeric.h:224
API for Transactions and Splits (journal entries)
The type used to store guids in C.
Definition: guid.h:75
time64 xaccTransRetDateDue(const Transaction *trans)
Dates and txn-type for A/R and A/P "invoice" postings.
Definition: Transaction.c:2539
size_t qof_print_date_buff(char *buff, size_t buflen, time64 secs)
Convenience: calls through to qof_print_date_dmy_buff().
Definition: gnc-date.cpp:581
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...
Definition: Transaction.c:1730
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric xaccTransGetAccountAmount(const Transaction *trans, const Account *acc)
Same as xaccTransGetAccountValue, but uses the Account&#39;s commodity.
Definition: Transaction.c:1205
gnc_numeric xaccTransGetAccountValue(const Transaction *trans, const Account *acc)
The xaccTransGetAccountValue() method returns the total value applied to a particular account...
Definition: Transaction.c:1189
const gchar * gnc_get_account_separator_string(void)
Returns the account separation character chosen by the user.
Definition: Account.cpp:201
#define NREC
not reconciled or cleared
Definition: Split.h:74
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Get an float value from the preferences backend.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69