GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
split-register.c
1 /********************************************************************\
2  * This program is free software; you can redistribute it and/or *
3  * modify it under the terms of the GNU General Public License as *
4  * published by the Free Software Foundation; either version 2 of *
5  * the License, or (at your option) any later version. *
6  * *
7  * This program is distributed in the hope that it will be useful, *
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
10  * GNU General Public License for more details. *
11  * *
12  * You should have received a copy of the GNU General Public License*
13  * along with this program; if not, contact: *
14  * *
15  * Free Software Foundation Voice: +1-617-542-5942 *
16  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
17  * Boston, MA 02110-1301, USA [email protected] *
18  * *
19 \********************************************************************/
20 /*
21  * split-register.c
22  * author Copyright (c) 1998-2000 Linas Vepstas <[email protected]>
23  * author Copyright (c) 2000-2001 Dave Peticolas <[email protected]>
24  */
25 #include "config.h"
26 
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <libguile.h>
30 
31 #include <gnc-gdate-utils.h>
32 #include "combocell.h"
33 #include "datecell.h"
34 #include "dialog-utils.h"
35 #include "gnc-component-manager.h"
36 #include "split-register-p.h"
37 #include "gnc-ledger-display.h"
38 #include "gnc-prefs.h"
39 #include "gnc-ui.h"
40 #include "gnome-utils/gnc-warnings.h"
41 #include "guile-util.h"
42 #include "numcell.h"
43 #include "pricecell.h"
44 #include "quickfillcell.h"
45 #include "recncell.h"
46 #include "split-register.h"
47 #include "split-register-control.h"
48 #include "split-register-layout.h"
49 #include "split-register-model.h"
50 #include "split-register-model-save.h"
51 #include "table-allgui.h"
52 #include "dialog-account.h"
53 #include "dialog-dup-trans.h"
54 #include "engine-helpers.h"
55 #include "qofbookslots.h"
56 
57 
60 /* This static indicates the debugging module that this .o belongs to. */
61 static QofLogModule log_module = GNC_MOD_LEDGER;
62 
63 /* The copied split or transaction, if any */
64 static CursorClass copied_class = CURSOR_CLASS_NONE;
65 static SCM copied_item = SCM_UNDEFINED;
66 static GncGUID copied_leader_guid;
67 
68 
71 static gboolean gnc_split_register_save_to_scm (SplitRegister *reg,
72  SCM trans_scm, SCM split_scm,
73  gboolean use_cut_semantics);
74 static gboolean gnc_split_register_auto_calc (SplitRegister *reg,
75  Split *split);
76 
77 
80 /* Uses the scheme split copying routines */
81 static void
82 gnc_copy_split_onto_split(Split *from, Split *to, gboolean use_cut_semantics)
83 {
84  SCM split_scm;
85 
86  if ((from == NULL) || (to == NULL))
87  return;
88 
89  split_scm = gnc_copy_split(from, use_cut_semantics);
90  if (split_scm == SCM_UNDEFINED)
91  return;
92 
93  gnc_copy_split_scm_onto_split(split_scm, to, gnc_get_current_book ());
94 }
95 
96 /* Uses the scheme transaction copying routines */
97 void
99  gboolean use_cut_semantics,
100  gboolean do_commit)
101 {
102  SCM trans_scm;
103 
104  if ((from == NULL) || (to == NULL))
105  return;
106 
107  trans_scm = gnc_copy_trans(from, use_cut_semantics);
108  if (trans_scm == SCM_UNDEFINED)
109  return;
110 
111  gnc_copy_trans_scm_onto_trans(trans_scm, to, do_commit,
112  gnc_get_current_book ());
113 }
114 
115 static int
116 gnc_split_get_value_denom (Split *split)
117 {
118  gnc_commodity *currency;
119  int denom;
120 
121  currency = xaccTransGetCurrency (xaccSplitGetParent (split));
122  denom = gnc_commodity_get_fraction (currency);
123  if (denom == 0)
124  {
125  gnc_commodity *commodity = gnc_default_currency ();
126  denom = gnc_commodity_get_fraction (commodity);
127  if (denom == 0)
128  denom = 100;
129  }
130 
131  return denom;
132 }
133 
134 static int
135 gnc_split_get_amount_denom (Split *split)
136 {
137  int denom;
138 
140  if (denom == 0)
141  {
142  gnc_commodity *commodity = gnc_default_currency ();
143  denom = gnc_commodity_get_fraction (commodity);
144  if (denom == 0)
145  denom = 100;
146  }
147 
148  return denom;
149 }
150 
151 /* returns TRUE if begin_edit was aborted */
152 gboolean
153 gnc_split_register_begin_edit_or_warn(SRInfo *info, Transaction *trans)
154 {
155  ENTER("info=%p, trans=%p", info, trans);
156 
157  if (!xaccTransIsOpen(trans))
158  {
159  xaccTransBeginEdit(trans);
160  /* This is now the pending transaction */
161  info->pending_trans_guid = *xaccTransGetGUID(trans);
162  LEAVE("opened and marked pending");
163  return FALSE;
164  }
165  else
166  {
167  Split *blank_split = xaccSplitLookup (&info->blank_split_guid,
168  gnc_get_current_book ());
169  Transaction *blank_trans = xaccSplitGetParent (blank_split);
170 
171  if (trans == blank_trans)
172  {
173  /* This is a brand-new transaction. It is already
174  * open, so just mark it as pending. */
175  info->pending_trans_guid = *xaccTransGetGUID(trans);
176  LEAVE("already open, now pending.");
177  return FALSE;
178  }
179  else
180  {
181  GtkWidget *parent = NULL;
182  if (info->get_parent)
183  parent = info->get_parent(info->user_data);
184  gnc_error_dialog(parent, "%s", _("This transaction is already being edited in another register. Please finish editing it there first."));
185  LEAVE("already editing");
186  return TRUE;
187  }
188  }
189  LEAVE(" ");
190  return FALSE; /* to satisfy static code analysis */
191 }
192 
193 void
195 {
196  SRInfo *info = gnc_split_register_get_info (reg);
197  VirtualLocation virt_loc;
198 
199  if (!reg)
200  return;
201 
202  if (reg->style == REG_STYLE_AUTO_LEDGER ||
203  reg->style == REG_STYLE_JOURNAL)
204  return;
205 
206  /* ok, so I just wanted an excuse to use exclusive-or */
207  if (!(expand ^ info->trans_expanded))
208  return;
209 
210  if (!expand)
211  {
212  virt_loc = reg->table->current_cursor_loc;
213  gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
214  &virt_loc.vcell_loc);
215 
216  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
217  gnc_table_move_cursor_gui (reg->table, virt_loc);
218  else
219  {
220  PERR ("Can't find place to go!");
221  return;
222  }
223  }
224 
225  info->trans_expanded = expand;
226 
227  gnc_table_set_virt_cell_cursor (reg->table,
228  reg->table->current_cursor_loc.vcell_loc,
229  gnc_split_register_get_active_cursor (reg));
230 
231  gnc_split_register_set_trans_visible(
232  reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
233 
234  virt_loc = reg->table->current_cursor_loc;
235  if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
236  {
237  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
238  gnc_table_move_cursor_gui (reg->table, virt_loc);
239  else
240  {
241  PERR ("Can't find place to go!");
242  return;
243  }
244  }
245 
246  gnc_table_refresh_gui (reg->table, TRUE);
247 
248  if (expand)
249  gnc_split_register_show_trans (reg,
250  reg->table->current_cursor_loc.vcell_loc);
251 }
252 
253 gboolean
255 {
256  SRInfo *info = gnc_split_register_get_info (reg);
257 
258  if (!reg)
259  return FALSE;
260 
261  if (reg->style == REG_STYLE_AUTO_LEDGER ||
262  reg->style == REG_STYLE_JOURNAL)
263  return TRUE;
264 
265  return info->trans_expanded;
266 }
267 
268 Transaction *
270 {
271  Split *split;
272  VirtualCellLocation vcell_loc;
273 
274  if (reg == NULL)
275  return NULL;
276 
278  if (split != NULL)
279  return xaccSplitGetParent(split);
280 
281  /* Split is blank. Assume it is the blank split of a multi-line
282  * transaction. Go back one row to find a split in the transaction. */
283  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
284 
285  vcell_loc.virt_row--;
286 
287  split = gnc_split_register_get_split (reg, vcell_loc);
288 
289  return xaccSplitGetParent (split);
290 }
291 
292 Split *
294 {
295  if (reg == NULL)
296  return NULL;
297 
298  return gnc_split_register_get_split(
299  reg, reg->table->current_cursor_loc.vcell_loc);
300 }
301 
302 Split *
304 {
305  SRInfo *info = gnc_split_register_get_info (reg);
306 
307  if (!reg) return NULL;
308 
309  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
310 }
311 
312 gboolean
314  VirtualCellLocation *vcell_loc)
315 {
316  Table *table;
317  int v_row;
318  int v_col;
319 
320  if (!reg || !split) return FALSE;
321 
322  table = reg->table;
323 
324  /* go backwards because typically you search for splits at the end
325  * and because we find split rows before transaction rows. */
326 
327  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
328  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
329  {
330  VirtualCellLocation vc_loc = { v_row, v_col };
331  VirtualCell *vcell;
332  Split *s;
333 
334  vcell = gnc_table_get_virtual_cell (table, vc_loc);
335  if (!vcell || !vcell->visible)
336  continue;
337 
338  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
339 
340  if (s == split)
341  {
342  if (vcell_loc)
343  *vcell_loc = vc_loc;
344 
345  return TRUE;
346  }
347  }
348 
349  return FALSE;
350 }
351 
352 gboolean
354  VirtualLocation *virt_loc)
355 {
356  VirtualLocation v_loc;
357  CursorClass cursor_class;
358  const char *cell_name;
359  gnc_numeric value;
360 
361  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
362  return FALSE;
363 
364  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
365 
366  value = xaccSplitGetValue (split);
367 
368  switch (cursor_class)
369  {
370  case CURSOR_CLASS_SPLIT:
371  case CURSOR_CLASS_TRANS:
372  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
373  break;
374  default:
375  return FALSE;
376  }
377 
378  if (!gnc_table_get_cell_location (reg->table, cell_name,
379  v_loc.vcell_loc, &v_loc))
380  return FALSE;
381 
382  if (virt_loc == NULL)
383  return TRUE;
384 
385  *virt_loc = v_loc;
386 
387  return TRUE;
388 }
389 
390 Split *
392 {
393  SRInfo *info = gnc_split_register_get_info(reg);
394  CursorClass cursor_class;
395  Transaction *trans;
396  Split *return_split;
397  Split *trans_split;
398  Split *blank_split;
399  gboolean changed;
400  Split *split;
401 
402  ENTER("reg=%p", reg);
403 
404  blank_split = xaccSplitLookup(&info->blank_split_guid,
405  gnc_get_current_book ());
408  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
409 
410  /* This shouldn't happen, but be paranoid. */
411  if (trans == NULL)
412  {
413  LEAVE("no transaction");
414  return NULL;
415  }
416 
417  cursor_class = gnc_split_register_get_current_cursor_class (reg);
418 
419  /* Can't do anything with this. */
420  if (cursor_class == CURSOR_CLASS_NONE)
421  {
422  LEAVE("no cursor class");
423  return NULL;
424  }
425 
426  /* This shouldn't happen, but be paranoid. */
427  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
428  {
429  LEAVE("no split with transaction class");
430  return NULL;
431  }
432 
433  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
434 
435  /* See if we were asked to duplicate an unchanged blank split.
436  * There's no point in doing that! */
437  if (!changed && ((split == NULL) || (split == blank_split)))
438  {
439  LEAVE("skip unchanged blank split");
440  return NULL;
441  }
442 
443  gnc_suspend_gui_refresh ();
444 
445  /* If the cursor has been edited, we are going to have to commit
446  * it before we can duplicate. Make sure the user wants to do that. */
447  if (changed)
448  {
449  GtkWidget *dialog, *window;
450  gint response;
451  const char *title = _("Save transaction before duplicating?");
452  const char *message =
453  _("The current transaction has been changed. Would you like to "
454  "record the changes before duplicating the transaction, or "
455  "cancel the duplication?");
456 
457  window = gnc_split_register_get_parent(reg);
458  dialog = gtk_message_dialog_new(GTK_WINDOW(window),
459  GTK_DIALOG_DESTROY_WITH_PARENT,
460  GTK_MESSAGE_QUESTION,
461  GTK_BUTTONS_CANCEL,
462  "%s", title);
463  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
464  "%s", message);
465  gtk_dialog_add_button(GTK_DIALOG(dialog),
466  _("_Record"), GTK_RESPONSE_ACCEPT);
467  response = gnc_dialog_run(GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_DUP);
468  gtk_widget_destroy(dialog);
469 
470  if (response != GTK_RESPONSE_ACCEPT)
471  {
472  gnc_resume_gui_refresh ();
473  LEAVE("save cancelled");
474  return NULL;
475  }
476 
477  gnc_split_register_save (reg, TRUE);
478 
479  /* If the split is NULL, then we were on a blank split row
480  * in an expanded transaction. The new split (created by
481  * gnc_split_register_save above) will be the last split in the
482  * current transaction, as it was just added. */
483  if (split == NULL)
484  split = xaccTransGetSplit (trans, xaccTransCountSplits (trans) - 1);
485  }
486 
487  /* Ok, we are now ready to make the copy. */
488 
489  if (cursor_class == CURSOR_CLASS_SPLIT)
490  {
491  Split *new_split;
492  char *out_num;
493  gboolean new_act_num = FALSE;
494 
495  /* We are on a split in an expanded transaction.
496  * Just copy the split and add it to the transaction.
497  * However, if the split-action field is being used as the register
498  * number, and the action field is a number, request a new value or
499  * cancel. Need to get next number and update account last num from
500  * split account not register account, which may be the same or not */
501 
503  && gnc_strisnum (gnc_get_num_action (NULL, split)))
504  {
505  Account *account = xaccSplitGetAccount (split);
506  const char *in_num = NULL;
507  const char* title = _("New Split Information");
508  time64 date = info->last_date_entered;
509 
510  if (account)
511  in_num = xaccAccountGetLastNum (account);
512  else
513  in_num = gnc_get_num_action (NULL, split);
514  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg),
515  title, FALSE, &date, in_num, &out_num, NULL, NULL))
516  {
517  gnc_resume_gui_refresh ();
518  LEAVE("dup cancelled");
519  return NULL;
520  }
521  new_act_num = TRUE;
522  }
523 
524  new_split = xaccMallocSplit (gnc_get_current_book ());
525 
526  xaccTransBeginEdit (trans);
527  xaccSplitSetParent (new_split, trans);
528  gnc_copy_split_onto_split (split, new_split, FALSE);
529  if (new_act_num) /* if new number supplied by user dialog */
530  gnc_set_num_action (NULL, new_split, out_num, NULL);
531  xaccTransCommitEdit (trans);
532 
533  if (new_act_num && gnc_strisnum (out_num))
534  {
535  Account *account = xaccSplitGetAccount (new_split);
536 
537  /* If current register is for account, set last num */
538  if (xaccAccountEqual(account,
539  gnc_split_register_get_default_account(reg),
540  TRUE))
541  {
542  NumCell *num_cell;
543  num_cell = (NumCell *) gnc_table_layout_get_cell (reg->table->layout,
544  NUM_CELL);
545  if (gnc_num_cell_set_last_num (num_cell, out_num))
546  gnc_split_register_set_last_num (reg, out_num);
547  }
548  else
549  {
550  xaccAccountSetLastNum (account, out_num);
551  }
552  }
553 
554  return_split = new_split;
555 
556  info->cursor_hint_split = new_split;
557  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
558  if (new_act_num)
559  g_free (out_num);
560  }
561  else
562  {
563  NumCell *num_cell;
564  Transaction *new_trans;
565  int trans_split_index;
566  int split_index;
567  const char *in_num = NULL;
568  const char *in_tnum = NULL;
569  char *out_num;
570  char *out_tnum;
571  time64 date;
572  gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book());
573 
574  /* We are on a transaction row. Copy the whole transaction. */
575 
576  date = info->last_date_entered;
577  if (gnc_strisnum (gnc_get_num_action (trans, trans_split)))
578  {
579  Account *account = gnc_split_register_get_default_account (reg);
580 
581  if (account)
582  in_num = xaccAccountGetLastNum (account);
583  else
584  in_num = gnc_get_num_action (trans, trans_split);
585  in_tnum = (reg->use_tran_num_for_num_field
586  ? NULL
587  : gnc_get_num_action (trans, NULL));
588  }
589 
590  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg), NULL,
591  TRUE, &date, in_num, &out_num, in_tnum, &out_tnum))
592  {
593  gnc_resume_gui_refresh ();
594  LEAVE("dup cancelled");
595  return NULL;
596  }
597 
598  if (use_autoreadonly)
599  {
600  GDate d;
601  GDate *readonly_threshold = qof_book_get_autoreadonly_gdate(gnc_get_current_book());
602  gnc_gdate_set_time64 (&d, date);
603  if (g_date_compare(&d, readonly_threshold) < 0)
604  {
605  GtkWidget *dialog = gtk_message_dialog_new(NULL,
606  0,
607  GTK_MESSAGE_ERROR,
608  GTK_BUTTONS_OK,
609  "%s", _("Cannot store a transaction at this date"));
610  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
611  "%s", _("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book. "
612  "This setting can be changed in File -> Properties -> Accounts."));
613  gtk_dialog_run(GTK_DIALOG(dialog));
614  gtk_widget_destroy(dialog);
615 
616  g_date_free(readonly_threshold);
617  return NULL;
618  }
619  g_date_free(readonly_threshold);
620  }
621 
622  split_index = xaccTransGetSplitIndex(trans, split);
623  trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
624 
625  /* we should *always* find the split, but be paranoid */
626  if (split_index < 0)
627  {
628  gnc_resume_gui_refresh ();
629  LEAVE("no split");
630  return NULL;
631  }
632 
633  new_trans = xaccMallocTransaction (gnc_get_current_book ());
634 
635  xaccTransBeginEdit (new_trans);
636  gnc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
637  xaccTransSetDatePostedSecsNormalized (new_trans, date);
638  /* We also must set a new DateEntered on the new entry
639  * because otherwise the ordering is not deterministic */
640  xaccTransSetDateEnteredSecs(new_trans, gnc_time(NULL));
641 
642  /* set per book option */
643  gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
644  if (!reg->use_tran_num_for_num_field)
645  {
646  /* find split in new_trans that equals trans_split and set
647  * split_action to out_num */
648  gnc_set_num_action (NULL,
649  xaccTransGetSplit (new_trans, trans_split_index),
650  out_num, NULL);
651  /* note that if the transaction has multiple splits to the register
652  * account, only the anchor split will be set with user input. The
653  * user will have to adjust other splits manually. */
654  }
655  xaccTransCommitEdit (new_trans);
656 
657  num_cell = (NumCell *) gnc_table_layout_get_cell (reg->table->layout,
658  NUM_CELL);
659  if (gnc_num_cell_set_last_num (num_cell, out_num))
660  gnc_split_register_set_last_num (reg, out_num);
661 
662  g_free (out_num);
663  if (!reg->use_tran_num_for_num_field)
664  g_free (out_tnum);
665 
666  /* This shouldn't happen, but be paranoid. */
667  if (split_index >= xaccTransCountSplits (new_trans))
668  split_index = 0;
669 
670  return_split = xaccTransGetSplit (new_trans, split_index);
671  trans_split = xaccTransGetSplit (new_trans, trans_split_index);
672 
673  info->cursor_hint_trans = new_trans;
674  info->cursor_hint_split = return_split;
675  info->cursor_hint_trans_split = trans_split;
676  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
677 
678  info->trans_expanded = FALSE;
679  }
680 
681  /* Refresh the GUI. */
682  gnc_resume_gui_refresh ();
683 
684  LEAVE(" ");
685  return return_split;
686 }
687 
688 static void
689 gnc_split_register_copy_current_internal (SplitRegister *reg,
690  gboolean use_cut_semantics)
691 {
692  SRInfo *info = gnc_split_register_get_info(reg);
693  CursorClass cursor_class;
694  Transaction *trans;
695  Split *blank_split;
696  gboolean changed;
697  Split *split;
698  SCM new_item;
699 
700  g_return_if_fail(reg);
701  ENTER("reg=%p, use_cut_semantics=%s", reg,
702  use_cut_semantics ? "TRUE" : "FALSE");
703 
704  blank_split = xaccSplitLookup(&info->blank_split_guid,
705  gnc_get_current_book ());
708 
709  /* This shouldn't happen, but be paranoid. */
710  if (trans == NULL)
711  {
712  LEAVE("no trans");
713  return;
714  }
715 
716  cursor_class = gnc_split_register_get_current_cursor_class (reg);
717 
718  /* Can't do anything with this. */
719  if (cursor_class == CURSOR_CLASS_NONE)
720  {
721  LEAVE("no cursor class");
722  return;
723  }
724 
725  /* This shouldn't happen, but be paranoid. */
726  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
727  {
728  g_warning("BUG DETECTED: transaction cursor with no anchoring split!");
729  LEAVE("transaction cursor with no anchoring split");
730  return;
731  }
732 
733  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
734 
735  /* See if we were asked to copy an unchanged blank split. Don't. */
736  if (!changed && ((split == NULL) || (split == blank_split)))
737  {
738  /* We're either on an unedited, brand-new split or an unedited, brand-new
739  * transaction (the transaction anchored by the blank split.) */
740  /* FIXME: This doesn't work exactly right. When entering a new transaction,
741  * you can edit the description, move to a split row, then move
742  * back to the description, then ask for a copy, and this code will
743  * be reached. It forgets that you changed the row the first time
744  * you were there. -Charles */
745  LEAVE("nothing to copy/cut");
746  return;
747  }
748 
749  /* Ok, we are now ready to make the copy. */
750 
751  if (cursor_class == CURSOR_CLASS_SPLIT)
752  {
753  /* We are on a split in an expanded transaction. Just copy the split. */
754  new_item = gnc_copy_split(split, use_cut_semantics);
755 
756  if (new_item != SCM_UNDEFINED)
757  {
758  if (changed)
759  gnc_split_register_save_to_scm (reg, SCM_UNDEFINED, new_item,
760  use_cut_semantics);
761 
762  copied_leader_guid = *guid_null();
763  }
764  }
765  else
766  {
767  /* We are on a transaction row. Copy the whole transaction. */
768  new_item = gnc_copy_trans(trans, use_cut_semantics);
769 
770  if (new_item != SCM_UNDEFINED)
771  {
772  if (changed)
773  {
774  int split_index;
775  SCM split_scm;
776 
777  split_index = xaccTransGetSplitIndex(trans, split);
778  if (split_index >= 0)
779  split_scm = gnc_trans_scm_get_split_scm(new_item, split_index);
780  else
781  split_scm = SCM_UNDEFINED;
782 
783  gnc_split_register_save_to_scm (reg, new_item, split_scm,
784  use_cut_semantics);
785  }
786 
787  copied_leader_guid = info->default_account;
788  }
789  }
790 
791  if (new_item == SCM_UNDEFINED)
792  {
793  g_warning("BUG DETECTED: copy failed");
794  LEAVE("copy failed");
795  return;
796  }
797 
798  /* unprotect the old object, if any */
799  if (copied_item != SCM_UNDEFINED)
800  scm_gc_unprotect_object(copied_item);
801 
802  copied_item = new_item;
803  scm_gc_protect_object(copied_item);
804 
805  copied_class = cursor_class;
806  LEAVE("%s %s", use_cut_semantics ? "cut" : "copied",
807  cursor_class == CURSOR_CLASS_SPLIT ? "split" : "transaction");
808 }
809 
810 void
812 {
813  gnc_split_register_copy_current_internal (reg, FALSE);
814 }
815 
816 void
818 {
819  SRInfo *info = gnc_split_register_get_info (reg);
820  CursorClass cursor_class;
821  Transaction *trans;
822  Split *blank_split;
823  gboolean changed;
824  Split *split;
825 
826  blank_split = xaccSplitLookup (&info->blank_split_guid,
827  gnc_get_current_book ());
830 
831  /* This shouldn't happen, but be paranoid. */
832  if (trans == NULL)
833  return;
834 
835  cursor_class = gnc_split_register_get_current_cursor_class (reg);
836 
837  /* Can't do anything with this. */
838  if (cursor_class == CURSOR_CLASS_NONE)
839  return;
840 
841  /* This shouldn't happen, but be paranoid. */
842  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
843  return;
844 
845  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
846 
847  /* See if we were asked to cut an unchanged blank split. Don't. */
848  if (!changed && ((split == NULL) || (split == blank_split)))
849  return;
850 
851  gnc_split_register_copy_current_internal (reg, TRUE);
852 
853  if (cursor_class == CURSOR_CLASS_SPLIT)
855  else
857 }
858 
859 void
861 {
862  SRInfo *info = gnc_split_register_get_info(reg);
863  CursorClass cursor_class;
864  Transaction *trans;
865  Transaction *blank_trans;
866  Split *blank_split;
867  Split *trans_split;
868  Split *split;
869 
870  ENTER("reg=%p", reg);
871 
872  if (copied_class == CURSOR_CLASS_NONE)
873  {
874  LEAVE("no copied cursor class");
875  return;
876  }
877 
878  blank_split = xaccSplitLookup (&info->blank_split_guid,
879  gnc_get_current_book ());
880  blank_trans = xaccSplitGetParent (blank_split);
883 
884  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
885 
886  /* This shouldn't happen, but be paranoid. */
887  if (trans == NULL)
888  {
889  LEAVE("no transaction");
890  return;
891  }
892 
893  cursor_class = gnc_split_register_get_current_cursor_class (reg);
894 
895  /* Can't do anything with this. */
896  if (cursor_class == CURSOR_CLASS_NONE)
897  {
898  LEAVE("no current cursor class");
899  return;
900  }
901 
902  /* This shouldn't happen, but be paranoid. */
903  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
904  {
905  g_warning("BUG DETECTED: transaction cursor with no anchoring split!");
906  LEAVE("transaction cursor with no anchoring split");
907  return;
908  }
909 
910  if (cursor_class == CURSOR_CLASS_SPLIT)
911  {
912  const char *message = _("You are about to overwrite an existing split. "
913  "Are you sure you want to do that?");
914 
915  if (copied_class == CURSOR_CLASS_TRANS)
916  {
917  /* An entire transaction was copied, but we're just on a split. */
918  LEAVE("can't copy trans to split");
919  return;
920  }
921 
922  /* Ask before overwriting an existing split. */
923  if (split != NULL &&
924  !gnc_verify_dialog (gnc_split_register_get_parent (reg),
925  FALSE, "%s", message))
926  {
927  LEAVE("user cancelled");
928  return;
929  }
930 
931  gnc_suspend_gui_refresh ();
932 
933  if (split == NULL)
934  {
935  /* We are on a null split in an expanded transaction. */
936  split = xaccMallocSplit(gnc_get_current_book ());
937  xaccSplitSetParent(split, trans);
938  }
939 
940  gnc_copy_split_scm_onto_split(copied_item, split,
941  gnc_get_current_book ());
942  }
943  else
944  {
945  const char *message = _("You are about to overwrite an existing "
946  "transaction. "
947  "Are you sure you want to do that?");
948  Account * copied_leader;
949  const GncGUID *new_guid;
950  int trans_split_index;
951  int split_index;
952  int num_splits;
953 
954  if (copied_class == CURSOR_CLASS_SPLIT)
955  {
956  LEAVE("can't copy split to transaction");
957  return;
958  }
959 
960  /* Ask before overwriting an existing transaction. */
961  if (split != blank_split &&
962  !gnc_verify_dialog(gnc_split_register_get_parent(reg),
963  FALSE, "%s", message))
964  {
965  LEAVE("user cancelled");
966  return;
967  }
968 
969  /* Open the transaction for editing. */
970  if (gnc_split_register_begin_edit_or_warn(info, trans))
971  {
972  LEAVE("can't begin editing");
973  return;
974  }
975 
976  gnc_suspend_gui_refresh ();
977 
978  DEBUG("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
979  trans, split, blank_trans, blank_split);
980 
981  split_index = xaccTransGetSplitIndex(trans, split);
982  trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
983 
984  copied_leader = xaccAccountLookup(&copied_leader_guid,
985  gnc_get_current_book());
986  if (copied_leader && (gnc_split_register_get_default_account(reg) != NULL))
987  {
988  new_guid = &info->default_account;
989  gnc_copy_trans_scm_onto_trans_swap_accounts(copied_item, trans,
990  &copied_leader_guid,
991  new_guid, FALSE,
992  gnc_get_current_book ());
993  }
994  else
995  gnc_copy_trans_scm_onto_trans(copied_item, trans, FALSE,
996  gnc_get_current_book ());
997 
998  num_splits = xaccTransCountSplits(trans);
999  if (split_index >= num_splits)
1000  split_index = 0;
1001 
1002  if (trans == blank_trans)
1003  {
1004  /* In pasting, the blank split is deleted. Pick a new one. */
1005  blank_split = xaccTransGetSplit(trans, 0);
1006  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
1007  info->blank_split_edited = TRUE;
1008  info->auto_complete = FALSE;
1009  DEBUG("replacement blank_split=%p", blank_split);
1010 
1011  /* NOTE: At this point, the blank transaction virtual cell is still
1012  * anchored by the old, deleted blank split. The register will
1013  * have to be reloaded (redrawn) to correct this. */
1014  }
1015 
1016  info->cursor_hint_trans = trans;
1017  info->cursor_hint_split = xaccTransGetSplit(trans, split_index);
1018  info->cursor_hint_trans_split = xaccTransGetSplit(trans,
1019  trans_split_index);
1020  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
1021  }
1022 
1023  /* Refresh the GUI. */
1024  gnc_resume_gui_refresh ();
1025  LEAVE(" ");
1026 }
1027 
1028 void
1030 {
1031  SRInfo *info = gnc_split_register_get_info (reg);
1032  Transaction *pending_trans;
1033  Transaction *trans;
1034  Split *blank_split;
1035  Split *split;
1036 
1037  if (!reg) return;
1038 
1039  blank_split = xaccSplitLookup (&info->blank_split_guid,
1040  gnc_get_current_book ());
1041 
1042  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1043  gnc_get_current_book ());
1044 
1045  /* get the current split based on cursor position */
1047  if (split == NULL)
1048  return;
1049 
1050  /* If we are deleting the blank split, just cancel. The user is
1051  * allowed to delete the blank split as a method for discarding
1052  * any edits they may have made to it. */
1053  if (split == blank_split)
1054  {
1056  return;
1057  }
1058 
1059  gnc_suspend_gui_refresh ();
1060 
1061  trans = xaccSplitGetParent(split);
1062 
1063  /* Check pending transaction */
1064  if (trans == pending_trans)
1065  {
1066  g_assert(xaccTransIsOpen(trans));
1067  }
1068  else
1069  {
1070  g_assert(!pending_trans);
1071  if (gnc_split_register_begin_edit_or_warn(info, trans))
1072  {
1073  gnc_resume_gui_refresh ();
1074  return;
1075  }
1076  }
1077  xaccSplitDestroy (split);
1078 
1079  gnc_resume_gui_refresh ();
1081 }
1082 
1083 void
1085 {
1086  SRInfo *info = gnc_split_register_get_info (reg);
1087  Transaction *pending_trans;
1088  Transaction *trans;
1089  Split *blank_split;
1090  Split *split;
1091  gboolean was_open;
1092 
1093  ENTER("reg=%p", reg);
1094  if (!reg)
1095  {
1096  LEAVE("no register");
1097  return;
1098  }
1099 
1100  blank_split = xaccSplitLookup (&info->blank_split_guid,
1101  gnc_get_current_book ());
1102  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1103  gnc_get_current_book ());
1104 
1105  /* get the current split based on cursor position */
1107  if (split == NULL)
1108  {
1109  LEAVE("no split");
1110  return;
1111  }
1112 
1113  gnc_suspend_gui_refresh ();
1114  trans = xaccSplitGetParent(split);
1115 
1116  /* If we just deleted the blank split, clean up. The user is
1117  * allowed to delete the blank split as a method for discarding
1118  * any edits they may have made to it. */
1119  if (split == blank_split)
1120  {
1121  DEBUG("deleting blank split");
1122  info->blank_split_guid = *guid_null();
1123  info->auto_complete = FALSE;
1124  }
1125  else
1126  {
1127  info->trans_expanded = FALSE;
1128  }
1129 
1130  /* Check pending transaction */
1131  if (trans == pending_trans)
1132  {
1133  DEBUG("clearing pending trans");
1134  info->pending_trans_guid = *guid_null();
1135  pending_trans = NULL;
1136  }
1137 
1138  was_open = xaccTransIsOpen(trans);
1139  xaccTransDestroy(trans);
1140  if (was_open)
1141  {
1142  DEBUG("committing");
1143  xaccTransCommitEdit(trans);
1144  }
1145  gnc_resume_gui_refresh ();
1146  LEAVE(" ");
1147 }
1148 
1149 void
1151 {
1152  SRInfo *info = gnc_split_register_get_info (reg);
1153  Transaction *pending_trans;
1154  Transaction *trans;
1155  Split *blank_split;
1156  Split *split;
1157 
1158  if (!reg) return;
1159 
1160  blank_split = xaccSplitLookup (&info->blank_split_guid,
1161  gnc_get_current_book ());
1162  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1163  gnc_get_current_book ());
1164 
1165  /* get the current split based on cursor position */
1167  if (split == NULL)
1168  return;
1169 
1170  /* Bail if trying to void the blank split. */
1171  if (split == blank_split)
1172  return;
1173 
1174  /* already voided. */
1175  if (xaccSplitGetReconcile (split) == VREC)
1176  return;
1177 
1178  info->trans_expanded = FALSE;
1179 
1180  gnc_suspend_gui_refresh ();
1181 
1182  trans = xaccSplitGetParent(split);
1183  xaccTransVoid(trans, reason);
1184 
1185  /* Check pending transaction */
1186  if (trans == pending_trans)
1187  {
1188  info->pending_trans_guid = *guid_null();
1189  pending_trans = NULL;
1190  }
1191  if (xaccTransIsOpen(trans))
1192  {
1193  PERR("We should not be voiding an open transaction.");
1194  xaccTransCommitEdit(trans);
1195  }
1196  gnc_resume_gui_refresh ();
1197 }
1198 
1199 void
1201 {
1202  SRInfo *info = gnc_split_register_get_info (reg);
1203  Transaction *pending_trans;
1204  Transaction *trans;
1205  Split *blank_split;
1206  Split *split;
1207 
1208  if (!reg) return;
1209 
1210  blank_split = xaccSplitLookup (&info->blank_split_guid,
1211  gnc_get_current_book ());
1212  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1213  gnc_get_current_book ());
1214 
1215  /* get the current split based on cursor position */
1217  if (split == NULL)
1218  return;
1219 
1220  /* Bail if trying to unvoid the blank split. */
1221  if (split == blank_split)
1222  return;
1223 
1224  /* not voided. */
1225  if (xaccSplitGetReconcile (split) != VREC)
1226  return;
1227 
1228  info->trans_expanded = FALSE;
1229 
1230  gnc_suspend_gui_refresh ();
1231 
1232  trans = xaccSplitGetParent(split);
1233 
1234  xaccTransUnvoid(trans);
1235 
1236  /* Check pending transaction */
1237  if (trans == pending_trans)
1238  {
1239  info->pending_trans_guid = *guid_null();
1240  pending_trans = NULL;
1241  }
1242 
1243  gnc_resume_gui_refresh ();
1244 }
1245 
1246 void
1248  Split *split)
1249 {
1250  SRInfo *info;
1251  Transaction *trans;
1252  Transaction *pending;
1253  int i = 0;
1254  Split *s;
1255 
1256  if ((reg == NULL) || (split == NULL))
1257  return;
1258 
1259  gnc_suspend_gui_refresh ();
1260  info = gnc_split_register_get_info(reg);
1261  pending = xaccTransLookup(&info->pending_trans_guid, gnc_get_current_book());
1262 
1263  trans = xaccSplitGetParent(split);
1264  if (!pending)
1265  {
1266  if (gnc_split_register_begin_edit_or_warn(info, trans))
1267  {
1268  gnc_resume_gui_refresh ();
1269  return;
1270  }
1271  }
1272  else if (pending == trans)
1273  {
1274  g_assert(xaccTransIsOpen(trans));
1275  }
1276  else g_assert_not_reached();
1277 
1278  while ((s = xaccTransGetSplit(trans, i)) != NULL)
1279  {
1280  if (s != split)
1281  xaccSplitDestroy(s);
1282  else i++;
1283  }
1284 
1285  gnc_resume_gui_refresh ();
1287 }
1288 
1289 void
1290 gnc_split_register_empty_current_trans (SplitRegister *reg)
1291 {
1292  Split *split;
1293 
1294  /* get the current split based on cursor position */
1297 }
1298 
1299 void
1301 {
1302  VirtualLocation virt_loc;
1303 
1304  if (reg == NULL)
1305  return;
1306 
1307  virt_loc = reg->table->current_cursor_loc;
1308 
1309  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1310  return;
1311 
1312  /* We're just cancelling the current split here, not the transaction.
1313  * When cancelling edits, reload the cursor from the transaction. */
1314  gnc_table_clear_current_cursor_changes (reg->table);
1315 
1316  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1317  gnc_table_move_cursor_gui (reg->table, virt_loc);
1318 
1319  gnc_table_refresh_gui (reg->table, TRUE);
1320 }
1321 
1322 void
1324 {
1325  SRInfo *info = gnc_split_register_get_info (reg);
1326  Transaction *pending_trans;
1327 
1328  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1329  gnc_get_current_book ());
1330 
1331  /* Get the currently open transaction, rollback the edits on it, and
1332  * then repaint everything. To repaint everything, make a note of
1333  * all of the accounts that will be affected by this rollback. */
1334  if (!xaccTransIsOpen (pending_trans))
1335  {
1337  return;
1338  }
1339 
1340  if (!pending_trans)
1341  return;
1342 
1343  gnc_suspend_gui_refresh ();
1344 
1345  xaccTransRollbackEdit (pending_trans);
1346 
1347  info->pending_trans_guid = *guid_null ();
1348 
1349  gnc_resume_gui_refresh ();
1351 }
1352 
1353 void
1355 {
1356  gnc_ledger_display_refresh_by_split_register (reg);
1357 }
1358 
1359 /* Copy from the register object to scheme. This needs to be
1360  * in sync with gnc_split_register_save and xaccSRSaveChangedCells. */
1361 static gboolean
1362 gnc_split_register_save_to_scm (SplitRegister *reg,
1363  SCM trans_scm, SCM split_scm,
1364  gboolean use_cut_semantics)
1365 {
1366  SCM other_split_scm = SCM_UNDEFINED;
1367  Transaction *trans;
1368 
1369  /* use the changed flag to avoid heavy-weight updates
1370  * of the split & transaction fields. This will help
1371  * cut down on uneccessary register redraws. */
1372  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1373  return FALSE;
1374 
1375  /* get the handle to the current split and transaction */
1377  if (trans == NULL)
1378  return FALSE;
1379 
1380  /* copy the contents from the cursor to the split */
1381  if (gnc_table_layout_get_cell_changed (reg->table->layout, DATE_CELL, TRUE))
1382  {
1383  BasicCell *cell;
1384  Timespec ts;
1385 
1386  cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
1387  gnc_date_cell_get_date ((DateCell *) cell, &ts);
1388 
1389  gnc_trans_scm_set_date(trans_scm, &ts);
1390  }
1391 
1392  if (gnc_table_layout_get_cell_changed (reg->table->layout, NUM_CELL, TRUE))
1393  {
1394  const char *value;
1395 
1396  value = gnc_table_layout_get_cell_value (reg->table->layout, NUM_CELL);
1397  if (reg->use_tran_num_for_num_field)
1398  gnc_trans_scm_set_num (trans_scm, value);
1399  /* else this contains the same as ACTN_CELL which is already handled below *
1400  * and the TNUM_CELL contains transaction number which is handled in next *
1401  * if statement. */
1402  }
1403 
1404  if (gnc_table_layout_get_cell_changed (reg->table->layout, TNUM_CELL, TRUE))
1405  {
1406  const char *value;
1407 
1408  value = gnc_table_layout_get_cell_value (reg->table->layout, TNUM_CELL);
1409  if (!reg->use_tran_num_for_num_field)
1410  gnc_trans_scm_set_num (trans_scm, value);
1411  /* else this cell is not used */
1412  }
1413 
1414  if (gnc_table_layout_get_cell_changed (reg->table->layout, DESC_CELL, TRUE))
1415  {
1416  const char *value;
1417 
1418  value = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
1419  gnc_trans_scm_set_description (trans_scm, value);
1420  }
1421 
1422  if (gnc_table_layout_get_cell_changed (reg->table->layout, NOTES_CELL, TRUE))
1423  {
1424  const char *value;
1425 
1426  value = gnc_table_layout_get_cell_value (reg->table->layout, NOTES_CELL);
1427  gnc_trans_scm_set_notes (trans_scm, value);
1428  }
1429 
1430  if (gnc_table_layout_get_cell_changed (reg->table->layout, RECN_CELL, TRUE))
1431  {
1432  BasicCell *cell;
1433  char flag;
1434 
1435  cell = gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
1436  flag = gnc_recn_cell_get_flag ((RecnCell *) cell);
1437 
1438  gnc_split_scm_set_reconcile_state(split_scm, flag);
1439  }
1440 
1441  if (gnc_table_layout_get_cell_changed (reg->table->layout, ACTN_CELL, TRUE))
1442  {
1443  const char *value;
1444 
1445  value = gnc_table_layout_get_cell_value (reg->table->layout, ACTN_CELL);
1446  gnc_split_scm_set_action (split_scm, value);
1447  }
1448 
1449  if (gnc_table_layout_get_cell_changed (reg->table->layout, MEMO_CELL, TRUE))
1450  {
1451  const char *value;
1452 
1453  value = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
1454  gnc_split_scm_set_memo (split_scm, value);
1455  }
1456 
1457  if (gnc_table_layout_get_cell_changed (reg->table->layout, XFRM_CELL, TRUE))
1458  {
1459  Account *new_account;
1460 
1461  new_account = gnc_split_register_get_account (reg, XFRM_CELL);
1462 
1463  if (new_account != NULL)
1464  gnc_split_scm_set_account (split_scm, new_account);
1465  }
1466 
1467  if (reg->style == REG_STYLE_LEDGER)
1468  other_split_scm = gnc_trans_scm_get_other_split_scm (trans_scm, split_scm);
1469 
1470  if (gnc_table_layout_get_cell_changed (reg->table->layout, MXFRM_CELL, TRUE))
1471  {
1472  other_split_scm = gnc_trans_scm_get_other_split_scm (trans_scm, split_scm);
1473 
1474  if (other_split_scm == SCM_UNDEFINED)
1475  {
1476  if (gnc_trans_scm_get_num_splits(trans_scm) == 1)
1477  {
1478  Split *temp_split;
1479 
1480  temp_split = xaccMallocSplit (gnc_get_current_book ());
1481  other_split_scm = gnc_copy_split (temp_split, use_cut_semantics);
1482  xaccSplitDestroy (temp_split);
1483 
1484  gnc_trans_scm_append_split_scm (trans_scm, other_split_scm);
1485  }
1486  }
1487 
1488  if (other_split_scm != SCM_UNDEFINED)
1489  {
1490  Account *new_account;
1491 
1492  new_account = gnc_split_register_get_account (reg, MXFRM_CELL);
1493 
1494  if (new_account != NULL)
1495  gnc_split_scm_set_account (other_split_scm, new_account);
1496  }
1497  }
1498 
1499  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1500  DEBT_CELL, TRUE) ||
1501  gnc_table_layout_get_cell_changed (reg->table->layout,
1502  CRED_CELL, TRUE))
1503  {
1504  BasicCell *cell;
1505  gnc_numeric new_value;
1506  gnc_numeric credit;
1507  gnc_numeric debit;
1508 
1509  cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
1510  credit = gnc_price_cell_get_value ((PriceCell *) cell);
1511 
1512  cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
1513  debit = gnc_price_cell_get_value ((PriceCell *) cell);
1514 
1515  new_value = gnc_numeric_sub_fixed (debit, credit);
1516 
1517  gnc_split_scm_set_value (split_scm, new_value);
1518  }
1519 
1520  if (gnc_table_layout_get_cell_changed (reg->table->layout, PRIC_CELL, TRUE))
1521  {
1522  /* do nothing for now */
1523  }
1524 
1525  if (gnc_table_layout_get_cell_changed (reg->table->layout, SHRS_CELL, TRUE))
1526  {
1527  BasicCell *cell;
1528  gnc_numeric shares;
1529 
1530  cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1531 
1532  shares = gnc_price_cell_get_value ((PriceCell *) cell);
1533 
1534  gnc_split_scm_set_amount (split_scm, shares);
1535  }
1536 
1537  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1538  DEBT_CELL, TRUE) ||
1539  gnc_table_layout_get_cell_changed (reg->table->layout,
1540  CRED_CELL, TRUE) ||
1541  gnc_table_layout_get_cell_changed (reg->table->layout,
1542  PRIC_CELL, TRUE) ||
1543  gnc_table_layout_get_cell_changed (reg->table->layout,
1544  SHRS_CELL, TRUE))
1545  {
1546  if (other_split_scm != SCM_UNDEFINED)
1547  {
1548  gnc_numeric num;
1549 
1550  num = gnc_split_scm_get_amount (split_scm);
1551  gnc_split_scm_set_amount (other_split_scm, gnc_numeric_neg (num));
1552 
1553  num = gnc_split_scm_get_value (split_scm);
1554  gnc_split_scm_set_value (other_split_scm, gnc_numeric_neg (num));
1555  }
1556  }
1557 
1558  return TRUE;
1559 }
1560 
1561 gboolean
1562 gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
1563 {
1564  SRInfo *info = gnc_split_register_get_info (reg);
1565  Transaction *pending_trans;
1566  Transaction *blank_trans;
1567  Transaction *trans;
1568  Account *account;
1569  Split *blank_split;
1570  const char *memo;
1571  const char *desc;
1572  Split *split;
1573 
1574  ENTER("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
1575 
1576  if (!reg)
1577  {
1578  LEAVE("no register");
1579  return FALSE;
1580  }
1581 
1582  blank_split = xaccSplitLookup (&info->blank_split_guid,
1583  gnc_get_current_book ());
1584 
1585  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1586  gnc_get_current_book ());
1587 
1588  blank_trans = xaccSplitGetParent (blank_split);
1589 
1590  /* get the handle to the current split and transaction */
1593  if (trans == NULL)
1594  {
1595  LEAVE("no transaction");
1596  return FALSE;
1597  }
1598 
1599  /* use the changed flag to avoid heavy-weight updates
1600  * of the split & transaction fields. This will help
1601  * cut down on unnecessary register redraws. */
1602  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1603  {
1604  if (!do_commit)
1605  {
1606  LEAVE("commit unnecessary");
1607  return FALSE;
1608  }
1609 
1610  if (!xaccTransIsOpen(trans))
1611  {
1612  LEAVE("transaction not open");
1613  return FALSE;
1614  }
1615 
1616  if (trans == pending_trans ||
1617  (trans == blank_trans && info->blank_split_edited))
1618  {
1619  /* We are going to commit. */
1620 
1621  gnc_suspend_gui_refresh ();
1622 
1623  if (trans == blank_trans)
1624  {
1625  /* We have to clear the blank split before the
1626  * refresh or a new one won't be created. */
1627  info->last_date_entered = xaccTransGetDate (trans);
1628  info->blank_split_guid = *guid_null ();
1629  info->blank_split_edited = FALSE;
1630  info->auto_complete = FALSE;
1631  }
1632 
1633  /* We have to clear the pending guid *before* committing the
1634  * trans, because the event handler will find it otherwise. */
1635  if (trans == pending_trans)
1636  info->pending_trans_guid = *guid_null ();
1637 
1638  PINFO("committing trans (%p)", trans);
1639  xaccTransCommitEdit(trans);
1640 
1641  gnc_resume_gui_refresh ();
1642  }
1643  else
1644  DEBUG("leaving trans (%p) open", trans);
1645 
1646  LEAVE("unchanged cursor");
1647  return TRUE;
1648  }
1649 
1650  DEBUG("save split=%p", split);
1651  DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
1652  blank_split, blank_trans, pending_trans, trans);
1653 
1654  /* Act on any changes to the current cell before the save. */
1655  (void) gnc_split_register_check_cell (reg,
1656  gnc_table_get_current_cell_name (reg->table));
1657 
1658  if (!gnc_split_register_auto_calc (reg, split))
1659  {
1660  LEAVE("auto calc failed");
1661  return FALSE;
1662  }
1663 
1664  /* Validate the transfer account names */
1665  (void)gnc_split_register_get_account (reg, MXFRM_CELL);
1666  (void)gnc_split_register_get_account (reg, XFRM_CELL);
1667 
1668  /* Maybe deal with exchange-rate transfers */
1669  if (gnc_split_register_handle_exchange (reg, FALSE))
1670  {
1671  LEAVE("no exchange rate");
1672  return TRUE;
1673  }
1674 
1675  gnc_suspend_gui_refresh ();
1676 
1677  /* determine whether we should commit the pending transaction */
1678  if (pending_trans != trans)
1679  {
1680  // FIXME: How could the pending transaction not be open?
1681  // FIXME: For that matter, how could an open pending
1682  // transaction ever not be the current trans?
1683  if (xaccTransIsOpen (pending_trans))
1684  {
1685  g_warning("Impossible? commiting pending %p", pending_trans);
1686  xaccTransCommitEdit (pending_trans);
1687  }
1688  else if (pending_trans)
1689  {
1690  g_critical("BUG DETECTED! pending transaction (%p) not open",
1691  pending_trans);
1692  g_assert_not_reached();
1693  }
1694 
1695  if (trans == blank_trans)
1696  {
1697  /* Don't begin editing the blank trans, because it's
1698  already open, but mark it pending now. */
1699  g_assert(xaccTransIsOpen(blank_trans));
1700  /* This is now the pending transaction */
1701  info->pending_trans_guid = *xaccTransGetGUID(blank_trans);
1702  }
1703  else
1704  {
1705  PINFO("beginning edit of trans %p", trans);
1706  if (gnc_split_register_begin_edit_or_warn(info, trans))
1707  {
1708  gnc_resume_gui_refresh ();
1709  LEAVE("transaction opened elsewhere");
1710  return FALSE;
1711  }
1712  }
1713  pending_trans = trans;
1714  }
1715  g_assert(xaccTransIsOpen(trans));
1716 
1717  /* If we are saving a brand new transaction and the blank split hasn't
1718  * been edited, then we need to give it a default account. */
1719  /* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
1720  * even better? What if there were some way that we could be on
1721  * a row other than the transaction row or blank split row, but
1722  * the blank split still hasn't been edited? It seems to be assumed
1723  * that it isn't possible, but... -Charles, Jan 2009 */
1724  if (split == blank_split && !info->blank_split_edited)
1725  {
1726  /* If we've reached this point, it means that the blank split is
1727  * anchoring the transaction - see gnc_split_register_add_transaction()
1728  * for an explanation - and the transaction has been edited (as evidenced
1729  * by the earlier check for a changed cursor.) Since the blank split
1730  * itself has not been edited, we'll have to assign a default account. */
1731  account = gnc_split_register_get_default_account(reg);
1732  if (account)
1733  xaccSplitSetAccount(blank_split, account);
1734  xaccTransSetDateEnteredSecs(trans, gnc_time (NULL));
1735  }
1736 
1737  if (split == NULL)
1738  {
1739  /* If we were asked to save data for a row for which there is no
1740  * associated split, then assume that this was an "empty" row - see
1741  * gnc_split_register_add_transaction() for an explanation. This row
1742  * is used to add splits to an existing transaction, or to add the
1743  * 2nd through nth split rows to a brand new transaction.
1744  * xaccSRGetCurrent will handle this case, too. We will create
1745  * a new split, copy the row contents to that split, and append
1746  * the split to the pre-existing transaction. */
1747  Split *trans_split;
1748 
1749  split = xaccMallocSplit (gnc_get_current_book ());
1750  xaccTransAppendSplit (trans, split);
1751 
1752  gnc_table_set_virt_cell_data (reg->table,
1753  reg->table->current_cursor_loc.vcell_loc,
1754  xaccSplitGetGUID (split));
1755  DEBUG("assigned cell to new split=%p", split);
1756 
1757  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
1758  if ((info->cursor_hint_trans == trans) &&
1759  (info->cursor_hint_trans_split == trans_split) &&
1760  (info->cursor_hint_split == NULL))
1761  {
1762  info->cursor_hint_split = split;
1763  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1764  }
1765  }
1766 
1767  DEBUG("updating trans=%p", trans);
1768 
1769  {
1770  SRSaveData *sd;
1771 
1772  sd = gnc_split_register_save_data_new (
1773  trans, split, (info->trans_expanded ||
1774  reg->style == REG_STYLE_AUTO_LEDGER ||
1775  reg->style == REG_STYLE_JOURNAL));
1776  gnc_table_save_cells (reg->table, sd);
1777  gnc_split_register_save_data_destroy (sd);
1778  }
1779 
1780  memo = xaccSplitGetMemo (split);
1781  memo = memo ? memo : "(null)";
1782  desc = xaccTransGetDescription (trans);
1783  desc = desc ? desc : "(null)";
1784  PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
1785 
1786  /* If the modified split is the "blank split", then it is now an
1787  * official part of the account. Set the blank split to NULL, so we
1788  * can be sure of getting a new blank split. Also, save the date
1789  * for the new blank split. */
1790  if (trans == blank_trans)
1791  {
1792  if (do_commit)
1793  {
1794  info->blank_split_guid = *guid_null ();
1795  info->auto_complete = FALSE;
1796  blank_split = NULL;
1797  info->last_date_entered = xaccTransGetDate (trans);
1798  }
1799  else
1800  info->blank_split_edited = TRUE;
1801  }
1802 
1803  /* If requested, commit the current transaction and set the pending
1804  * transaction to NULL. */
1805  if (do_commit)
1806  {
1807  g_assert(trans == blank_trans || trans == pending_trans);
1808  if (pending_trans == trans)
1809  {
1810  pending_trans = NULL;
1811  info->pending_trans_guid = *guid_null ();
1812  }
1813  xaccTransCommitEdit (trans);
1814  }
1815 
1816  gnc_table_clear_current_cursor_changes (reg->table);
1817 
1818  gnc_resume_gui_refresh ();
1819 
1820  LEAVE(" ");
1821  return TRUE;
1822 }
1823 
1824 
1825 Account *
1826 gnc_split_register_get_account_by_name (SplitRegister *reg, BasicCell * bcell,
1827  const char *name)
1828 {
1829  const char *placeholder = _("The account %s does not allow transactions.");
1830  const char *missing = _("The account %s does not exist. "
1831  "Would you like to create it?");
1832  char *account_name;
1833  ComboCell *cell = (ComboCell *) bcell;
1834  Account *account;
1835 
1836  if (!name || (strlen(name) == 0))
1837  return NULL;
1838 
1839  /* Find the account */
1840  account = gnc_account_lookup_for_register (gnc_get_current_root_account (), name);
1841  if (!account)
1842  account = gnc_account_lookup_by_code(gnc_get_current_root_account(), name);
1843 
1844  if (!account)
1845  {
1846  /* Ask if they want to create a new one. */
1847  if (!gnc_verify_dialog (gnc_split_register_get_parent (reg),
1848  TRUE, missing, name))
1849  return NULL;
1850 
1851  /* User said yes, they want to create a new account. */
1852  account = gnc_ui_new_accounts_from_name_window (name);
1853  if (!account)
1854  return NULL;
1855  }
1856 
1857  /* Now have the account. */
1858  account_name = gnc_get_account_name_for_register (account);
1859  if (g_strcmp0(account_name, gnc_basic_cell_get_value(bcell)))
1860  {
1861  /* The name has changed. Update the cell. */
1862  gnc_combo_cell_set_value (cell, account_name);
1863  gnc_basic_cell_set_changed (&cell->cell, TRUE);
1864  }
1865  g_free (account_name);
1866 
1867  /* See if the account (either old or new) is a placeholder. */
1868  if (xaccAccountGetPlaceholder (account))
1869  {
1870  gnc_error_dialog (gnc_split_register_get_parent (reg),
1871  placeholder, name);
1872  }
1873 
1874  /* Be seeing you. */
1875  return account;
1876 }
1877 
1878 Account *
1879 gnc_split_register_get_account (SplitRegister *reg, const char * cell_name)
1880 {
1881  BasicCell *cell;
1882  const char *name;
1883 
1884  if (!gnc_table_layout_get_cell_changed (reg->table->layout, cell_name, TRUE))
1885  return NULL;
1886 
1887  cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
1888  if (!cell)
1889  return NULL;
1890  name = gnc_basic_cell_get_value (cell);
1891  return gnc_split_register_get_account_by_name (reg, cell, name);
1892 }
1893 
1894 static gnc_numeric
1895 calculate_value (SplitRegister *reg)
1896 {
1897  gnc_numeric credit;
1898  gnc_numeric debit;
1899 
1900  PriceCell *cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
1901  CRED_CELL);
1902  credit = gnc_price_cell_get_value (cell);
1903 
1904  cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
1905  DEBT_CELL);
1906  debit = gnc_price_cell_get_value (cell);
1907 
1908  return gnc_numeric_sub_fixed (debit, credit);
1909 }
1910 
1911 
1912 static int
1913 recalc_message_box (SplitRegister *reg, gboolean shares_changed,
1914  gboolean price_changed, gboolean value_changed)
1915 {
1916  int choice;
1917  int default_value;
1918  GList *node;
1919  GList *radio_list = NULL;
1920  const char *title = _("Recalculate Transaction");
1921  const char *message = _("The values entered for this transaction "
1922  "are inconsistent. Which value would you "
1923  "like to have recalculated?");
1924 
1925  if (shares_changed)
1926  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
1927  _("_Shares"),
1928  _("Changed")));
1929  else
1930  radio_list = g_list_append (radio_list, g_strdup (_("_Shares")));
1931 
1932  if (price_changed)
1933  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
1934  _("_Price"),
1935  _("Changed")));
1936  else
1937  radio_list = g_list_append (radio_list, g_strdup (_("_Price")));
1938 
1939  if (value_changed)
1940  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
1941  _("_Value"),
1942  _("Changed")));
1943  else
1944  radio_list = g_list_append (radio_list, g_strdup (_("_Value")));
1945 
1946  if (price_changed) default_value = 2; /* change the value */
1947  else default_value = 1; /* change the value */
1948 
1949  choice = gnc_choose_radio_option_dialog
1950  (gnc_split_register_get_parent (reg),
1951  title,
1952  message,
1953  _("_Recalculate"),
1954  default_value,
1955  radio_list);
1956 
1957  for (node = radio_list; node; node = node->next)
1958  g_free (node->data);
1959 
1960  g_list_free (radio_list);
1961 
1962  return choice;
1963 }
1964 
1965 static void
1966 recalculate_shares (Split* split, SplitRegister *reg,
1967  gnc_numeric value, gnc_numeric price, gboolean value_changed)
1968 {
1969  gint64 denom = gnc_split_get_amount_denom (split);
1970  gnc_numeric amount = gnc_numeric_div (value, price, denom,
1972 
1973  BasicCell *cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1974  gnc_price_cell_set_value ((PriceCell *) cell, amount);
1975  gnc_basic_cell_set_changed (cell, TRUE);
1976 
1977  if (value_changed)
1978  {
1979  cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
1980  gnc_basic_cell_set_changed (cell, FALSE);
1981  }
1982 }
1983 
1984 static void
1985 recalculate_price (Split *split, SplitRegister *reg,
1986  gnc_numeric value, gnc_numeric amount)
1987 {
1988  BasicCell *price_cell;
1989  gnc_numeric price = gnc_numeric_div (value, amount,
1992 
1993  if (gnc_numeric_negative_p (price))
1994  {
1995  BasicCell *debit_cell;
1996  BasicCell *credit_cell;
1997 
1998  debit_cell = gnc_table_layout_get_cell (reg->table->layout,
1999  DEBT_CELL);
2000 
2001  credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2002  CRED_CELL);
2003 
2004  price = gnc_numeric_neg (price);
2005 
2006  gnc_price_cell_set_debt_credit_value ((PriceCell *) debit_cell,
2007  (PriceCell *) credit_cell,
2008  gnc_numeric_neg (value));
2009 
2010  gnc_basic_cell_set_changed (debit_cell, TRUE);
2011  gnc_basic_cell_set_changed (credit_cell, TRUE);
2012  }
2013 
2014  price_cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
2015  gnc_price_cell_set_value ((PriceCell *) price_cell, price);
2016  gnc_basic_cell_set_changed (price_cell, TRUE);
2017 }
2018 
2019 static void
2020 recalculate_value (Split *split, SplitRegister *reg,
2021  gnc_numeric price, gnc_numeric amount, gboolean shares_changed)
2022 {
2023  BasicCell *debit_cell = gnc_table_layout_get_cell (reg->table->layout,
2024  DEBT_CELL);
2025  BasicCell *credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2026  CRED_CELL);
2027  gint64 denom = gnc_split_get_value_denom (split);
2028  gnc_numeric value = gnc_numeric_mul (price, amount, denom,
2030 
2031  gnc_price_cell_set_debt_credit_value ((PriceCell *) debit_cell,
2032  (PriceCell *) credit_cell, value);
2033 
2034  gnc_basic_cell_set_changed (debit_cell, TRUE);
2035  gnc_basic_cell_set_changed (credit_cell, TRUE);
2036 
2037  if (shares_changed)
2038  {
2039  BasicCell *cell = gnc_table_layout_get_cell (reg->table->layout,
2040  PRIC_CELL);
2041  gnc_basic_cell_set_changed (cell, FALSE);
2042  }
2043 }
2044 
2045 static void
2046 record_price (SplitRegister *reg, Account *account, gnc_numeric value)
2047 {
2049  QofBook *book = qof_instance_get_book (QOF_INSTANCE (account));
2050  GNCPriceDB *pricedb = gnc_pricedb_get_db (book);
2051  gnc_commodity *comm = xaccAccountGetCommodity (account);
2052  gnc_commodity *curr = xaccTransGetCurrency (trans);
2053  GNCPrice *price;
2054  Timespec ts;
2055  BasicCell *cell;
2056 
2057  /* Only record the price for account types that don't have a
2058  * "rate" cell. They'll get handled later by
2059  * gnc_split_register_handle_exchange.
2060  */
2061  if (gnc_split_reg_has_rate_cell (reg->type))
2062  return;
2063  cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
2064  gnc_date_cell_get_date ((DateCell*)cell, &ts);
2065  price = gnc_price_create (book);
2066  gnc_price_begin_edit (price);
2067  gnc_price_set_commodity (price, comm);
2068  gnc_price_set_currency (price, curr);
2069  gnc_price_set_time (price, ts);
2070  gnc_price_set_source (price, "user:split-register");
2071  gnc_price_set_value (price, value);
2072  gnc_pricedb_add_price (pricedb, price);
2073  gnc_price_commit_edit (price);
2074 }
2075 
2076 static gboolean
2077 gnc_split_register_auto_calc (SplitRegister *reg, Split *split)
2078 {
2079  PriceCell *cell = NULL;
2080  gboolean recalc_shares = FALSE;
2081  gboolean recalc_price = FALSE;
2082  gboolean recalc_value = FALSE;
2083  gboolean price_changed;
2084  gboolean value_changed;
2085  gboolean shares_changed;
2086  gnc_numeric calc_value;
2087  gnc_numeric value;
2088  gnc_numeric price;
2089  gnc_numeric amount;
2090  Account *account;
2091  int denom;
2092  int choice;
2093 
2094  if (STOCK_REGISTER != reg->type &&
2095  CURRENCY_REGISTER != reg->type &&
2096  PORTFOLIO_LEDGER != reg->type)
2097  return TRUE;
2098 
2099  account = gnc_split_register_get_account (reg, XFRM_CELL);
2100 
2101  if (!account)
2102  account = xaccSplitGetAccount (split);
2103 
2104  if (!account)
2105  account = gnc_split_register_get_default_account (reg);
2106 
2107  if (!xaccAccountIsPriced(account))
2108  return TRUE;
2109 
2110  price_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2111  PRIC_CELL, TRUE);
2112  value_changed = (gnc_table_layout_get_cell_changed (reg->table->layout,
2113  DEBT_CELL, TRUE) ||
2114  gnc_table_layout_get_cell_changed (reg->table->layout,
2115  CRED_CELL, TRUE));
2116  shares_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2117  SHRS_CELL, TRUE);
2118 
2119  if (!price_changed && !value_changed && !shares_changed)
2120  return TRUE;
2121 
2122  /* If we are using commodity trading accounts then the value may
2123  not really be the value. Punt if so. */
2125  {
2126  gnc_commodity *acc_commodity;
2127  acc_commodity = xaccAccountGetCommodity (account);
2128  if (! (xaccAccountIsPriced (account) ||
2129  !gnc_commodity_is_iso (acc_commodity)))
2130  return TRUE;
2131  }
2132 
2133  if (shares_changed)
2134  {
2135  cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
2136  SHRS_CELL);
2137  amount = gnc_price_cell_get_value (cell);
2138  }
2139  else
2140  amount = xaccSplitGetAmount (split);
2141 
2142  if (price_changed)
2143  {
2144  cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
2145  PRIC_CELL);
2146  price = gnc_price_cell_get_value (cell);
2147  }
2148  else
2149  price = xaccSplitGetSharePrice (split);
2150 
2151  if (value_changed)
2152  value = calculate_value (reg);
2153  else
2154  value = xaccSplitGetValue (split);
2155 
2156 
2157  /* Check if shares and price are BOTH zero (and value is non-zero).
2158  * If so, we can assume that this is an income-correcting split
2159  */
2160  if (gnc_numeric_zero_p(amount) && gnc_numeric_zero_p(price) &&
2161  !gnc_numeric_zero_p(value))
2162  {
2163  return TRUE;
2164  }
2165 
2166  /* Check if precisely one value is zero. If so, we can assume that the
2167  * zero value needs to be recalculated. */
2168 
2169  if (!gnc_numeric_zero_p (amount))
2170  {
2171  if (gnc_numeric_zero_p (price))
2172  {
2173  if (!gnc_numeric_zero_p (value))
2174  recalc_price = TRUE;
2175  }
2176  else if (gnc_numeric_zero_p (value))
2177  recalc_value = TRUE;
2178  }
2179  else if (!gnc_numeric_zero_p (price))
2180  if (!gnc_numeric_zero_p (value))
2181  recalc_shares = TRUE;
2182 
2183  /* If we have not already flagged a recalc, check if this is a split
2184  * which has 2 of the 3 values changed. */
2185 
2186  if ((!recalc_shares) &&
2187  (!recalc_price) &&
2188  (!recalc_value))
2189  {
2190  if (price_changed && value_changed)
2191  {
2192  if (!shares_changed)
2193  recalc_shares = TRUE;
2194  }
2195  else if (value_changed && shares_changed)
2196  recalc_price = TRUE;
2197  else if (price_changed && shares_changed)
2198  recalc_value = TRUE;
2199  }
2200 
2201  calc_value = gnc_numeric_mul (price, amount,
2203 
2204  denom = gnc_split_get_value_denom (split);
2205 
2206  /* Now, if we have not flagged one of the recalcs, and value and
2207  * calc_value are not the same number, then we need to ask for
2208  * help from the user. */
2209 
2210  if (!recalc_shares &&
2211  !recalc_price &&
2212  !recalc_value &&
2213  !gnc_numeric_same (value, calc_value, denom, GNC_HOW_RND_ROUND_HALF_UP))
2214  {
2215  choice = recalc_message_box(reg, shares_changed,
2216  price_changed,
2217  value_changed);
2218  switch (choice)
2219  {
2220  case 0: /* Modify number of shares */
2221  recalc_shares = TRUE;
2222  break;
2223  case 1: /* Modify the share price */
2224  recalc_price = TRUE;
2225  break;
2226  case 2: /* Modify total value */
2227  recalc_value = TRUE;
2228  break;
2229  default: /* Cancel */
2230  return FALSE;
2231  }
2232  }
2233 
2234  if (recalc_shares && !gnc_numeric_zero_p (price))
2235  recalculate_shares (split, reg, value, price, value_changed);
2236 
2237  if (recalc_price && !gnc_numeric_zero_p (amount))
2238  {
2239  recalculate_price (split, reg, value, amount);
2240  price_changed = TRUE;
2241  }
2242  if (recalc_value)
2243  recalculate_value (split, reg, price, amount, shares_changed);
2244 
2245  if (price_changed)
2246  {
2247  cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
2248  PRIC_CELL);
2249  price = gnc_price_cell_get_value (cell);
2250  if (gnc_numeric_positive_p(price))
2251  record_price (reg, account, price);
2252  }
2253  return TRUE;
2254 }
2255 
2256 static GNCAccountType
2257 gnc_split_register_type_to_account_type (SplitRegisterType sr_type)
2258 {
2259  switch (sr_type)
2260  {
2261  case BANK_REGISTER:
2262  return ACCT_TYPE_BANK;
2263  case CASH_REGISTER:
2264  return ACCT_TYPE_CASH;
2265  case ASSET_REGISTER:
2266  return ACCT_TYPE_ASSET;
2267  case CREDIT_REGISTER:
2268  return ACCT_TYPE_CREDIT;
2269  case LIABILITY_REGISTER:
2270  return ACCT_TYPE_LIABILITY;
2271  case PAYABLE_REGISTER:
2272  return ACCT_TYPE_PAYABLE;
2273  case RECEIVABLE_REGISTER:
2274  return ACCT_TYPE_RECEIVABLE;
2275  case INCOME_LEDGER:
2276  case INCOME_REGISTER:
2277  return ACCT_TYPE_INCOME;
2278  case EXPENSE_REGISTER:
2279  return ACCT_TYPE_EXPENSE;
2280  case STOCK_REGISTER:
2281  case PORTFOLIO_LEDGER:
2282  return ACCT_TYPE_STOCK;
2283  case CURRENCY_REGISTER:
2284  return ACCT_TYPE_CURRENCY;
2285  case TRADING_REGISTER:
2286  return ACCT_TYPE_TRADING;
2287  case GENERAL_LEDGER:
2288  return ACCT_TYPE_NONE;
2289  case EQUITY_REGISTER:
2290  return ACCT_TYPE_EQUITY;
2291  case SEARCH_LEDGER:
2292  return ACCT_TYPE_NONE;
2293  default:
2294  return ACCT_TYPE_NONE;
2295  }
2296 }
2297 
2298 const char *
2300 {
2301  SRInfo *info = gnc_split_register_get_info (reg);
2302 
2303  if (!reg)
2304  return NULL;
2305 
2306  if (info->debit_str)
2307  return info->debit_str;
2308 
2309  info->debit_str =
2310  gnc_get_debit_string
2311  (gnc_split_register_type_to_account_type (reg->type));
2312 
2313  if (info->debit_str)
2314  return info->debit_str;
2315 
2316  info->debit_str = g_strdup (_("Debit"));
2317 
2318  return info->debit_str;
2319 }
2320 
2321 const char *
2323 {
2324  SRInfo *info = gnc_split_register_get_info (reg);
2325 
2326  if (!reg)
2327  return NULL;
2328 
2329  if (info->credit_str)
2330  return info->credit_str;
2331 
2332  info->credit_str =
2333  gnc_get_credit_string
2334  (gnc_split_register_type_to_account_type (reg->type));
2335 
2336  if (info->credit_str)
2337  return info->credit_str;
2338 
2339  info->credit_str = g_strdup (_("Credit"));
2340 
2341  return info->credit_str;
2342 }
2343 
2344 gboolean
2346 {
2347  SRInfo *info = gnc_split_register_get_info (reg);
2348  Transaction *pending_trans;
2349 
2350  ENTER("reg=%p", reg);
2351 
2352  if (reg == NULL)
2353  {
2354  LEAVE("no register");
2355  return FALSE;
2356  }
2357 
2358  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2359  {
2360  LEAVE("cursor changed");
2361  return TRUE;
2362  }
2363 
2364  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2365  gnc_get_current_book ());
2366  if (xaccTransIsOpen (pending_trans))
2367  {
2368  LEAVE("open and pending txn");
2369  return TRUE;
2370  }
2371 
2372  LEAVE("register unchanged");
2373  return FALSE;
2374 }
2375 
2376 void
2378  gboolean show_present)
2379 {
2380  SRInfo *info = gnc_split_register_get_info (reg);
2381 
2382  if (reg == NULL)
2383  return;
2384 
2385  info->show_present_divider = show_present;
2386 }
2387 
2388 gboolean
2390 {
2391  SRInfo *info = gnc_split_register_get_info (reg);
2392 
2393  if (!info)
2394  return FALSE;
2395 
2396  return info->full_refresh;
2397 }
2398 
2399 /* configAction strings into the action cell */
2400 /* hack alert -- this stuff really, really should be in a config file ... */
2401 static void
2402 gnc_split_register_config_action (SplitRegister *reg)
2403 {
2404  ComboCell *cell;
2405 
2406  cell = (ComboCell *) gnc_table_layout_get_cell (reg->table->layout,
2407  ACTN_CELL);
2408 
2409  /* setup strings in the action pull-down */
2410  switch (reg->type)
2411  {
2412  case BANK_REGISTER:
2413  /* broken ! FIXME bg */
2414  case SEARCH_LEDGER:
2415  /* Translators: This string has a context prefix; the translation
2416  must only contain the part after the | character. */
2417  gnc_combo_cell_add_menu_item (cell, Q_("Action Column|Deposit"));
2418  gnc_combo_cell_add_menu_item (cell, _("Withdraw"));
2419  gnc_combo_cell_add_menu_item (cell, _("Check"));
2420  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2421  gnc_combo_cell_add_menu_item (cell, _("ATM Deposit"));
2422  gnc_combo_cell_add_menu_item (cell, _("ATM Draw"));
2423  gnc_combo_cell_add_menu_item (cell, _("Teller"));
2424  gnc_combo_cell_add_menu_item (cell, _("Charge"));
2425  gnc_combo_cell_add_menu_item (cell, _("Payment"));
2426  gnc_combo_cell_add_menu_item (cell, _("Receipt"));
2427  gnc_combo_cell_add_menu_item (cell, _("Increase"));
2428  gnc_combo_cell_add_menu_item (cell, _("Decrease"));
2429  /* Action: Point Of Sale */
2430  gnc_combo_cell_add_menu_item (cell, _("POS"));
2431  gnc_combo_cell_add_menu_item (cell, _("Phone"));
2432  gnc_combo_cell_add_menu_item (cell, _("Online"));
2433  /* Action: Automatic Deposit ?!? */
2434  gnc_combo_cell_add_menu_item (cell, _("AutoDep"));
2435  gnc_combo_cell_add_menu_item (cell, _("Wire"));
2436  gnc_combo_cell_add_menu_item (cell, _("Credit"));
2437  gnc_combo_cell_add_menu_item (cell, _("Direct Debit"));
2438  gnc_combo_cell_add_menu_item (cell, _("Transfer"));
2439  break;
2440  case CASH_REGISTER:
2441  gnc_combo_cell_add_menu_item (cell, _("Increase"));
2442  gnc_combo_cell_add_menu_item (cell, _("Decrease"));
2443  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2444  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2445  break;
2446  case ASSET_REGISTER:
2447  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2448  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2449  gnc_combo_cell_add_menu_item (cell, _("Fee"));
2450  break;
2451  case CREDIT_REGISTER:
2452  gnc_combo_cell_add_menu_item (cell, _("ATM Deposit"));
2453  gnc_combo_cell_add_menu_item (cell, _("ATM Draw"));
2454  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2455  gnc_combo_cell_add_menu_item (cell, _("Credit"));
2456  gnc_combo_cell_add_menu_item (cell, _("Fee"));
2457  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2458  gnc_combo_cell_add_menu_item (cell, _("Online"));
2459  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2460  break;
2461  case LIABILITY_REGISTER:
2462  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2463  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2464  gnc_combo_cell_add_menu_item (cell, _("Loan"));
2465  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2466  gnc_combo_cell_add_menu_item (cell, _("Payment"));
2467  break;
2468  case RECEIVABLE_REGISTER:
2469  case PAYABLE_REGISTER:
2470  gnc_combo_cell_add_menu_item (cell, _("Invoice"));
2471  gnc_combo_cell_add_menu_item (cell, _("Payment"));
2472  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2473  gnc_combo_cell_add_menu_item (cell, _("Credit"));
2474  break;
2475  case INCOME_LEDGER:
2476  case INCOME_REGISTER:
2477  gnc_combo_cell_add_menu_item (cell, _("Increase"));
2478  gnc_combo_cell_add_menu_item (cell, _("Decrease"));
2479  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2480  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2481  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2482  gnc_combo_cell_add_menu_item (cell, _("Payment"));
2483  gnc_combo_cell_add_menu_item (cell, _("Rebate"));
2484  gnc_combo_cell_add_menu_item (cell, _("Paycheck"));
2485  break;
2486  case EXPENSE_REGISTER:
2487  case TRADING_REGISTER:
2488  gnc_combo_cell_add_menu_item (cell, _("Increase"));
2489  gnc_combo_cell_add_menu_item (cell, _("Decrease"));
2490  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2491  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2492  break;
2493  case GENERAL_LEDGER:
2494  case EQUITY_REGISTER:
2495  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2496  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2497  gnc_combo_cell_add_menu_item (cell, _("Equity"));
2498  break;
2499  case STOCK_REGISTER:
2500  case PORTFOLIO_LEDGER:
2501  case CURRENCY_REGISTER:
2502  gnc_combo_cell_add_menu_item (cell, ACTION_BUY_STR);
2503  gnc_combo_cell_add_menu_item (cell, ACTION_SELL_STR);
2504  gnc_combo_cell_add_menu_item (cell, _("Price"));
2505  gnc_combo_cell_add_menu_item (cell, _("Fee"));
2506  /* Action: Dividend */
2507  gnc_combo_cell_add_menu_item (cell, _("Dividend"));
2508  gnc_combo_cell_add_menu_item (cell, _("Interest"));
2509  /* Action: Long Term Capital Gains */
2510  gnc_combo_cell_add_menu_item (cell, _("LTCG"));
2511  /* Action: Short Term Capital Gains */
2512  gnc_combo_cell_add_menu_item (cell, _("STCG"));
2513  gnc_combo_cell_add_menu_item (cell, _("Income"));
2514  /* Action: Distribution */
2515  gnc_combo_cell_add_menu_item (cell, _("Dist"));
2516  /* Translators: This string has a disambiguation prefix */
2517  gnc_combo_cell_add_menu_item (cell, Q_("Action Column|Split"));
2518  break;
2519 
2520  default:
2521  gnc_combo_cell_add_menu_item (cell, _("Increase"));
2522  gnc_combo_cell_add_menu_item (cell, _("Decrease"));
2523  gnc_combo_cell_add_menu_item (cell, _("Buy"));
2524  gnc_combo_cell_add_menu_item (cell, _("Sell"));
2525  break;
2526  }
2527 }
2528 
2529 static void
2530 gnc_split_register_config_cells (SplitRegister *reg)
2531 {
2533  ((ComboCell *)
2534  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2535  SPLIT_TRANS_STR);
2536 
2538  ((ComboCell *)
2539  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2540  STOCK_SPLIT_STR);
2541 
2542  /* the action cell */
2544  ((ComboCell *)
2545  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), TRUE);
2546 
2547  /* Use 6 decimal places for prices and "exchange rates" */
2548  gnc_price_cell_set_fraction
2549  ((PriceCell *)
2550  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL), 1000000);
2551 
2552  /* Initialize shares and share balance cells */
2553  gnc_price_cell_set_print_info
2554  ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL),
2555  gnc_default_share_print_info ());
2556 
2557  gnc_price_cell_set_print_info
2558  ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, TSHRS_CELL),
2559  gnc_default_share_print_info ());
2560 
2561  /* Initialize the rate cell
2562  * use a share_print_info to make sure we don't have rounding errors
2563  */
2564  gnc_price_cell_set_print_info
2565  ((PriceCell *) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL),
2566  gnc_default_share_print_info());
2567 
2568  /* The action cell should accept strings not in the list */
2570  ((ComboCell *)
2571  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), FALSE);
2572 
2573  /* number format for share quantities in stock ledgers */
2574  switch (reg->type)
2575  {
2576  case CURRENCY_REGISTER:
2577  case STOCK_REGISTER:
2578  case PORTFOLIO_LEDGER:
2579  gnc_price_cell_set_print_info
2580  ((PriceCell *)
2581  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
2582  gnc_default_price_print_info ());
2583  break;
2584 
2585  default:
2586  break;
2587  }
2588 
2589  /* add menu items for the action cell */
2590  gnc_split_register_config_action (reg);
2591 }
2592 
2593 static void
2594 split_register_pref_changed (gpointer prefs, gchar *pref, gpointer user_data)
2595 {
2596  SplitRegister * reg = user_data;
2597  SRInfo *info;
2598 
2599  g_return_if_fail(pref);
2600  if (reg == NULL)
2601  return;
2602 
2603  info = reg->sr_info;
2604  if (!info)
2605  return;
2606 
2607  if (g_str_has_suffix(pref, GNC_PREF_ACCOUNTING_LABELS))
2608  {
2609  /* Release current strings. Will be reloaded at next reference. */
2610  g_free (info->debit_str);
2611  g_free (info->tdebit_str);
2612  g_free (info->credit_str);
2613  g_free (info->tcredit_str);
2614 
2615  info->debit_str = NULL;
2616  info->tdebit_str = NULL;
2617  info->credit_str = NULL;
2618  info->tcredit_str = NULL;
2619 
2620  }
2621  else if (g_str_has_suffix(pref, GNC_PREF_ACCOUNT_SEPARATOR))
2622  {
2623  info->separator_changed = TRUE;
2624  }
2625  else
2626  {
2627  g_warning("split_register_pref_changed: Unknown preference %s", pref);
2628  }
2629 }
2630 
2631 static void
2632 split_register_book_option_changed (gpointer new_val, gpointer user_data)
2633 {
2634  SplitRegister * reg = user_data;
2635  gboolean *new_data = (gboolean*)new_val;
2636 
2637  if (reg == NULL)
2638  return;
2639 
2640  reg->use_tran_num_for_num_field = (*new_data ? FALSE : TRUE);
2641 }
2642 
2643 static void
2644 gnc_split_register_init (SplitRegister *reg,
2645  SplitRegisterType type,
2646  SplitRegisterStyle style,
2647  gboolean use_double_line,
2648  gboolean do_auto_complete,
2649  gboolean is_template)
2650 {
2651  TableLayout *layout;
2652  TableModel *model;
2653  TableControl *control;
2654 
2655  /* Register 'destroy' callback */
2656  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2657  GNC_PREF_ACCOUNTING_LABELS,
2658  split_register_pref_changed,
2659  reg);
2660  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2661  GNC_PREF_ACCOUNT_SEPARATOR,
2662  split_register_pref_changed,
2663  reg);
2664  gnc_book_option_register_cb(OPTION_NAME_NUM_FIELD_SOURCE,
2665  split_register_book_option_changed,
2666  reg);
2667 
2668  reg->sr_info = NULL;
2669 
2670  reg->type = type;
2671  reg->style = style;
2672  reg->use_double_line = use_double_line;
2673  reg->do_auto_complete = do_auto_complete;
2674  reg->is_template = is_template;
2676  (qof_book_use_split_action_for_num_field(gnc_get_current_book())
2677  ? FALSE : TRUE);
2678 
2679  layout = gnc_split_register_layout_new (reg);
2680 
2681  if (is_template)
2682  model = gnc_template_register_model_new ();
2683  else
2684  model = gnc_split_register_model_new ();
2685  model->handler_user_data = reg;
2686 
2687  control = gnc_split_register_control_new ();
2688  control->user_data = reg;
2689 
2690  reg->table = gnc_table_new (layout, model, control);
2691 
2692  gnc_split_register_config_cells (reg);
2693 
2694  /* Set up header */
2695  {
2696  VirtualCellLocation vcell_loc = { 0, 0 };
2697  CellBlock *header;
2698 
2699  header = gnc_table_layout_get_cursor (reg->table->layout, CURSOR_HEADER);
2700 
2701  gnc_table_set_vcell (reg->table, header, NULL, TRUE, TRUE, vcell_loc);
2702  }
2703 
2704  /* Set up first and only initial row */
2705  {
2706  VirtualLocation vloc;
2707  CellBlock *cursor;
2708 
2709  vloc.vcell_loc.virt_row = 1;
2710  vloc.vcell_loc.virt_col = 0;
2711  vloc.phys_row_offset = 0;
2712  vloc.phys_col_offset = 0;
2713 
2714  cursor = gnc_table_layout_get_cursor (reg->table->layout,
2715  CURSOR_SINGLE_LEDGER);
2716 
2717  gnc_table_set_vcell (reg->table, cursor, NULL, TRUE, TRUE, vloc.vcell_loc);
2718 
2719  if (gnc_table_find_close_valid_cell (reg->table, &vloc, FALSE))
2720  gnc_table_move_cursor (reg->table, vloc);
2721  else
2722  {
2723  PERR ("Can't find valid initial location");
2724  }
2725  }
2726 }
2727 
2728 SplitRegister *
2730  SplitRegisterStyle style,
2731  gboolean use_double_line,
2732  gboolean is_template)
2733 {
2734  SplitRegister * reg;
2735  gboolean default_do_auto_complete = TRUE;
2736 
2737  reg = g_new0 (SplitRegister, 1);
2738 
2739  if (type >= NUM_SINGLE_REGISTER_TYPES)
2740  style = REG_STYLE_JOURNAL;
2741 
2742  gnc_split_register_init (reg,
2743  type,
2744  style,
2745  use_double_line,
2746  default_do_auto_complete,
2747  is_template);
2748 
2749  return reg;
2750 }
2751 
2752 void
2754  SplitRegisterType newtype,
2755  SplitRegisterStyle newstyle,
2756  gboolean use_double_line)
2757 {
2758  if (!reg) return;
2759 
2760  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2761  if (reg->use_double_line && !use_double_line)
2762  {
2763  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2764  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
2765  {
2766  if (virt_loc.phys_row_offset)
2767  {
2768  gnc_table_move_vertical_position (reg->table, &virt_loc, -virt_loc.phys_row_offset);
2769  gnc_table_move_cursor_gui (reg->table, virt_loc);
2770  }
2771  }
2772  else
2773  {
2774  /* WTF? Go to a known safe location. */
2775  virt_loc.vcell_loc.virt_row = 1;
2776  virt_loc.vcell_loc.virt_col = 0;
2777  virt_loc.phys_row_offset = 0;
2778  virt_loc.phys_col_offset = 0;
2779  gnc_table_move_cursor_gui (reg->table, virt_loc);
2780  }
2781  }
2782 
2783  reg->type = newtype;
2784 
2785  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
2786  newstyle = REG_STYLE_JOURNAL;
2787 
2788  reg->style = newstyle;
2789  reg->use_double_line = use_double_line;
2790 
2791  gnc_table_realize_gui (reg->table);
2792 }
2793 
2794 void
2796  gboolean do_auto_complete)
2797 {
2798  g_return_if_fail(reg);
2799  reg->do_auto_complete = do_auto_complete;
2800 }
2801 
2802 static void
2803 gnc_split_register_destroy_info (SplitRegister *reg)
2804 {
2805  SRInfo *info;
2806 
2807  if (reg == NULL)
2808  return;
2809 
2810  info = reg->sr_info;
2811  if (!info)
2812  return;
2813 
2814  g_free (info->debit_str);
2815  g_free (info->tdebit_str);
2816  g_free (info->credit_str);
2817  g_free (info->tcredit_str);
2818 
2819  info->debit_str = NULL;
2820  info->tdebit_str = NULL;
2821  info->credit_str = NULL;
2822  info->tcredit_str = NULL;
2823 
2824  g_free (reg->sr_info);
2825 
2826  reg->sr_info = NULL;
2827 }
2828 
2829 void
2830 gnc_split_register_set_data (SplitRegister *reg, void *user_data,
2831  SRGetParentCallback get_parent)
2832 {
2833  SRInfo *info = gnc_split_register_get_info (reg);
2834 
2835  g_return_if_fail (reg != NULL);
2836 
2837  info->user_data = user_data;
2838  info->get_parent = get_parent;
2839 }
2840 
2841 static void
2842 gnc_split_register_cleanup (SplitRegister *reg)
2843 {
2844  SRInfo *info = gnc_split_register_get_info (reg);
2845  Transaction *pending_trans;
2846  Transaction *blank_trans = NULL;
2847  Split *blank_split;
2848 
2849  ENTER("reg=%p", reg);
2850 
2851  blank_split = xaccSplitLookup (&info->blank_split_guid,
2852  gnc_get_current_book ());
2853 
2854  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2855  gnc_get_current_book ());
2856 
2857  gnc_suspend_gui_refresh ();
2858 
2859  /* Destroy the transaction containing the "blank split", which was only
2860  * created to support the area for entering a new transaction. Since the
2861  * register is closing, this transaction is no longer needed. */
2862  if (blank_split != NULL)
2863  {
2864  gboolean was_open;
2865 
2866  blank_trans = xaccSplitGetParent (blank_split);
2867 
2868  DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p",
2869  blank_split, blank_trans, pending_trans);
2870 
2871  /* Destroying the transaction will automatically remove its splits. */
2872  was_open = xaccTransIsOpen (blank_trans);
2873  xaccTransDestroy (blank_trans);
2874  if (was_open)
2875  xaccTransCommitEdit (blank_trans);
2876 
2877  /* Update the register info. */
2878  if (blank_trans == pending_trans)
2879  {
2880  info->pending_trans_guid = *guid_null ();
2881  pending_trans = NULL;
2882  }
2883  info->blank_split_guid = *guid_null ();
2884  info->auto_complete = FALSE;
2885  blank_split = NULL;
2886  }
2887 
2888  /* be sure to take care of any open transactions */
2889  if (pending_trans != NULL)
2890  {
2891  g_critical("BUG DETECTED: pending_trans=%p, blank_split=%p, blank_trans=%p",
2892  pending_trans, blank_split, blank_trans);
2893  g_assert_not_reached();
2894  info->pending_trans_guid = *guid_null ();
2895  /* CAS: It's not clear to me that we'd really want to commit
2896  here, rather than rollback. But, maybe this is just dead
2897  code. */
2898  if (xaccTransIsOpen (pending_trans))
2899  xaccTransCommitEdit (pending_trans);
2900  else g_assert_not_reached();
2901 
2902  pending_trans = NULL;
2903  }
2904 
2905  gnc_split_register_destroy_info (reg);
2906 
2907  gnc_resume_gui_refresh ();
2908 
2909  LEAVE(" ");
2910 }
2911 
2912 void
2914 {
2915  g_return_if_fail(reg);
2916 
2917  ENTER("reg=%p", reg);
2918 
2919  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2920  GNC_PREF_ACCOUNTING_LABELS,
2921  split_register_pref_changed,
2922  reg);
2923  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
2924  GNC_PREF_ACCOUNT_SEPARATOR,
2925  split_register_pref_changed,
2926  reg);
2927  gnc_book_option_remove_cb(OPTION_NAME_NUM_FIELD_SOURCE,
2928  split_register_book_option_changed,
2929  reg);
2930  gnc_split_register_cleanup (reg);
2931 
2932  gnc_table_destroy (reg->table);
2933  reg->table = NULL;
2934 
2935  /* free the memory itself */
2936  g_free (reg);
2937  LEAVE(" ");
2938 }
2939 
2940 void
2942 {
2943  gnc_table_model_set_read_only (reg->table->model, read_only);
2944 }
void gnc_copy_trans_onto_trans(Transaction *from, Transaction *to, gboolean use_cut_semantics, gboolean do_commit)
GNCPrice * gnc_price_create(QofBook *book)
Definition: gnc-pricedb.c:236
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
const char * gnc_split_register_get_debit_string(SplitRegister *reg)
void gnc_split_register_void_current_trans(SplitRegister *reg, const char *reason)
#define xaccTransAppendSplit(t, s)
Definition: Transaction.h:357
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
void gnc_combo_cell_set_autosize(ComboCell *cell, gboolean autosize)
const char * xaccAccountGetLastNum(const Account *acc)
Definition: Account.c:4472
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
Definition: Transaction.c:1920
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2215
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Definition: Transaction.c:1015
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:128
Dialog for create/edit an account.
QofBook * qof_instance_get_book(gconstpointer)
gboolean xaccAccountIsPriced(const Account *acc)
Definition: Account.c:4249
gboolean xaccTransIsOpen(const Transaction *trans)
Definition: Transaction.c:1819
void gnc_split_register_copy_current(SplitRegister *reg)
The type, style and table for the register.
#define PINFO(format, args...)
Definition: qoflog.h:249
gboolean xaccSplitDestroy(Split *split)
Definition: Split.c:1492
gboolean use_tran_num_for_num_field
int xaccAccountGetCommoditySCU(const Account *acc)
Definition: Account.c:2458
gnc_numeric gnc_numeric_neg(gnc_numeric a)
void gnc_split_register_unvoid_current_trans(SplitRegister *reg)
Split * gnc_split_register_get_current_split(SplitRegister *reg)
void gnc_split_register_delete_current_split(SplitRegister *reg)
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
Definition: gnc-pricedb.c:1053
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
char xaccSplitGetReconcile(const Split *split)
Definition: Split.c:1980
Account * gnc_ui_new_accounts_from_name_window(const char *name)
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
gboolean gnc_split_register_full_refresh_ok(SplitRegister *reg)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
SplitRegister * gnc_split_register_new(SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line, gboolean is_template)
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
gboolean gnc_numeric_zero_p(gnc_numeric a)
gboolean gnc_split_register_changed(SplitRegister *reg)
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
gboolean gnc_table_move_vertical_position(Table *table, VirtualLocation *virt_loc, int phys_row_offset)
Create the actual register visual layout.
SplitRegisterType
Register types.
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
#define PERR(format, args...)
Definition: qoflog.h:237
void gnc_split_register_set_auto_complete(SplitRegister *reg, gboolean do_auto_complete)
#define ENTER(format, args...)
Definition: qoflog.h:261
gboolean gnc_strisnum(const gchar *s)
void xaccAccountSetLastNum(Account *acc, const char *num)
Definition: Account.c:4481
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Definition: gnc-pricedb.c:872
Definition: guid.h:65
gboolean gnc_numeric_negative_p(gnc_numeric a)
#define VREC
Definition: Split.h:71
gnc_commodity * gnc_default_currency(void)
Definition: gnc-ui-util.c:939
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
Definition: Transaction.c:1024
void gnc_split_register_redraw(SplitRegister *reg)
gboolean use_double_line
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
int xaccTransCountSplits(const Transaction *trans)
Definition: Transaction.c:2170
gchar * gnc_get_account_name_for_register(const Account *account)
Definition: gnc-ui-util.c:282
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
Definition: Split.c:1104
void gnc_split_register_paste_current(SplitRegister *reg)
void xaccTransVoid(Transaction *trans, const char *reason)
Definition: Transaction.c:2495
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
Definition: Account.c:2836
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
gboolean do_auto_complete
GtkWidget *(* SRGetParentCallback)(gpointer user_data)
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
#define xaccSplitGetGUID(X)
Definition: Split.h:521
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Definition: Account.c:1475
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Definition: Split.c:1999
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Definition: Transaction.c:2154
void xaccTransUnvoid(Transaction *trans)
Definition: Transaction.c:2552
API for checkbook register display area.
void gnc_split_register_empty_current_trans_except_split(SplitRegister *reg, Split *split)
GNCAccountType
Definition: Account.h:96
gboolean gnc_numeric_positive_p(gnc_numeric a)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
void gnc_combo_cell_add_ignore_string(ComboCell *cell, const char *ignore_string)
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
Generic api to store and retrieve preferences.
void gnc_split_register_set_read_only(SplitRegister *reg, gboolean read_only)
void gnc_combo_cell_set_strict(ComboCell *cell, gboolean strict)
CursorClass
const char * gnc_split_register_get_credit_string(SplitRegister *reg)
gboolean gnc_split_register_handle_exchange(SplitRegister *reg, gboolean force_dialog)
GDate helper routines.
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
const GncGUID * guid_null(void)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
Declarations for the Table object.
#define LEAVE(format, args...)
Definition: qoflog.h:271
void gnc_split_register_delete_current_trans(SplitRegister *reg)
gboolean gnc_split_register_get_split_amount_virt_loc(SplitRegister *reg, Split *split, VirtualLocation *virt_loc)
Split * gnc_split_register_duplicate_current(SplitRegister *reg)
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
void gnc_split_register_show_present_divider(SplitRegister *reg, gboolean show_present)
gint64 time64
Definition: gnc-date.h:83
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Definition: Transaction.c:1951
gboolean qof_book_uses_autoreadonly(const QofBook *book)
void gnc_split_register_destroy(SplitRegister *reg)
void gnc_split_register_set_data(SplitRegister *reg, gpointer user_data, SRGetParentCallback get_parent)
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
TableLayout * gnc_split_register_layout_new(SplitRegister *reg)
void gnc_split_register_cut_current(SplitRegister *reg)
Account * gnc_account_lookup_for_register(const Account *base_account, const gchar *name)
SplitRegisterStyle
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
void xaccTransRollbackEdit(Transaction *trans)
Definition: Transaction.c:1661
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
void gnc_split_register_cancel_cursor_trans_changes(SplitRegister *reg)
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_gdate_set_time64(GDate *gd, time64 time)
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Definition: gnc-prefs.c:148
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987
void gnc_split_register_config(SplitRegister *reg, SplitRegisterType newtype, SplitRegisterStyle newstyle, gboolean use_double_line)
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
Definition: Account.c:1827