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