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