GnuCash  5.6-150-g038405b370+
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 gnu@gnu.org *
18  * *
19 \********************************************************************/
20 /*
21  * split-register.c
22  * author Copyright (c) 1998-2000 Linas Vepstas <linas@linas.org>
23  * author Copyright (c) 2000-2001 Dave Peticolas <dave@krondo.com>
24  * author Copyright (c) 2017 Aaron Laws
25  */
26 #include <config.h>
27 
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 
31 #include "combocell.h"
32 #include "completioncell.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-date.h"
38 #include <gnc-hooks.h>
39 #include "gnc-ledger-display.h"
40 #include "gnc-prefs.h"
41 #include "gnc-ui.h"
42 #include "gnc-warnings.h"
43 #include "split-register-copy-ops.h"
44 #include "numcell.h"
45 #include "pricecell.h"
46 #include "quickfillcell.h"
47 #include "recncell.h"
48 #include "split-register.h"
49 #include "split-register-control.h"
50 #include "split-register-layout.h"
51 #include "split-register-model.h"
53 #include "table-allgui.h"
54 #include "dialog-account.h"
55 #include "dialog-dup-trans.h"
56 #include "engine-helpers.h"
57 #include "qofbookslots.h"
58 
59 
62 /* This static indicates the debugging module that this .o belongs to. */
63 static QofLogModule log_module = GNC_MOD_LEDGER;
64 
65 /* The copied split or transaction, if any */
66 typedef struct
67 {
68  GType ftype;
69  union
70  {
71  FloatingSplit *fs;
72  FloatingTxn *ft;
73  };
74  CursorClass cursor_class;
75  GncGUID leader_guid;
76  gint anchor_split_index;
77 } ft_fs_store;
78 
79 static ft_fs_store copied_item = { 0, { NULL } };
80 
83 static gboolean gnc_split_register_save_to_copy_buffer (SplitRegister *reg,
84  FloatingTxn *ft,
85  FloatingSplit *fs,
86  gboolean use_cut_semantics);
87 static gboolean gnc_split_register_auto_calc (SplitRegister *reg,
88  Split *split);
89 
90 
93 static void
94 clear_copied_item()
95 {
96  if (copied_item.ftype == GNC_TYPE_SPLIT)
97  gnc_float_split_free (copied_item.fs);
98  if (copied_item.ftype == GNC_TYPE_TRANSACTION)
99  gnc_float_txn_free (copied_item.ft);
100  copied_item.ftype = 0;
101  copied_item.fs = NULL;
102  copied_item.ft = NULL;
103  copied_item.cursor_class = CURSOR_CLASS_NONE;
104  copied_item.leader_guid = *guid_null();
105  copied_item.anchor_split_index = 0;
106 }
107 
108 static void
109 gnc_copy_split_onto_split (Split* from, Split* to, gboolean use_cut_semantics)
110 {
111  FloatingSplit *fs;
112 
113  if ((from == NULL) || (to == NULL))
114  return;
115 
116  fs = gnc_split_to_float_split (from);
117  if (!fs)
118  return;
119 
120  gnc_float_split_to_split (fs, to);
121  gnc_float_split_free (fs);
122 }
123 
124 void
125 gnc_copy_trans_onto_trans (Transaction* from, Transaction* to,
126  gboolean use_cut_semantics,
127  gboolean do_commit)
128 {
129  FloatingTxn *ft;
130 
131  if ((from == NULL) || (to == NULL))
132  return;
133 
134  ft = gnc_txn_to_float_txn (from, use_cut_semantics);
135  if (!ft)
136  return;
137 
138  gnc_float_txn_to_txn (ft, to, do_commit);
139  gnc_float_txn_free (ft);
140 }
141 
142 static int
143 gnc_split_get_value_denom (Split* split)
144 {
145  gnc_commodity* currency;
146  int denom;
147 
148  currency = xaccTransGetCurrency (xaccSplitGetParent (split));
149  denom = gnc_commodity_get_fraction (currency);
150  if (denom == 0)
151  {
152  gnc_commodity* commodity = gnc_default_currency ();
153  denom = gnc_commodity_get_fraction (commodity);
154  if (denom == 0)
155  denom = 100;
156  }
157 
158  return denom;
159 }
160 
161 static int
162 gnc_split_get_amount_denom (Split* split)
163 {
164  int denom;
165 
167  if (denom == 0)
168  {
169  gnc_commodity* commodity = gnc_default_currency ();
170  denom = gnc_commodity_get_fraction (commodity);
171  if (denom == 0)
172  denom = 100;
173  }
174 
175  return denom;
176 }
177 
178 /* returns TRUE if begin_edit was aborted */
179 gboolean
180 gnc_split_register_begin_edit_or_warn (SRInfo* info, Transaction* trans)
181 {
182  ENTER ("info=%p, trans=%p", info, trans);
183 
184  if (!xaccTransIsOpen (trans))
185  {
186  xaccTransBeginEdit (trans);
187  /* This is now the pending transaction */
188  info->pending_trans_guid = *xaccTransGetGUID (trans);
189  LEAVE ("opened and marked pending");
190  return FALSE;
191  }
192  else
193  {
194  Split* blank_split = xaccSplitLookup (&info->blank_split_guid,
195  gnc_get_current_book ());
196  Transaction* blank_trans = xaccSplitGetParent (blank_split);
197 
198  if (trans == blank_trans)
199  {
200  /* This is a brand-new transaction. It is already
201  * open, so just mark it as pending. */
202  info->pending_trans_guid = *xaccTransGetGUID (trans);
203  LEAVE ("already open, now pending.");
204  return FALSE;
205  }
206  else
207  {
208  GtkWindow* parent = NULL;
209  if (info->get_parent)
210  parent = GTK_WINDOW (info->get_parent (info->user_data));
211  gnc_error_dialog (parent, "%s",
212  _ ("This transaction is already being edited in another register. Please finish editing it there first."));
213  LEAVE ("already editing");
214  return TRUE;
215  }
216  }
217  LEAVE (" ");
218  return FALSE; /* to satisfy static code analysis */
219 }
220 
221 void
222 gnc_split_register_expand_current_trans (SplitRegister* reg, gboolean expand)
223 {
224  SRInfo* info = gnc_split_register_get_info (reg);
225  VirtualLocation virt_loc;
226 
227  if (!reg)
228  return;
229 
230  if (reg->style == REG_STYLE_AUTO_LEDGER ||
231  reg->style == REG_STYLE_JOURNAL)
232  return;
233 
234  /* ok, so I just wanted an excuse to use exclusive-or */
235  if (! (expand ^ info->trans_expanded))
236  return;
237 
238  if (!expand)
239  {
240  virt_loc = reg->table->current_cursor_loc;
241  gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
242  &virt_loc.vcell_loc);
243 
244  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
245  gnc_table_move_cursor_gui (reg->table, virt_loc);
246  else
247  {
248  PERR ("Can't find place to go!");
249  return;
250  }
251  }
252 
253  info->trans_expanded = expand;
254 
255  gnc_table_set_virt_cell_cursor (reg->table,
256  reg->table->current_cursor_loc.vcell_loc,
257  gnc_split_register_get_active_cursor (reg));
258 
260  reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
261 
262  virt_loc = reg->table->current_cursor_loc;
263  if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
264  {
265  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
266  gnc_table_move_cursor_gui (reg->table, virt_loc);
267  else
268  {
269  PERR ("Can't find place to go!");
270  return;
271  }
272  }
273 
274  gnc_table_refresh_gui (reg->table, TRUE);
275 
276  if (expand)
277  gnc_split_register_show_trans (reg,
278  reg->table->current_cursor_loc.vcell_loc);
279 }
280 
281 gboolean
283 {
284  SRInfo* info = gnc_split_register_get_info (reg);
285 
286  if (!reg)
287  return FALSE;
288 
289  if (reg->style == REG_STYLE_AUTO_LEDGER ||
290  reg->style == REG_STYLE_JOURNAL)
291  return TRUE;
292 
293  return info->trans_expanded;
294 }
295 
296 Transaction*
298 {
299  Split* split;
300  VirtualCellLocation vcell_loc;
301 
302  if (reg == NULL)
303  return NULL;
304 
306  if (split != NULL)
307  return xaccSplitGetParent (split);
308 
309  /* Split is blank. Assume it is the blank split of a multi-line
310  * transaction. Go back one row to find a split in the transaction. */
311  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
312 
313  vcell_loc.virt_row--;
314 
315  split = gnc_split_register_get_split (reg, vcell_loc);
316 
317  return xaccSplitGetParent (split);
318 }
319 
320 Split*
322 {
323  if (reg == NULL)
324  return NULL;
325 
326  return gnc_split_register_get_split (
327  reg, reg->table->current_cursor_loc.vcell_loc);
328 }
329 
330 Split*
332 {
333  SRInfo* info = gnc_split_register_get_info (reg);
334 
335  if (!reg) return NULL;
336 
337  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
338 }
339 
340 gboolean
341 gnc_split_register_get_split_virt_loc (SplitRegister* reg, Split* split,
342  VirtualCellLocation* vcell_loc)
343 {
344  Table* table;
345  int v_row;
346  int v_col;
347 
348  if (!reg || !split) return FALSE;
349 
350  table = reg->table;
351 
352  /* go backwards because typically you search for splits at the end
353  * and because we find split rows before transaction rows. */
354 
355  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
356  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
357  {
358  VirtualCellLocation vc_loc = { v_row, v_col };
359  VirtualCell* vcell;
360  Split* s;
361 
362  vcell = gnc_table_get_virtual_cell (table, vc_loc);
363  if (!vcell || !vcell->visible)
364  continue;
365 
366  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
367 
368  if (s == split)
369  {
370  if (vcell_loc)
371  *vcell_loc = vc_loc;
372 
373  return TRUE;
374  }
375  }
376 
377  return FALSE;
378 }
379 
380 gboolean
381 gnc_split_register_get_split_amount_virt_loc (SplitRegister* reg, Split* split,
382  VirtualLocation* virt_loc)
383 {
384  VirtualLocation v_loc;
385  CursorClass cursor_class;
386  const char* cell_name;
387  gnc_numeric value;
388 
389  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
390  return FALSE;
391 
392  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
393 
394  value = xaccSplitGetValue (split);
395 
396  switch (cursor_class)
397  {
398  case CURSOR_CLASS_SPLIT:
399  case CURSOR_CLASS_TRANS:
400  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
401  break;
402  default:
403  return FALSE;
404  }
405 
406  if (!gnc_table_get_cell_location (reg->table, cell_name,
407  v_loc.vcell_loc, &v_loc))
408  return FALSE;
409 
410  if (virt_loc == NULL)
411  return TRUE;
412 
413  *virt_loc = v_loc;
414 
415  return TRUE;
416 }
417 
418 Split*
420 {
421  SRInfo* info = gnc_split_register_get_info (reg);
422  CursorClass cursor_class;
423  Transaction* trans;
424  Split* return_split;
425  Split* trans_split;
426  Split* blank_split;
427  gboolean changed;
428  Split* split;
429 
430  ENTER ("reg=%p", reg);
431 
432  blank_split = xaccSplitLookup (&info->blank_split_guid,
433  gnc_get_current_book ());
436  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
437 
438  /* This shouldn't happen, but be paranoid. */
439  if (trans == NULL)
440  {
441  LEAVE ("no transaction");
442  return NULL;
443  }
444 
445  cursor_class = gnc_split_register_get_current_cursor_class (reg);
446 
447  /* Can't do anything with this. */
448  if (cursor_class == CURSOR_CLASS_NONE)
449  {
450  LEAVE ("no cursor class");
451  return NULL;
452  }
453 
454  /* This shouldn't happen, but be paranoid. */
455  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
456  {
457  LEAVE ("no split with transaction class");
458  return NULL;
459  }
460 
461  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
462 
463  /* See if we were asked to duplicate an unchanged blank split.
464  * There's no point in doing that! */
465  if (!changed && ((split == NULL) || (split == blank_split)))
466  {
467  LEAVE ("skip unchanged blank split");
468  return NULL;
469  }
470 
471  gnc_suspend_gui_refresh ();
472 
473  /* If the cursor has been edited, we are going to have to commit
474  * it before we can duplicate. Make sure the user wants to do that. */
475  if (changed)
476  {
477  GtkWidget* dialog, *window;
478  gint response;
479  const char* title = _ ("Save transaction before duplicating?");
480  const char* message =
481  _ ("The current transaction has been changed. Would you like to "
482  "record the changes before duplicating the transaction, or "
483  "cancel the duplication?");
484 
485  window = gnc_split_register_get_parent (reg);
486  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
487  GTK_DIALOG_DESTROY_WITH_PARENT,
488  GTK_MESSAGE_QUESTION,
489  GTK_BUTTONS_CANCEL,
490  "%s", title);
491  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
492  "%s", message);
493  gtk_dialog_add_button (GTK_DIALOG (dialog),
494  _ ("_Record"), GTK_RESPONSE_ACCEPT);
495  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_TRANS_DUP);
496  gtk_widget_destroy (dialog);
497 
498  if (response != GTK_RESPONSE_ACCEPT)
499  {
500  gnc_resume_gui_refresh ();
501  LEAVE ("save cancelled");
502  return NULL;
503  }
504 
505  gnc_split_register_save (reg, TRUE);
506 
507  /* If the split is NULL, then we were on a blank split row
508  * in an expanded transaction. The new split (created by
509  * gnc_split_register_save above) will be the last split in the
510  * current transaction, as it was just added. */
511  if (split == NULL)
512  split = xaccTransGetSplit (trans, xaccTransCountSplits (trans) - 1);
513  }
514 
515  /* Ok, we are now ready to make the copy. */
516 
517  if (cursor_class == CURSOR_CLASS_SPLIT)
518  {
519  Split* new_split;
520  char* out_num;
521  gboolean new_act_num = FALSE;
522 
523  /* We are on a split in an expanded transaction.
524  * Just copy the split and add it to the transaction.
525  * However, if the split-action field is being used as the register
526  * number, and the action field is a number, request a new value or
527  * cancel. Need to get next number and update account last num from
528  * split account not register account, which may be the same or not */
529 
530  if (!reg->use_tran_num_for_num_field
531  && gnc_strisnum (gnc_get_num_action (NULL, split)))
532  {
533  Account* account = xaccSplitGetAccount (split);
534  const char* in_num = NULL;
535  const char* title = _ ("New Split Information");
536  time64 date = info->last_date_entered;
537 
538  if (account)
539  in_num = xaccAccountGetLastNum (account);
540  else
541  in_num = gnc_get_num_action (NULL, split);
542 
543  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg),
544  title, FALSE, &date, in_num, &out_num,
545  NULL, NULL, NULL, NULL))
546  {
547  gnc_resume_gui_refresh ();
548  LEAVE ("dup cancelled");
549  return NULL;
550  }
551  new_act_num = TRUE;
552  }
553 
554  new_split = xaccMallocSplit (gnc_get_current_book ());
555 
556  xaccTransBeginEdit (trans);
557  xaccSplitSetParent (new_split, trans);
558  gnc_copy_split_onto_split (split, new_split, FALSE);
559  if (new_act_num) /* if new number supplied by user dialog */
560  gnc_set_num_action (NULL, new_split, out_num, NULL);
561 
562  xaccTransCommitEdit (trans);
563 
564  if (new_act_num && gnc_strisnum (out_num))
565  {
566  Account* account = xaccSplitGetAccount (new_split);
567 
568  /* If current register is for account, set last num */
569  if (xaccAccountEqual (account,
570  gnc_split_register_get_default_account (reg),
571  TRUE))
572  {
573  NumCell* num_cell;
574  num_cell = (NumCell*) gnc_table_layout_get_cell (reg->table->layout,
575  NUM_CELL);
576  if (gnc_num_cell_set_last_num (num_cell, out_num))
577  gnc_split_register_set_last_num (reg, out_num);
578  }
579  else
580  {
581  xaccAccountSetLastNum (account, out_num);
582  }
583  }
584 
585  return_split = new_split;
586 
587  info->cursor_hint_split = new_split;
588  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
589  if (new_act_num)
590  g_free (out_num);
591  }
592  else
593  {
594  Account* account;
595  NumCell* num_cell;
596  Transaction* new_trans;
597  int trans_split_index;
598  int split_index;
599  const char* in_num = NULL;
600  const char* in_tnum = NULL;
601  char* out_num = NULL;
602  char* out_tnum = NULL;
603  char* out_tdoclink = NULL;
604  time64 date;
605  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
606  gnc_get_current_book ());
607 
608  /* We are on a transaction row. Copy the whole transaction. */
609 
610  date = info->last_date_entered;
611 
612  account = gnc_split_register_get_default_account (reg);
613 
614  if (account && gnc_strisnum (gnc_get_num_action (trans, trans_split)))
615  in_num = xaccAccountGetLastNum (account);
616  else
617  in_num = gnc_get_num_action (trans, trans_split);
618 
619  in_tnum = (reg->use_tran_num_for_num_field
620  ? NULL
621  : gnc_get_num_action (trans, NULL));
622 
623  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg), NULL,
624  TRUE, &date, in_num, &out_num, in_tnum, &out_tnum,
625  xaccTransGetDocLink (trans), &out_tdoclink))
626  {
627  gnc_resume_gui_refresh ();
628  LEAVE ("dup cancelled");
629  return NULL;
630  }
631 
632  if (use_autoreadonly)
633  {
634  GDate d;
635  GDate* readonly_threshold = qof_book_get_autoreadonly_gdate (
636  gnc_get_current_book ());
637  gnc_gdate_set_time64 (&d, date);
638  if (g_date_compare (&d, readonly_threshold) < 0)
639  {
640  GtkWidget* dialog = gtk_message_dialog_new (NULL,
641  0,
642  GTK_MESSAGE_ERROR,
643  GTK_BUTTONS_OK,
644  "%s", _ ("Cannot store a transaction at this date"));
645  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
646  "%s", _ ("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book. "
647  "This setting can be changed in File->Properties->Accounts."));
648  gtk_dialog_run (GTK_DIALOG (dialog));
649  gtk_widget_destroy (dialog);
650 
651  g_date_free (readonly_threshold);
652  return NULL;
653  }
654  g_date_free (readonly_threshold);
655  }
656 
657  split_index = xaccTransGetSplitIndex (trans, split);
658  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
659 
660  /* we should *always* find the split, but be paranoid */
661  if (split_index < 0)
662  {
663  gnc_resume_gui_refresh ();
664  LEAVE ("no split");
665  return NULL;
666  }
667 
668  new_trans = xaccMallocTransaction (gnc_get_current_book ());
669 
670  xaccTransBeginEdit (new_trans);
671  gnc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
672  xaccTransSetDatePostedSecsNormalized (new_trans, date);
673  /* We also must set a new DateEntered on the new entry
674  * because otherwise the ordering is not deterministic */
675  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
676 
677  /* clear the document link entry if returned value NULL */
678  if (out_tdoclink == NULL)
679  xaccTransSetDocLink (new_trans, "");
680  else
681  g_free (out_tdoclink);
682 
683  /* set per book option */
684  gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
685  if (!reg->use_tran_num_for_num_field)
686  {
687  /* find split in new_trans that equals trans_split and set
688  * split_action to out_num */
689  gnc_set_num_action (NULL,
690  xaccTransGetSplit (new_trans, trans_split_index),
691  out_num, NULL);
692  /* note that if the transaction has multiple splits to the register
693  * account, only the anchor split will be set with user input. The
694  * user will have to adjust other splits manually. */
695  }
696  xaccTransCommitEdit (new_trans);
697 
698  num_cell = (NumCell*) gnc_table_layout_get_cell (reg->table->layout,
699  NUM_CELL);
700  if (gnc_num_cell_set_last_num (num_cell, out_num))
701  gnc_split_register_set_last_num (reg, out_num);
702 
703  g_free (out_num);
704  if (!reg->use_tran_num_for_num_field)
705  g_free (out_tnum);
706 
707  /* This shouldn't happen, but be paranoid. */
708  if (split_index >= xaccTransCountSplits (new_trans))
709  split_index = 0;
710 
711  return_split = xaccTransGetSplit (new_trans, split_index);
712  trans_split = xaccTransGetSplit (new_trans, trans_split_index);
713 
714  info->cursor_hint_trans = new_trans;
715  info->cursor_hint_split = return_split;
716  info->cursor_hint_trans_split = trans_split;
717  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
718 
719  info->trans_expanded = FALSE;
720  }
721 
722  /* Refresh the GUI. */
723  gnc_resume_gui_refresh ();
724 
725  LEAVE (" ");
726  return return_split;
727 }
728 
729 static void
730 gnc_split_register_copy_current_internal (SplitRegister* reg,
731  gboolean use_cut_semantics)
732 {
733  SRInfo* info = gnc_split_register_get_info (reg);
734  CursorClass cursor_class;
735  Transaction* trans;
736  Split* blank_split;
737  gboolean changed;
738  Split *split;
739  FloatingSplit *new_fs = NULL;
740  FloatingTxn *new_ft = NULL;
741 
742  g_return_if_fail (reg);
743  ENTER ("reg=%p, use_cut_semantics=%s", reg,
744  use_cut_semantics ? "TRUE" : "FALSE");
745 
746  blank_split = xaccSplitLookup (&info->blank_split_guid,
747  gnc_get_current_book ());
750 
751  /* This shouldn't happen, but be paranoid. */
752  if (trans == NULL)
753  {
754  LEAVE ("no trans");
755  return;
756  }
757 
758  cursor_class = gnc_split_register_get_current_cursor_class (reg);
759 
760  /* Can't do anything with this. */
761  if (cursor_class == CURSOR_CLASS_NONE)
762  {
763  LEAVE ("no cursor class");
764  return;
765  }
766 
767  /* This shouldn't happen, but be paranoid. */
768  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
769  {
770  g_warning ("BUG DETECTED: transaction cursor with no anchoring split!");
771  LEAVE ("transaction cursor with no anchoring split");
772  return;
773  }
774 
775  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
776 
777  /* See if we were asked to copy an unchanged blank split. Don't. */
778  if (!changed && ((split == NULL) || (split == blank_split)))
779  {
780  /* We're either on an unedited, brand-new split or an unedited, brand-new
781  * transaction (the transaction anchored by the blank split.) */
782  /* FIXME: This doesn't work exactly right. When entering a new transaction,
783  * you can edit the description, move to a split row, then move
784  * back to the description, then ask for a copy, and this code will
785  * be reached. It forgets that you changed the row the first time
786  * you were there. -Charles */
787  LEAVE ("nothing to copy/cut");
788  return;
789  }
790 
791  /* unprotect the old object, if any */
792  clear_copied_item();
793 
794  /* Ok, we are now ready to make the copy. */
795 
796  if (cursor_class == CURSOR_CLASS_SPLIT)
797  {
798  /* We are on a split in an expanded transaction. Just copy the split. */
799  new_fs = gnc_split_to_float_split (split);
800 
801  if (new_fs)
802  {
803  if (changed)
804  gnc_split_register_save_to_copy_buffer (reg, NULL, new_fs,
805  use_cut_semantics);
806 
807  copied_item.leader_guid = *guid_null ();
808  }
809  }
810  else
811  {
812  /* We are on a transaction row. Copy the whole transaction. */
813  new_ft = gnc_txn_to_float_txn (trans, use_cut_semantics);
814 
815  if (new_ft)
816  {
817  if (changed)
818  {
819  int split_index;
820  FloatingSplit *fs;
821 
822  split_index = xaccTransGetSplitIndex (trans, split);
823  if (split_index >= 0)
824  fs = gnc_float_txn_get_float_split (new_ft, split_index);
825  else
826  fs = NULL;
827 
828  gnc_split_register_save_to_copy_buffer (reg, new_ft, fs,
829  use_cut_semantics);
830  }
831 
832  copied_item.leader_guid = info->default_account;
833  copied_item.anchor_split_index = xaccTransGetSplitIndex (trans, split);
834  }
835  }
836 
837  if (!new_fs && !new_ft)
838  {
839  g_warning ("BUG DETECTED: copy failed");
840  LEAVE ("copy failed");
841  return;
842  }
843 
844  if (new_fs)
845  {
846  copied_item.fs = new_fs;
847  copied_item.ftype = GNC_TYPE_SPLIT;
848  }
849  else if (new_ft)
850  {
851  copied_item.ft = new_ft;
852  copied_item.ftype = GNC_TYPE_TRANSACTION;
853  }
854 
855  copied_item.cursor_class = cursor_class;
856  gnc_hook_add_dangler (HOOK_BOOK_CLOSED, clear_copied_item, NULL, NULL);
857  LEAVE ("%s %s", use_cut_semantics ? "cut" : "copied",
858  cursor_class == CURSOR_CLASS_SPLIT ? "split" : "transaction");
859 }
860 
861 void
863 {
864  gnc_split_register_copy_current_internal (reg, FALSE);
865 }
866 
867 void
868 gnc_split_register_cut_current (SplitRegister* reg)
869 {
870  SRInfo* info = gnc_split_register_get_info (reg);
871  CursorClass cursor_class;
872  Transaction* trans;
873  Split* blank_split;
874  gboolean changed;
875  Split* split;
876 
877  blank_split = xaccSplitLookup (&info->blank_split_guid,
878  gnc_get_current_book ());
881 
882  /* This shouldn't happen, but be paranoid. */
883  if (trans == NULL)
884  return;
885 
886  cursor_class = gnc_split_register_get_current_cursor_class (reg);
887 
888  /* Can't do anything with this. */
889  if (cursor_class == CURSOR_CLASS_NONE)
890  return;
891 
892  /* This shouldn't happen, but be paranoid. */
893  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
894  return;
895 
896  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
897 
898  /* See if we were asked to cut an unchanged blank split. Don't. */
899  if (!changed && ((split == NULL) || (split == blank_split)))
900  return;
901 
902  gnc_split_register_copy_current_internal (reg, TRUE);
903 
904  if (cursor_class == CURSOR_CLASS_SPLIT)
906  else
908 }
909 
910 void
912 {
913  SRInfo* info = gnc_split_register_get_info (reg);
914  CursorClass cursor_class;
915  Transaction* trans;
916  Transaction* blank_trans;
917  Split* blank_split;
918  Split* trans_split;
919  Split* split;
920 
921  ENTER ("reg=%p", reg);
922 
923  if (copied_item.cursor_class == CURSOR_CLASS_NONE)
924  {
925  LEAVE ("no copied cursor class");
926  return;
927  }
928 
929  blank_split = xaccSplitLookup (&info->blank_split_guid,
930  gnc_get_current_book ());
931  blank_trans = xaccSplitGetParent (blank_split);
934 
935  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
936 
937  /* This shouldn't happen, but be paranoid. */
938  if (trans == NULL)
939  {
940  LEAVE ("no transaction");
941  return;
942  }
943 
944  cursor_class = gnc_split_register_get_current_cursor_class (reg);
945 
946  /* Can't do anything with this. */
947  if (cursor_class == CURSOR_CLASS_NONE)
948  {
949  LEAVE ("no current cursor class");
950  return;
951  }
952 
953  /* This shouldn't happen, but be paranoid. */
954  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
955  {
956  g_warning ("BUG DETECTED: transaction cursor with no anchoring split!");
957  LEAVE ("transaction cursor with no anchoring split");
958  return;
959  }
960 
961  if (cursor_class == CURSOR_CLASS_SPLIT)
962  {
963  const char* message = _ ("You are about to overwrite an existing split. "
964  "Are you sure you want to do that?");
965  const char* anchor_message = _ ("This is the split anchoring this transaction "
966  "to the register. You may not overwrite it from "
967  "this register window. You may overwrite it if "
968  "you navigate to a register that shows another "
969  "side of this same transaction.");
970 
971  if (copied_item.cursor_class == CURSOR_CLASS_TRANS)
972  {
973  /* An entire transaction was copied, but we're just on a split. */
974  LEAVE ("can't copy trans to split");
975  return;
976  }
977 
978  if (split != NULL)
979  {
980  /* the General Journal does not have any anchoring splits */
981  if ((reg->type != GENERAL_JOURNAL) &&
982  split == gnc_split_register_get_current_trans_split (reg, NULL))
983  {
984  gnc_warning_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
985  "%s", anchor_message);
986  LEAVE ("anchore split");
987  return;
988  }
989  else if (!gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
990  FALSE, "%s", message))
991  {
992  LEAVE ("user cancelled");
993  return;
994  }
995  }
996 
997  /* Open the transaction for editing. */
998  if (gnc_split_register_begin_edit_or_warn (info, trans))
999  {
1000  LEAVE ("can't begin editing");
1001  return;
1002  }
1003 
1004  gnc_suspend_gui_refresh ();
1005 
1006  if (split == NULL)
1007  {
1008  /* We are on a null split in an expanded transaction. */
1009  split = xaccMallocSplit (gnc_get_current_book ());
1010  xaccSplitSetParent (split, trans);
1011  }
1012 
1013  if (copied_item.ftype != GNC_TYPE_SPLIT)
1014  {
1015  LEAVE ("copy buffer doesn't represent a split");
1016  return;
1017  }
1018 
1019  gnc_float_split_to_split (copied_item.fs, split);
1020  }
1021  else
1022  {
1023  const char *message = _("You are about to overwrite an existing "
1024  "transaction. "
1025  "Are you sure you want to do that?");
1026  Account * copied_leader;
1027  Account * default_account;
1028  int trans_split_index;
1029  int split_index;
1030  int num_splits;
1031 
1032  if (copied_item.cursor_class == CURSOR_CLASS_SPLIT)
1033  {
1034  LEAVE ("can't copy split to transaction");
1035  return;
1036  }
1037 
1038 
1039  if (copied_item.ftype != GNC_TYPE_TRANSACTION)
1040  {
1041  LEAVE ("copy buffer doesn't represent a transaction");
1042  return;
1043  }
1044 
1045  /* Ask before overwriting an existing transaction. */
1046  if (split != blank_split &&
1047  !gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
1048  FALSE, "%s", message))
1049  {
1050  LEAVE ("user cancelled");
1051  return;
1052  }
1053 
1054  /* Open the transaction for editing. */
1055  if (gnc_split_register_begin_edit_or_warn (info, trans))
1056  {
1057  LEAVE ("can't begin editing");
1058  return;
1059  }
1060 
1061  gnc_suspend_gui_refresh ();
1062 
1063  DEBUG ("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
1064  trans, split, blank_trans, blank_split);
1065 
1066  split_index = xaccTransGetSplitIndex (trans, split);
1067  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
1068 
1069  copied_leader = xaccAccountLookup (&copied_item.leader_guid,
1070  gnc_get_current_book ());
1071  default_account = gnc_split_register_get_default_account (reg);
1072  if (copied_leader && default_account)
1073  {
1074  gnc_float_txn_to_txn_swap_accounts (copied_item.ft, trans,
1075  copied_leader,
1076  default_account, FALSE);
1077  }
1078  else
1079  gnc_float_txn_to_txn (copied_item.ft, trans, FALSE);
1080 
1081  num_splits = xaccTransCountSplits (trans);
1082  if (split_index >= num_splits)
1083  split_index = 0;
1084 
1085  if (trans == blank_trans)
1086  {
1087  /* In pasting, the blank split is deleted. Pick a new one. */
1088  gint anchor_split_index = copied_item.anchor_split_index;
1089  if (anchor_split_index > num_splits)
1090  anchor_split_index = 0;
1091 
1092  blank_split = xaccTransGetSplit (trans, anchor_split_index);
1093  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
1094  info->blank_split_edited = TRUE;
1095  info->auto_complete = FALSE;
1096  DEBUG ("replacement blank_split=%p", blank_split);
1097 
1098  /* NOTE: At this point, the blank transaction virtual cell is still
1099  * anchored by the old, deleted blank split. The register will
1100  * have to be reloaded (redrawn) to correct this. */
1101  }
1102 
1103  info->cursor_hint_trans = trans;
1104  info->cursor_hint_split = xaccTransGetSplit (trans, split_index);
1105  info->cursor_hint_trans_split = xaccTransGetSplit (trans,
1106  trans_split_index);
1107  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
1108  }
1109 
1110  /* Refresh the GUI. */
1111  gnc_resume_gui_refresh ();
1112  LEAVE (" ");
1113 }
1114 
1115 gboolean
1116 gnc_split_register_is_blank_split (SplitRegister* reg, Split* split)
1117 {
1118  SRInfo* info = gnc_split_register_get_info (reg);
1119  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1120  gnc_get_current_book ());
1121 
1122  if (split == current_blank_split)
1123  return TRUE;
1124 
1125  return FALSE;
1126 }
1127 
1128 void
1129 gnc_split_register_change_blank_split_ref (SplitRegister* reg, Split* split)
1130 {
1131  SRInfo* info = gnc_split_register_get_info (reg);
1132  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1133  gnc_get_current_book ());
1134  Split* pref_split = NULL; // has the same account as incoming split
1135  Split* other_split = NULL; // other split
1136  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1137  Transaction* trans = xaccSplitGetParent (split);
1138 
1139  // loop through splitlist looking for splits other than the blank_split
1140  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1141  {
1142  Split *s = n->data;
1143  if (s != current_blank_split && xaccTransStillHasSplit (trans, s))
1144  {
1145  if (blank_split_account == xaccSplitGetAccount (s))
1146  pref_split = s; // prefer same account
1147  else
1148  other_split = s; // any other split
1149  }
1150  }
1151  // now change the saved blank split reference
1152  if (pref_split != NULL)
1153  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1154  else if (other_split != NULL)
1155  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1156  else
1157  info->blank_split_guid = *guid_null();
1158 }
1159 
1160 void
1162 {
1163  SRInfo* info = gnc_split_register_get_info (reg);
1164  Transaction* pending_trans;
1165  Transaction* trans;
1166  Split* blank_split;
1167  Split* split;
1168 
1169  if (!reg) return;
1170 
1171  blank_split = xaccSplitLookup (&info->blank_split_guid,
1172  gnc_get_current_book ());
1173 
1174  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1175  gnc_get_current_book ());
1176 
1177  /* get the current split based on cursor position */
1179  if (split == NULL)
1180  return;
1181 
1182  /* If we are deleting the blank split, just cancel. The user is
1183  * allowed to delete the blank split as a method for discarding
1184  * any edits they may have made to it. */
1185  if (split == blank_split)
1186  {
1188  return;
1189  }
1190 
1191  gnc_suspend_gui_refresh ();
1192 
1193  trans = xaccSplitGetParent (split);
1194 
1195  /* Check pending transaction */
1196  if (trans == pending_trans)
1197  {
1198  g_assert (xaccTransIsOpen (trans));
1199  }
1200  else
1201  {
1202  g_assert (!pending_trans);
1203  if (gnc_split_register_begin_edit_or_warn (info, trans))
1204  {
1205  gnc_resume_gui_refresh ();
1206  return;
1207  }
1208  }
1209  xaccSplitDestroy (split);
1210 
1211  gnc_resume_gui_refresh ();
1213 }
1214 
1215 void
1217 {
1218  SRInfo* info = gnc_split_register_get_info (reg);
1219  Transaction* pending_trans;
1220  Transaction* trans;
1221  Split* blank_split;
1222  Split* split;
1223  gboolean was_open;
1224 
1225  ENTER ("reg=%p", reg);
1226  if (!reg)
1227  {
1228  LEAVE ("no register");
1229  return;
1230  }
1231 
1232  blank_split = xaccSplitLookup (&info->blank_split_guid,
1233  gnc_get_current_book ());
1234  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1235  gnc_get_current_book ());
1236 
1237  /* get the current split based on cursor position */
1239  if (split == NULL)
1240  {
1241  LEAVE ("no split");
1242  return;
1243  }
1244 
1245  gnc_suspend_gui_refresh ();
1246  trans = xaccSplitGetParent (split);
1247 
1248  /* If we just deleted the blank split, clean up. The user is
1249  * allowed to delete the blank split as a method for discarding
1250  * any edits they may have made to it. */
1251  if (split == blank_split)
1252  {
1253  DEBUG ("deleting blank split");
1254  info->blank_split_guid = *guid_null ();
1255  info->auto_complete = FALSE;
1256  }
1257  else
1258  {
1259  info->trans_expanded = FALSE;
1260  }
1261 
1262  /* Check pending transaction */
1263  if (trans == pending_trans)
1264  {
1265  DEBUG ("clearing pending trans");
1266  info->pending_trans_guid = *guid_null ();
1267  pending_trans = NULL;
1268  }
1269 
1270  was_open = xaccTransIsOpen (trans);
1271  xaccTransDestroy (trans);
1272  if (was_open)
1273  {
1274  DEBUG ("committing");
1275  xaccTransCommitEdit (trans);
1276  }
1277  gnc_resume_gui_refresh ();
1279  LEAVE (" ");
1280 }
1281 
1282 void
1283 gnc_split_register_void_current_trans (SplitRegister* reg, const char* reason)
1284 {
1285  SRInfo* info = gnc_split_register_get_info (reg);
1286  Transaction* pending_trans;
1287  Transaction* trans;
1288  Split* blank_split;
1289  Split* split;
1290 
1291  if (!reg) return;
1292 
1293  blank_split = xaccSplitLookup (&info->blank_split_guid,
1294  gnc_get_current_book ());
1295  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1296  gnc_get_current_book ());
1297 
1298  /* get the current split based on cursor position */
1300  if (split == NULL)
1301  return;
1302 
1303  /* Bail if trying to void the blank split. */
1304  if (split == blank_split)
1305  return;
1306 
1307  /* already voided. */
1308  if (xaccSplitGetReconcile (split) == VREC)
1309  return;
1310 
1311  info->trans_expanded = FALSE;
1312 
1313  gnc_suspend_gui_refresh ();
1314 
1315  trans = xaccSplitGetParent (split);
1316  xaccTransVoid (trans, reason);
1317 
1318  /* Check pending transaction */
1319  if (trans == pending_trans)
1320  {
1321  info->pending_trans_guid = *guid_null ();
1322  pending_trans = NULL;
1323  }
1324  if (xaccTransIsOpen (trans))
1325  {
1326  PERR ("We should not be voiding an open transaction.");
1327  xaccTransCommitEdit (trans);
1328  }
1329  gnc_resume_gui_refresh ();
1330 }
1331 
1332 void
1334 {
1335  SRInfo* info = gnc_split_register_get_info (reg);
1336  Transaction* pending_trans;
1337  Transaction* trans;
1338  Split* blank_split;
1339  Split* split;
1340 
1341  if (!reg) return;
1342 
1343  blank_split = xaccSplitLookup (&info->blank_split_guid,
1344  gnc_get_current_book ());
1345  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1346  gnc_get_current_book ());
1347 
1348  /* get the current split based on cursor position */
1350  if (split == NULL)
1351  return;
1352 
1353  /* Bail if trying to unvoid the blank split. */
1354  if (split == blank_split)
1355  return;
1356 
1357  /* not voided. */
1358  if (xaccSplitGetReconcile (split) != VREC)
1359  return;
1360 
1361  info->trans_expanded = FALSE;
1362 
1363  gnc_suspend_gui_refresh ();
1364 
1365  trans = xaccSplitGetParent (split);
1366 
1367  xaccTransUnvoid (trans);
1368 
1369  /* Check pending transaction */
1370  if (trans == pending_trans)
1371  {
1372  info->pending_trans_guid = *guid_null ();
1373  pending_trans = NULL;
1374  }
1375 
1376  gnc_resume_gui_refresh ();
1377 }
1378 
1379 void
1381  Split* split)
1382 {
1383  SRInfo* info;
1384  Transaction* trans;
1385  Transaction* pending;
1386  int i = 0;
1387  Split* s;
1388 
1389  if ((reg == NULL) || (split == NULL))
1390  return;
1391 
1392  gnc_suspend_gui_refresh ();
1393  info = gnc_split_register_get_info (reg);
1394  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1395 
1396  trans = xaccSplitGetParent (split);
1397  if (!pending)
1398  {
1399  if (gnc_split_register_begin_edit_or_warn (info, trans))
1400  {
1401  gnc_resume_gui_refresh ();
1402  return;
1403  }
1404  }
1405  else if (pending == trans)
1406  {
1407  g_assert (xaccTransIsOpen (trans));
1408  }
1409  else g_assert_not_reached ();
1410 
1411  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1412  {
1413  if (s != split)
1414  xaccSplitDestroy (s);
1415  else i++;
1416  }
1417 
1418  gnc_resume_gui_refresh ();
1420 }
1421 
1422 void
1423 gnc_split_register_empty_current_trans (SplitRegister* reg)
1424 {
1425  Split* split;
1426 
1427  /* get the current split based on cursor position */
1430 }
1431 
1432 void
1434 {
1435  VirtualLocation virt_loc;
1436 
1437  if (reg == NULL)
1438  return;
1439 
1440  virt_loc = reg->table->current_cursor_loc;
1441 
1442  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1443  return;
1444 
1445  /* We're just cancelling the current split here, not the transaction.
1446  * When cancelling edits, reload the cursor from the transaction. */
1447  gnc_table_clear_current_cursor_changes (reg->table);
1448 
1449  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1450  gnc_table_move_cursor_gui (reg->table, virt_loc);
1451 
1452  gnc_table_refresh_gui (reg->table, TRUE);
1453 }
1454 
1455 void
1457 {
1458  SRInfo* info = gnc_split_register_get_info (reg);
1459  Transaction* pending_trans, *blank_trans;
1460  gboolean refresh_all = FALSE;
1461 
1462  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1463  gnc_get_current_book ());
1464 
1466 
1467  if (pending_trans == blank_trans)
1468  refresh_all = TRUE;
1469 
1470  /* Get the currently open transaction, rollback the edits on it, and
1471  * then repaint everything. To repaint everything, make a note of
1472  * all of the accounts that will be affected by this rollback. */
1473  if (!xaccTransIsOpen (pending_trans))
1474  {
1476  return;
1477  }
1478 
1479  if (!pending_trans)
1480  return;
1481 
1482  gnc_suspend_gui_refresh ();
1483 
1484  xaccTransRollbackEdit (pending_trans);
1485 
1486  info->pending_trans_guid = *guid_null ();
1487 
1488  gnc_resume_gui_refresh ();
1489 
1490  if (refresh_all)
1491  gnc_gui_refresh_all (); // force a refresh of all registers
1492  else
1494 }
1495 
1496 void
1497 gnc_split_register_redraw (SplitRegister* reg)
1498 {
1499  gnc_ledger_display_refresh_by_split_register (reg);
1500 }
1501 
1502 /* Copy from the register object to scheme. This needs to be
1503  * in sync with gnc_split_register_save and xaccSRSaveChangedCells. */
1504 static gboolean
1505 gnc_split_register_save_to_copy_buffer (SplitRegister *reg,
1506  FloatingTxn *ft, FloatingSplit *fs,
1507  gboolean use_cut_semantics)
1508 {
1509  FloatingSplit *other_fs = NULL;
1510  Transaction *trans;
1511 
1512  /* use the changed flag to avoid heavy-weight updates
1513  * of the split & transaction fields. This will help
1514  * cut down on unnecessary register redraws. */
1515  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1516  return FALSE;
1517 
1518  /* get the handle to the current split and transaction */
1520  if (trans == NULL)
1521  return FALSE;
1522 
1523  /* copy the contents from the cursor to the split */
1524  if (gnc_table_layout_get_cell_changed (reg->table->layout, DATE_CELL, TRUE))
1525  {
1526  BasicCell* cell;
1527  time64 time;
1528  cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
1529  gnc_date_cell_get_date ((DateCell*) cell, &time, TRUE);
1531  }
1532 
1533  if (gnc_table_layout_get_cell_changed (reg->table->layout, NUM_CELL, TRUE))
1534  {
1535  const char* value;
1536 
1537  value = gnc_table_layout_get_cell_value (reg->table->layout, NUM_CELL);
1538  if (reg->use_tran_num_for_num_field)
1539  xaccTransSetNum (trans, value);
1540  /* else this contains the same as ACTN_CELL which is already handled below *
1541  * and the TNUM_CELL contains transaction number which is handled in next *
1542  * if statement. */
1543  }
1544 
1545  if (gnc_table_layout_get_cell_changed (reg->table->layout, TNUM_CELL, TRUE))
1546  {
1547  const char* value;
1548 
1549  value = gnc_table_layout_get_cell_value (reg->table->layout, TNUM_CELL);
1550  if (!reg->use_tran_num_for_num_field)
1551  xaccTransSetNum (trans, value);
1552  /* else this cell is not used */
1553  }
1554 
1555  if (gnc_table_layout_get_cell_changed (reg->table->layout, DESC_CELL, TRUE))
1556  {
1557  const char* value;
1558 
1559  value = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
1560  xaccTransSetDescription (trans, value);
1561  }
1562 
1563  if (gnc_table_layout_get_cell_changed (reg->table->layout, NOTES_CELL, TRUE))
1564  {
1565  const char* value;
1566 
1567  value = gnc_table_layout_get_cell_value (reg->table->layout, NOTES_CELL);
1568  xaccTransSetNotes (trans, value);
1569  }
1570 
1571  if (gnc_table_layout_get_cell_changed (reg->table->layout, RECN_CELL, TRUE))
1572  {
1573  BasicCell* cell;
1574  char flag;
1575 
1576  cell = gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
1577  flag = gnc_recn_cell_get_flag ((RecnCell*) cell);
1578 
1579  gnc_float_split_set_reconcile_state (fs, flag);
1580  }
1581 
1582  if (gnc_table_layout_get_cell_changed (reg->table->layout, ACTN_CELL, TRUE))
1583  {
1584  const char* value;
1585 
1586  value = gnc_table_layout_get_cell_value (reg->table->layout, ACTN_CELL);
1587  gnc_float_split_set_action (fs, value);
1588  }
1589 
1590  if (gnc_table_layout_get_cell_changed (reg->table->layout, MEMO_CELL, TRUE))
1591  {
1592  const char* value;
1593 
1594  value = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
1595  gnc_float_split_set_memo (fs, value);
1596  }
1597 
1598  if (gnc_table_layout_get_cell_changed (reg->table->layout, XFRM_CELL, TRUE))
1599  {
1600  Account* new_account;
1601 
1602  new_account = gnc_split_register_get_account (reg, XFRM_CELL);
1603 
1604  if (new_account != NULL)
1605  gnc_float_split_set_account (fs, new_account);
1606  }
1607 
1608  if (reg->style == REG_STYLE_LEDGER)
1609  other_fs = gnc_float_txn_get_other_float_split (ft, fs);
1610 
1611  if (gnc_table_layout_get_cell_changed (reg->table->layout, MXFRM_CELL, TRUE))
1612  {
1613  other_fs = gnc_float_txn_get_other_float_split (ft, fs);
1614 
1615  if (!other_fs)
1616  {
1617  if (ft && g_list_length (ft->m_splits) == 1)
1618  {
1619  Split* temp_split;
1620 
1621  temp_split = xaccMallocSplit (gnc_get_current_book ());
1622  other_fs = gnc_split_to_float_split (temp_split);
1623  xaccSplitDestroy (temp_split);
1624 
1625  gnc_float_txn_append_float_split (ft, other_fs);
1626  }
1627  }
1628 
1629  if (other_fs)
1630  {
1631  Account* new_account;
1632 
1633  new_account = gnc_split_register_get_account (reg, MXFRM_CELL);
1634 
1635  if (new_account != NULL)
1636  gnc_float_split_set_account (other_fs, new_account);
1637  }
1638  }
1639 
1640  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1641  DEBT_CELL, TRUE) ||
1642  gnc_table_layout_get_cell_changed (reg->table->layout,
1643  CRED_CELL, TRUE))
1644  {
1645  BasicCell* cell;
1646  gnc_numeric new_value;
1647  gnc_numeric credit;
1648  gnc_numeric debit;
1649 
1650  cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
1651  credit = gnc_price_cell_get_value ((PriceCell*) cell);
1652 
1653  cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
1654  debit = gnc_price_cell_get_value ((PriceCell*) cell);
1655 
1656  new_value = gnc_numeric_sub_fixed (debit, credit);
1657 
1658  gnc_float_split_set_value (fs, new_value);
1659  }
1660 
1661  if (gnc_table_layout_get_cell_changed (reg->table->layout, PRIC_CELL, TRUE))
1662  {
1663  /* do nothing for now */
1664  }
1665 
1666  if (gnc_table_layout_get_cell_changed (reg->table->layout, SHRS_CELL, TRUE))
1667  {
1668  BasicCell* cell;
1669  gnc_numeric shares;
1670 
1671  cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1672 
1673  shares = gnc_price_cell_get_value ((PriceCell*) cell);
1674 
1675  gnc_float_split_set_amount (fs, shares);
1676  }
1677 
1678  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1679  DEBT_CELL, TRUE) ||
1680  gnc_table_layout_get_cell_changed (reg->table->layout,
1681  CRED_CELL, TRUE) ||
1682  gnc_table_layout_get_cell_changed (reg->table->layout,
1683  PRIC_CELL, TRUE) ||
1684  gnc_table_layout_get_cell_changed (reg->table->layout,
1685  SHRS_CELL, TRUE))
1686  {
1687  if (other_fs)
1688  {
1689  gnc_numeric num;
1690 
1691  num = gnc_float_split_get_amount (fs);
1692  gnc_float_split_set_amount (other_fs, gnc_numeric_neg (num));
1693 
1694  num = gnc_float_split_get_value (fs);
1695  gnc_float_split_set_value (other_fs, gnc_numeric_neg (num));
1696  }
1697  }
1698 
1699  return TRUE;
1700 }
1701 static void
1702 unreconcile_splits (SplitRegister* reg)
1703 {
1704  if (reg->unrecn_splits == NULL)
1705  return; //Nothing to do.
1706  PINFO ("Unreconcile %d splits of reconciled transaction",
1707  g_list_length (reg->unrecn_splits));
1708 
1709  for (GList* node = reg->unrecn_splits; node; node = node->next)
1710  {
1711  Split* split = node->data;
1712  Transaction* txn = xaccSplitGetParent (split);
1713  if (!xaccTransIsOpen (txn))
1714  PWARN ("Unreconcile of split failed because its parent transaction wasn't open for editing");
1715  else if (xaccSplitGetReconcile (split) == YREC)
1716  xaccSplitSetReconcile (split, NREC);
1717  }
1718  g_list_free (reg->unrecn_splits);
1719  reg->unrecn_splits = NULL;
1720 }
1721 
1722 gboolean
1723 gnc_split_register_save (SplitRegister* reg, gboolean do_commit)
1724 {
1725  SRInfo* info = gnc_split_register_get_info (reg);
1726  Transaction* pending_trans;
1727  Transaction* blank_trans;
1728  Transaction* trans;
1729  Account* account;
1730  Split* blank_split;
1731  const char* memo;
1732  const char* desc;
1733  Split* split;
1734 
1735  ENTER ("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
1736 
1737  if (!reg)
1738  {
1739  LEAVE ("no register");
1740  return FALSE;
1741  }
1742 
1743  blank_split = xaccSplitLookup (&info->blank_split_guid,
1744  gnc_get_current_book ());
1745 
1746  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1747  gnc_get_current_book ());
1748 
1749  blank_trans = xaccSplitGetParent (blank_split);
1750 
1751  /* get the handle to the current split and transaction */
1754  if (trans == NULL)
1755  {
1756  LEAVE ("no transaction");
1757  return FALSE;
1758  }
1759 
1760  /* use the changed flag to avoid heavy-weight updates
1761  * of the split & transaction fields. This will help
1762  * cut down on unnecessary register redraws. */
1763  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1764  {
1765  if (!do_commit)
1766  {
1767  LEAVE ("commit unnecessary");
1768  return FALSE;
1769  }
1770 
1771  if (!xaccTransIsOpen (trans))
1772  {
1773  LEAVE ("transaction not open");
1774  return FALSE;
1775  }
1776 
1777  if (trans == pending_trans ||
1778  (trans == blank_trans && info->blank_split_edited))
1779  {
1780  /* We are going to commit. */
1781 
1782  gnc_suspend_gui_refresh ();
1783 
1784  if (trans == blank_trans)
1785  {
1786  /* We have to clear the blank split before the
1787  * refresh or a new one won't be created. */
1788  info->last_date_entered = xaccTransGetDate (trans);
1789  info->blank_split_guid = *guid_null ();
1790  info->blank_split_edited = FALSE;
1791  info->auto_complete = FALSE;
1792  }
1793 
1794  /* We have to clear the pending guid *before* committing the
1795  * trans, because the event handler will find it otherwise. */
1796  if (trans == pending_trans)
1797  info->pending_trans_guid = *guid_null ();
1798 
1799  PINFO ("committing trans (%p)", trans);
1800  unreconcile_splits (reg);
1801  xaccTransCommitEdit (trans);
1802  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1803 
1804  gnc_resume_gui_refresh ();
1805  }
1806  else
1807  DEBUG ("leaving trans (%p) open", trans);
1808 
1809  LEAVE ("unchanged cursor");
1810  return TRUE;
1811  }
1812 
1813  DEBUG ("save split=%p", split);
1814  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
1815  blank_split, blank_trans, pending_trans, trans);
1816 
1817  /* Act on any changes to the current cell before the save. */
1818  if (!gnc_split_register_check_cell (reg,
1819  gnc_table_get_current_cell_name (reg->table)))
1820  {
1821  LEAVE ("need another go at changing cell");
1822  return FALSE;
1823  }
1824 
1825  if (!gnc_split_register_auto_calc (reg, split))
1826  {
1827  LEAVE ("auto calc failed");
1828  return FALSE;
1829  }
1830 
1831  /* Validate the transfer account names */
1832  (void)gnc_split_register_get_account (reg, MXFRM_CELL);
1833  (void)gnc_split_register_get_account (reg, XFRM_CELL);
1834 
1835  /* Maybe deal with exchange-rate transfers */
1836  if (gnc_split_register_handle_exchange (reg, FALSE))
1837  {
1838  LEAVE ("no exchange rate");
1839  return TRUE;
1840  }
1841 
1842  gnc_suspend_gui_refresh ();
1843 
1844  /* determine whether we should commit the pending transaction */
1845  if (pending_trans != trans)
1846  {
1847  // FIXME: How could the pending transaction not be open?
1848  // FIXME: For that matter, how could an open pending
1849  // transaction ever not be the current trans?
1850  if (xaccTransIsOpen (pending_trans))
1851  {
1852  g_warning ("Impossible? committing pending %p", pending_trans);
1853  unreconcile_splits (reg);
1854  xaccTransCommitEdit (pending_trans);
1855  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1856  }
1857  else if (pending_trans)
1858  {
1859  g_critical ("BUG DETECTED! pending transaction (%p) not open",
1860  pending_trans);
1861  g_assert_not_reached ();
1862  }
1863 
1864  if (trans == blank_trans)
1865  {
1866  /* Don't begin editing the blank trans, because it's
1867  already open, but mark it pending now. */
1868  g_assert (xaccTransIsOpen (blank_trans));
1869  /* This is now the pending transaction */
1870  info->pending_trans_guid = *xaccTransGetGUID (blank_trans);
1871  }
1872  else
1873  {
1874  PINFO ("beginning edit of trans %p", trans);
1875  if (gnc_split_register_begin_edit_or_warn (info, trans))
1876  {
1877  gnc_resume_gui_refresh ();
1878  LEAVE ("transaction opened elsewhere");
1879  return FALSE;
1880  }
1881  }
1882  pending_trans = trans;
1883  }
1884  g_assert (xaccTransIsOpen (trans));
1885 
1886  /* If we are saving a brand new transaction and the blank split hasn't
1887  * been edited, then we need to give it a default account. */
1888  /* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
1889  * even better? What if there were some way that we could be on
1890  * a row other than the transaction row or blank split row, but
1891  * the blank split still hasn't been edited? It seems to be assumed
1892  * that it isn't possible, but... -Charles, Jan 2009 */
1893  if (split == blank_split && !info->blank_split_edited)
1894  {
1895  /* If we've reached this point, it means that the blank split is
1896  * anchoring the transaction - see gnc_split_register_add_transaction ()
1897  * for an explanation - and the transaction has been edited (as evidenced
1898  * by the earlier check for a changed cursor.) Since the blank split
1899  * itself has not been edited, we'll have to assign a default account. */
1900  account = gnc_split_register_get_default_account (reg);
1901  if (account)
1902  xaccSplitSetAccount (blank_split, account);
1903  xaccTransSetDateEnteredSecs (trans, gnc_time (NULL));
1904  }
1905 
1906  if (split == NULL)
1907  {
1908  /* If we were asked to save data for a row for which there is no
1909  * associated split, then assume that this was an "empty" row - see
1910  * gnc_split_register_add_transaction () for an explanation. This row
1911  * is used to add splits to an existing transaction, or to add the
1912  * 2nd through nth split rows to a brand new transaction.
1913  * xaccSRGetCurrent will handle this case, too. We will create
1914  * a new split, copy the row contents to that split, and append
1915  * the split to the pre-existing transaction. */
1916  Split* trans_split;
1917 
1918  split = xaccMallocSplit (gnc_get_current_book ());
1919  xaccTransAppendSplit (trans, split);
1920 
1921  gnc_table_set_virt_cell_data (reg->table,
1922  reg->table->current_cursor_loc.vcell_loc,
1923  xaccSplitGetGUID (split));
1924  DEBUG ("assigned cell to new split=%p", split);
1925 
1926  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
1927  if ((info->cursor_hint_trans == trans) &&
1928  (info->cursor_hint_trans_split == trans_split) &&
1929  (info->cursor_hint_split == NULL))
1930  {
1931  info->cursor_hint_split = split;
1932  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1933  }
1934  }
1935 
1936  DEBUG ("updating trans=%p", trans);
1937 
1938  {
1939  SRSaveData* sd;
1940 
1941  sd = gnc_split_register_save_data_new (
1942  trans, split, (info->trans_expanded ||
1943  reg->style == REG_STYLE_AUTO_LEDGER ||
1944  reg->style == REG_STYLE_JOURNAL));
1945  gnc_table_save_cells (reg->table, sd);
1946  gnc_split_register_save_data_destroy (sd);
1947  }
1948 
1949  memo = xaccSplitGetMemo (split);
1950  memo = memo ? memo : "(null)";
1951  desc = xaccTransGetDescription (trans);
1952  desc = desc ? desc : "(null)";
1953  PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
1954 
1955  /* If the modified split is the "blank split", then it is now an
1956  * official part of the account. Set the blank split to NULL, so we
1957  * can be sure of getting a new blank split. Also, save the date
1958  * for the new blank split. */
1959  if (trans == blank_trans)
1960  {
1961  if (do_commit)
1962  {
1963  info->blank_split_guid = *guid_null ();
1964  info->auto_complete = FALSE;
1965  blank_split = NULL;
1966  info->last_date_entered = xaccTransGetDate (trans);
1967  }
1968  else
1969  info->blank_split_edited = TRUE;
1970  }
1971 
1972  /* If requested, commit the current transaction and set the pending
1973  * transaction to NULL. */
1974  if (do_commit)
1975  {
1976  g_assert (trans == blank_trans || trans == pending_trans);
1977  if (pending_trans == trans)
1978  {
1979  pending_trans = NULL;
1980  info->pending_trans_guid = *guid_null ();
1981  }
1982  unreconcile_splits (reg);
1983  xaccTransCommitEdit (trans);
1984  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1985  }
1986 
1987  gnc_table_clear_current_cursor_changes (reg->table);
1988 
1989  gnc_resume_gui_refresh ();
1990 
1991  LEAVE (" ");
1992  return TRUE;
1993 }
1994 
1995 
1996 Account*
1997 gnc_split_register_get_account_by_name (SplitRegister* reg, BasicCell* bcell,
1998  const char* name)
1999 {
2000  const char* placeholder = _ ("The account %s does not allow transactions.");
2001  const char* missing = _ ("The account %s does not exist. "
2002  "Would you like to create it?");
2003  char* account_name;
2004  ComboCell* cell = (ComboCell*) bcell;
2005  Account* account;
2006  static gboolean creating_account = FALSE;
2007  GtkWindow* parent = GTK_WINDOW (gnc_split_register_get_parent (reg));
2008 
2009  if (!name || (strlen (name) == 0))
2010  return NULL;
2011 
2012  /* Find the account */
2013  account = gnc_account_lookup_for_register (gnc_get_current_root_account (),
2014  name);
2015  if (!account)
2016  account = gnc_account_lookup_by_code (gnc_get_current_root_account (), name);
2017 
2018  /* if gnc_ui_new_accounts_from_name_window is used, there is a call to
2019  * refresh which subsequently calls this function again, that's the
2020  * reason for static creating_account. */
2021 
2022  if (!account && !creating_account)
2023  {
2024  /* Ask if they want to create a new one. */
2025  if (!gnc_verify_dialog (parent, TRUE, missing, name))
2026  return NULL;
2027  creating_account = TRUE;
2028  /* User said yes, they want to create a new account. */
2029  account = gnc_ui_new_accounts_from_name_window (parent, name);
2030  creating_account = FALSE;
2031  if (!account)
2032  return NULL;
2033  }
2034 
2035  if (!creating_account)
2036  {
2037  /* Now have the account. */
2038  account_name = gnc_get_account_name_for_split_register (account,
2039  reg->show_leaf_accounts);
2040  if (g_strcmp0 (account_name, gnc_basic_cell_get_value (bcell)))
2041  {
2042  /* The name has changed. Update the cell. */
2043  gnc_combo_cell_set_value (cell, account_name);
2044  gnc_basic_cell_set_changed (&cell->cell, TRUE);
2045  }
2046  g_free (account_name);
2047 
2048  /* See if the account (either old or new) is a placeholder. */
2049  if (account && xaccAccountGetPlaceholder (account))
2050  {
2051  gchar* fullname = gnc_account_get_full_name (account);
2052  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
2053  placeholder, fullname);
2054  g_free (fullname);
2055  return NULL;
2056  }
2057  }
2058 
2059  /* Be seeing you. */
2060  return account;
2061 }
2062 
2063 Account*
2064 gnc_split_register_get_account (SplitRegister* reg, const char* cell_name)
2065 {
2066  BasicCell* cell;
2067  const char* name;
2068 
2069  if (!gnc_table_layout_get_cell_changed (reg->table->layout, cell_name, TRUE))
2070  return NULL;
2071 
2072  cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
2073  if (!cell)
2074  return NULL;
2075  name = gnc_basic_cell_get_value (cell);
2076  return gnc_split_register_get_account_by_name (reg, cell, name);
2077 }
2078 
2079 static gnc_numeric
2080 calculate_value (SplitRegister* reg)
2081 {
2082  gnc_numeric credit;
2083  gnc_numeric debit;
2084 
2085  PriceCell* cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
2086  CRED_CELL);
2087  credit = gnc_price_cell_get_value (cell);
2088 
2089  cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
2090  DEBT_CELL);
2091  debit = gnc_price_cell_get_value (cell);
2092 
2093  return gnc_numeric_sub_fixed (debit, credit);
2094 }
2095 
2096 
2097 static int
2098 recalc_message_box (SplitRegister* reg, gboolean shares_changed,
2099  gboolean price_changed, gboolean value_changed)
2100 {
2101  int choice;
2102  int default_value;
2103  GList* node;
2104  GList* radio_list = NULL;
2105  const char* title = _ ("Recalculate Transaction");
2106  const char* message = _ ("The values entered for this transaction "
2107  "are inconsistent. Which value would you "
2108  "like to have recalculated?");
2109 
2110  if (shares_changed)
2111  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2112  _ ("_Shares"),
2113  _ ("Changed")));
2114  else
2115  radio_list = g_list_append (radio_list, g_strdup (_ ("_Shares")));
2116 
2117  if (price_changed)
2118  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2119  _ ("_Price"),
2120  _ ("Changed")));
2121  else
2122  radio_list = g_list_append (radio_list, g_strdup (_ ("_Price")));
2123 
2124  if (value_changed)
2125  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2126  _ ("_Value"),
2127  _ ("Changed")));
2128  else
2129  radio_list = g_list_append (radio_list, g_strdup (_ ("_Value")));
2130 
2131  if (price_changed) default_value = 2; /* change the value */
2132  else default_value = 1; /* change the value */
2133 
2134  choice = gnc_choose_radio_option_dialog
2135  (gnc_split_register_get_parent (reg),
2136  title,
2137  message,
2138  _ ("_Recalculate"),
2139  default_value,
2140  radio_list);
2141 
2142  for (node = radio_list; node; node = node->next)
2143  g_free (node->data);
2144 
2145  g_list_free (radio_list);
2146 
2147  return choice;
2148 }
2149 
2150 static void
2151 recalculate_shares (Split* split, SplitRegister* reg,
2152  gnc_numeric value, gnc_numeric price, gboolean value_changed)
2153 {
2154  gint64 denom = gnc_split_get_amount_denom (split);
2155  gnc_numeric amount = gnc_numeric_div (value, price, denom,
2157 
2158  BasicCell* cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
2159  gnc_price_cell_set_value ((PriceCell*) cell, amount);
2160  gnc_basic_cell_set_changed (cell, TRUE);
2161 
2162  if (value_changed)
2163  {
2164  cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
2165  gnc_basic_cell_set_changed (cell, FALSE);
2166  }
2167 }
2168 
2169 static void
2170 recalculate_price (Split* split, SplitRegister* reg,
2171  gnc_numeric value, gnc_numeric amount)
2172 {
2173  BasicCell* price_cell;
2174  gnc_numeric price = gnc_numeric_div (value, amount,
2177 
2178  if (gnc_numeric_negative_p (price))
2179  {
2180  BasicCell* debit_cell;
2181  BasicCell* credit_cell;
2182 
2183  debit_cell = gnc_table_layout_get_cell (reg->table->layout,
2184  DEBT_CELL);
2185 
2186  credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2187  CRED_CELL);
2188 
2189  price = gnc_numeric_neg (price);
2190 
2192  (PriceCell*) credit_cell,
2193  gnc_numeric_neg (value));
2194 
2195  gnc_basic_cell_set_changed (debit_cell, TRUE);
2196  gnc_basic_cell_set_changed (credit_cell, TRUE);
2197  }
2198 
2199  price_cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
2200  gnc_price_cell_set_value ((PriceCell*) price_cell, price);
2201  gnc_basic_cell_set_changed (price_cell, TRUE);
2202 }
2203 
2204 static void
2205 recalculate_value (Split* split, SplitRegister* reg,
2206  gnc_numeric price, gnc_numeric amount, gboolean shares_changed)
2207 {
2208  BasicCell* debit_cell = gnc_table_layout_get_cell (reg->table->layout,
2209  DEBT_CELL);
2210  BasicCell* credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2211  CRED_CELL);
2212  gint64 denom = gnc_split_get_value_denom (split);
2213  gnc_numeric value = gnc_numeric_mul (price, amount, denom,
2215 
2217  (PriceCell*) credit_cell, value);
2218 
2219  gnc_basic_cell_set_changed (debit_cell, TRUE);
2220  gnc_basic_cell_set_changed (credit_cell, TRUE);
2221 
2222  if (shares_changed)
2223  {
2224  BasicCell* cell = gnc_table_layout_get_cell (reg->table->layout,
2225  PRIC_CELL);
2226  gnc_basic_cell_set_changed (cell, FALSE);
2227  }
2228 }
2229 
2230 static gboolean
2231 gnc_split_register_auto_calc (SplitRegister* reg, Split* split)
2232 {
2233  PriceCell* cell = NULL;
2234  gboolean recalc_shares = FALSE;
2235  gboolean recalc_price = FALSE;
2236  gboolean recalc_value = FALSE;
2237  gboolean price_changed;
2238  gboolean value_changed;
2239  gboolean shares_changed;
2240  gnc_numeric calc_value;
2241  gnc_numeric value;
2242  gnc_numeric price;
2243  gnc_numeric amount;
2244  Account* account;
2245  int denom;
2246  int choice;
2247 
2248  if (STOCK_REGISTER != reg->type &&
2249  CURRENCY_REGISTER != reg->type &&
2250  PORTFOLIO_LEDGER != reg->type)
2251  return TRUE;
2252 
2253  account = gnc_split_register_get_account (reg, XFRM_CELL);
2254 
2255  if (!account)
2256  account = xaccSplitGetAccount (split);
2257 
2258  if (!account)
2259  account = gnc_split_register_get_default_account (reg);
2260 
2261  if (!xaccAccountIsPriced (account))
2262  return TRUE;
2263 
2264  price_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2265  PRIC_CELL, TRUE);
2266  value_changed = (gnc_table_layout_get_cell_changed (reg->table->layout,
2267  DEBT_CELL, TRUE) ||
2268  gnc_table_layout_get_cell_changed (reg->table->layout,
2269  CRED_CELL, TRUE));
2270  shares_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2271  SHRS_CELL, TRUE);
2272 
2273  if (!price_changed && !value_changed && !shares_changed)
2274  return TRUE;
2275 
2276  /* If we are using commodity trading accounts then the value may
2277  not really be the value. Punt if so. */
2279  {
2280  gnc_commodity* acc_commodity;
2281  acc_commodity = xaccAccountGetCommodity (account);
2282  if (! (xaccAccountIsPriced (account) ||
2283  !gnc_commodity_is_iso (acc_commodity)))
2284  return TRUE;
2285  }
2286 
2287  if (shares_changed)
2288  {
2289  cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
2290  SHRS_CELL);
2291  amount = gnc_price_cell_get_value (cell);
2292  }
2293  else
2294  amount = xaccSplitGetAmount (split);
2295 
2296  if (price_changed)
2297  {
2298  cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
2299  PRIC_CELL);
2300  price = gnc_price_cell_get_value (cell);
2301  }
2302  else
2303  price = xaccSplitGetSharePrice (split);
2304 
2305  if (value_changed)
2306  value = calculate_value (reg);
2307  else
2308  value = xaccSplitGetValue (split);
2309 
2310 
2311  /* Check if shares and price are BOTH zero (and value is non-zero).
2312  * If so, we can assume that this is an income-correcting split
2313  */
2314  if (gnc_numeric_zero_p (amount) && gnc_numeric_zero_p (price) &&
2315  !gnc_numeric_zero_p (value))
2316  {
2317  return TRUE;
2318  }
2319 
2320  /* Check if precisely one value is zero. If so, we can assume that the
2321  * zero value needs to be recalculated. */
2322 
2323  if (!gnc_numeric_zero_p (amount))
2324  {
2325  if (gnc_numeric_zero_p (price))
2326  {
2327  if (!gnc_numeric_zero_p (value))
2328  recalc_price = TRUE;
2329  }
2330  else if (gnc_numeric_zero_p (value))
2331  recalc_value = TRUE;
2332  }
2333  else if (!gnc_numeric_zero_p (price))
2334  if (!gnc_numeric_zero_p (value))
2335  recalc_shares = TRUE;
2336 
2337  /* If we have not already flagged a recalc, check if this is a split
2338  * which has 2 of the 3 values changed. */
2339 
2340  if ((!recalc_shares) &&
2341  (!recalc_price) &&
2342  (!recalc_value))
2343  {
2344  if (price_changed && value_changed)
2345  {
2346  if (!shares_changed)
2347  recalc_shares = TRUE;
2348  }
2349  else if (value_changed && shares_changed)
2350  recalc_price = TRUE;
2351  else if (price_changed && shares_changed)
2352  recalc_value = TRUE;
2353  }
2354 
2355  calc_value = gnc_numeric_mul (price, amount,
2357 
2358  denom = gnc_split_get_value_denom (split);
2359 
2360  /* Now, if we have not flagged one of the recalcs, and value and
2361  * calc_value are not the same number, then we need to ask for
2362  * help from the user. */
2363 
2364  if (!recalc_shares &&
2365  !recalc_price &&
2366  !recalc_value &&
2367  !gnc_numeric_same (value, calc_value, denom, GNC_HOW_RND_ROUND_HALF_UP))
2368  {
2369  choice = recalc_message_box (reg, shares_changed,
2370  price_changed,
2371  value_changed);
2372  switch (choice)
2373  {
2374  case 0: /* Modify number of shares */
2375  recalc_shares = TRUE;
2376  break;
2377  case 1: /* Modify the share price */
2378  recalc_price = TRUE;
2379  break;
2380  case 2: /* Modify total value */
2381  recalc_value = TRUE;
2382  break;
2383  default: /* Cancel */
2384  return FALSE;
2385  }
2386  }
2387 
2388  if (recalc_shares && !gnc_numeric_zero_p (price))
2389  recalculate_shares (split, reg, value, price, value_changed);
2390 
2391  if (recalc_price && !gnc_numeric_zero_p (amount))
2392  {
2393  recalculate_price (split, reg, value, amount);
2394  price_changed = TRUE;
2395  }
2396  if (recalc_value)
2397  recalculate_value (split, reg, price, amount, shares_changed);
2398 
2399  return TRUE;
2400 }
2401 
2402 static GNCAccountType
2403 gnc_split_register_type_to_account_type (SplitRegisterType sr_type)
2404 {
2405  switch (sr_type)
2406  {
2407  case BANK_REGISTER:
2408  return ACCT_TYPE_BANK;
2409  case CASH_REGISTER:
2410  return ACCT_TYPE_CASH;
2411  case ASSET_REGISTER:
2412  return ACCT_TYPE_ASSET;
2413  case CREDIT_REGISTER:
2414  return ACCT_TYPE_CREDIT;
2415  case LIABILITY_REGISTER:
2416  return ACCT_TYPE_LIABILITY;
2417  case PAYABLE_REGISTER:
2418  return ACCT_TYPE_PAYABLE;
2419  case RECEIVABLE_REGISTER:
2420  return ACCT_TYPE_RECEIVABLE;
2421  case INCOME_LEDGER:
2422  case INCOME_REGISTER:
2423  return ACCT_TYPE_INCOME;
2424  case EXPENSE_REGISTER:
2425  return ACCT_TYPE_EXPENSE;
2426  case STOCK_REGISTER:
2427  case PORTFOLIO_LEDGER:
2428  return ACCT_TYPE_STOCK;
2429  case CURRENCY_REGISTER:
2430  return ACCT_TYPE_CURRENCY;
2431  case TRADING_REGISTER:
2432  return ACCT_TYPE_TRADING;
2433  case GENERAL_JOURNAL:
2434  return ACCT_TYPE_NONE;
2435  case EQUITY_REGISTER:
2436  return ACCT_TYPE_EQUITY;
2437  case SEARCH_LEDGER:
2438  return ACCT_TYPE_NONE;
2439  default:
2440  return ACCT_TYPE_NONE;
2441  }
2442 }
2443 
2444 const char*
2446 {
2447  SRInfo* info = gnc_split_register_get_info (reg);
2448 
2449  if (!reg)
2450  return NULL;
2451 
2452  if (info->debit_str)
2453  return info->debit_str;
2454 
2455  info->debit_str =
2457  (gnc_split_register_type_to_account_type (reg->type));
2458 
2459  if (info->debit_str)
2460  return info->debit_str;
2461 
2462  info->debit_str = g_strdup (_ ("Debit"));
2463 
2464  return info->debit_str;
2465 }
2466 
2467 const char*
2469 {
2470  SRInfo* info = gnc_split_register_get_info (reg);
2471 
2472  if (!reg)
2473  return NULL;
2474 
2475  if (info->credit_str)
2476  return info->credit_str;
2477 
2478  info->credit_str =
2480  (gnc_split_register_type_to_account_type (reg->type));
2481 
2482  if (info->credit_str)
2483  return info->credit_str;
2484 
2485  info->credit_str = g_strdup (_ ("Credit"));
2486 
2487  return info->credit_str;
2488 }
2489 
2490 gboolean
2491 gnc_split_register_changed (SplitRegister* reg)
2492 {
2493  SRInfo* info = gnc_split_register_get_info (reg);
2494  Transaction* pending_trans;
2495 
2496  ENTER ("reg=%p", reg);
2497 
2498  if (reg == NULL)
2499  {
2500  LEAVE ("no register");
2501  return FALSE;
2502  }
2503 
2504  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2505  {
2506  LEAVE ("cursor changed");
2507  return TRUE;
2508  }
2509 
2510  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2511  gnc_get_current_book ());
2512  if (xaccTransIsOpen (pending_trans))
2513  {
2514  LEAVE ("open and pending txn");
2515  return TRUE;
2516  }
2517 
2518  LEAVE ("register unchanged");
2519  return FALSE;
2520 }
2521 
2522 void
2524  gboolean show_present)
2525 {
2526  SRInfo* info = gnc_split_register_get_info (reg);
2527 
2528  if (reg == NULL)
2529  return;
2530 
2531  info->show_present_divider = show_present;
2532 }
2533 
2534 gboolean
2536 {
2537  SRInfo* info = gnc_split_register_get_info (reg);
2538 
2539  if (!info)
2540  return FALSE;
2541 
2542  return info->full_refresh;
2543 }
2544 
2545 /* configAction strings into the action cell */
2546 /* hack alert -- this stuff really, really should be in a config file ... */
2547 static void
2548 gnc_split_register_config_action (SplitRegister* reg)
2549 {
2550  ComboCell* cell;
2551 
2552  cell = (ComboCell*) gnc_table_layout_get_cell (reg->table->layout,
2553  ACTN_CELL);
2554 
2555  /* setup strings in the action pull-down */
2556  switch (reg->type)
2557  {
2558  case BANK_REGISTER:
2559  /* broken ! FIXME bg */
2560  case SEARCH_LEDGER:
2561  gnc_combo_cell_add_menu_item (cell, C_ ("Action Column", "Deposit"));
2562  gnc_combo_cell_add_menu_item (cell, _ ("Withdraw"));
2563  gnc_combo_cell_add_menu_item (cell, _ ("Check"));
2564  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2565  gnc_combo_cell_add_menu_item (cell, _ ("ATM Deposit"));
2566  gnc_combo_cell_add_menu_item (cell, _ ("ATM Draw"));
2567  gnc_combo_cell_add_menu_item (cell, _ ("Teller"));
2568  gnc_combo_cell_add_menu_item (cell, _ ("Charge"));
2569  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2570  gnc_combo_cell_add_menu_item (cell, _ ("Receipt"));
2571  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2572  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2573  /* Action: Point Of Sale */
2574  gnc_combo_cell_add_menu_item (cell, _ ("POS"));
2575  gnc_combo_cell_add_menu_item (cell, _ ("Phone"));
2576  gnc_combo_cell_add_menu_item (cell, _ ("Online"));
2577  /* Action: Automatic Deposit ?!? */
2578  gnc_combo_cell_add_menu_item (cell, _ ("AutoDep"));
2579  gnc_combo_cell_add_menu_item (cell, _ ("Wire"));
2580  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2581  gnc_combo_cell_add_menu_item (cell, _ ("Direct Debit"));
2582  gnc_combo_cell_add_menu_item (cell, _ ("Transfer"));
2583  break;
2584  case CASH_REGISTER:
2585  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2586  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2587  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2588  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2589  break;
2590  case ASSET_REGISTER:
2591  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2592  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2593  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2594  break;
2595  case CREDIT_REGISTER:
2596  gnc_combo_cell_add_menu_item (cell, _ ("ATM Deposit"));
2597  gnc_combo_cell_add_menu_item (cell, _ ("ATM Draw"));
2598  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2599  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2600  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2601  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2602  gnc_combo_cell_add_menu_item (cell, _ ("Online"));
2603  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2604  break;
2605  case LIABILITY_REGISTER:
2606  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2607  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2608  gnc_combo_cell_add_menu_item (cell, _ ("Loan"));
2609  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2610  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2611  break;
2612  case RECEIVABLE_REGISTER:
2613  case PAYABLE_REGISTER:
2614  gnc_combo_cell_add_menu_item (cell, _ ("Invoice"));
2615  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2616  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2617  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2618  break;
2619  case INCOME_LEDGER:
2620  case INCOME_REGISTER:
2621  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2622  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2623  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2624  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2625  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2626  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2627  gnc_combo_cell_add_menu_item (cell, _ ("Rebate"));
2628  gnc_combo_cell_add_menu_item (cell, _ ("Paycheck"));
2629  break;
2630  case EXPENSE_REGISTER:
2631  case TRADING_REGISTER:
2632  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2633  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2634  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2635  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2636  break;
2637  case GENERAL_JOURNAL:
2638  case EQUITY_REGISTER:
2639  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2640  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2641  gnc_combo_cell_add_menu_item (cell, _ ("Equity"));
2642  break;
2643  case STOCK_REGISTER:
2644  case PORTFOLIO_LEDGER:
2645  case CURRENCY_REGISTER:
2646  gnc_combo_cell_add_menu_item (cell, ACTION_BUY_STR);
2647  gnc_combo_cell_add_menu_item (cell, ACTION_SELL_STR);
2648  gnc_combo_cell_add_menu_item (cell, _ ("Price"));
2649  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2650  /* Action: Dividend */
2651  gnc_combo_cell_add_menu_item (cell, _ ("Dividend"));
2652  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2653  /* Action: Long Term Capital Gains */
2654  gnc_combo_cell_add_menu_item (cell, _ ("LTCG"));
2655  /* Action: Short Term Capital Gains */
2656  gnc_combo_cell_add_menu_item (cell, _ ("STCG"));
2657  gnc_combo_cell_add_menu_item (cell, _ ("Income"));
2658  /* Action: Distribution */
2659  gnc_combo_cell_add_menu_item (cell, _ ("Dist"));
2660  gnc_combo_cell_add_menu_item (cell, C_ ("Action Column", "Split"));
2661  break;
2662 
2663  default:
2664  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2665  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2666  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2667  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2668  break;
2669  }
2670 }
2671 
2672 static void
2673 gnc_split_register_config_cells (SplitRegister* reg)
2674 {
2676  ((ComboCell*)
2677  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2678  SPLIT_TRANS_STR);
2679 
2681  ((ComboCell*)
2682  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2683  STOCK_SPLIT_STR);
2684 
2685  /* the action cell */
2687  ((ComboCell*)
2688  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), TRUE);
2689 
2690  /* the description cell */
2692  ((CompletionCell*)
2693  gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), TRUE);
2694 
2695  /* Use GNC_COMMODITY_MAX_FRACTION for prices and "exchange rates" */
2697  ((PriceCell*)
2698  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
2700 
2701  /* Initialize shares and share balance cells */
2703  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL),
2704  gnc_default_share_print_info ());
2705 
2707  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, TSHRS_CELL),
2708  gnc_default_share_print_info ());
2709 
2710  /* Initialize the rate cell
2711  * use a share_print_info to make sure we don't have rounding errors
2712  */
2714  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL),
2715  gnc_default_share_print_info ());
2716 
2717  /* The action cell should accept strings not in the list */
2719  ((ComboCell*)
2720  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), FALSE);
2721 
2722  /* The description cell should accept strings not in the list */
2724  ((CompletionCell*)
2725  gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), FALSE);
2726 
2727  /* number format for share quantities in stock ledgers */
2728  switch (reg->type)
2729  {
2730  case CURRENCY_REGISTER:
2731  case STOCK_REGISTER:
2732  case PORTFOLIO_LEDGER:
2734  ((PriceCell*)
2735  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
2736  gnc_default_price_print_info (gnc_default_currency ()));
2737  break;
2738 
2739  default:
2740  break;
2741  }
2742 
2743  /* add menu items for the action cell */
2744  gnc_split_register_config_action (reg);
2745 }
2746 
2747 static void
2748 split_register_pref_changed (gpointer prefs, gchar* pref, gpointer user_data)
2749 {
2750  SplitRegister* reg = user_data;
2751  SRInfo* info;
2752 
2753  g_return_if_fail (pref);
2754  if (reg == NULL)
2755  return;
2756 
2757  info = reg->sr_info;
2758  if (!info)
2759  return;
2760 
2761  if (g_str_has_suffix (pref, GNC_PREF_ACCOUNTING_LABELS))
2762  {
2763  /* Release current strings. Will be reloaded at next reference. */
2764  g_free (info->tdebit_str);
2765  g_free (info->tcredit_str);
2766 
2767  info->debit_str = NULL;
2768  info->tdebit_str = NULL;
2769  info->credit_str = NULL;
2770  info->tcredit_str = NULL;
2771 
2772  }
2773  else if (g_str_has_suffix (pref, GNC_PREF_ACCOUNT_SEPARATOR))
2774  {
2775  info->separator_changed = TRUE;
2776  }
2777  else if (g_str_has_suffix (pref, GNC_PREF_SHOW_LEAF_ACCT_NAMES))
2778  {
2779  reg->show_leaf_accounts = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2780  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
2781  }
2782  else if (g_str_has_suffix (pref, GNC_PREF_ALT_COLOR_BY_TRANS))
2783  {
2784  reg->double_alt_color = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2785  GNC_PREF_ALT_COLOR_BY_TRANS);
2786  }
2787  else
2788  {
2789  g_warning ("split_register_pref_changed: Unknown preference %s", pref);
2790  }
2791 }
2792 
2793 static void
2794 split_register_book_option_changed (gpointer new_val, gpointer user_data)
2795 {
2796  SplitRegister* reg = user_data;
2797  gboolean* new_data = (gboolean*)new_val;
2798 
2799  if (reg == NULL)
2800  return;
2801 
2802  reg->use_tran_num_for_num_field = (*new_data ? FALSE : TRUE);
2803 }
2804 
2805 static void
2806 gnc_split_register_init (SplitRegister* reg,
2807  SplitRegisterType type,
2808  SplitRegisterStyle style,
2809  gboolean use_double_line,
2810  gboolean do_auto_complete,
2811  gboolean is_template,
2812  gboolean mismatched_commodities)
2813 {
2814  TableLayout* layout;
2815  TableModel* model;
2816  TableControl* control;
2817 
2818  /* Register 'destroy' callback */
2819  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2820  GNC_PREF_ACCOUNTING_LABELS,
2821  split_register_pref_changed,
2822  reg);
2823  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2824  GNC_PREF_ACCOUNT_SEPARATOR,
2825  split_register_pref_changed,
2826  reg);
2827  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
2828  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
2829  split_register_pref_changed,
2830  reg);
2831  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
2832  GNC_PREF_ALT_COLOR_BY_TRANS,
2833  split_register_pref_changed,
2834  reg);
2835  gnc_book_option_register_cb (OPTION_NAME_NUM_FIELD_SOURCE,
2836  split_register_book_option_changed,
2837  reg);
2838 
2839  reg->sr_info = NULL;
2840 
2841  reg->unrecn_splits = NULL;
2842 
2843  reg->show_leaf_accounts = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2844  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
2845  reg->double_alt_color = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2846  GNC_PREF_ALT_COLOR_BY_TRANS);
2847 
2848  reg->type = type;
2849  reg->style = style;
2850  reg->use_double_line = use_double_line;
2851  reg->do_auto_complete = do_auto_complete;
2852  reg->is_template = is_template;
2853  reg->mismatched_commodities = mismatched_commodities;
2854  reg->use_tran_num_for_num_field =
2855  (qof_book_use_split_action_for_num_field (gnc_get_current_book ())
2856  ? FALSE : TRUE);
2857 
2858  layout = gnc_split_register_layout_new (reg);
2859 
2860  if (is_template)
2861  model = gnc_template_register_model_new ();
2862  else
2863  model = gnc_split_register_model_new ();
2864  model->handler_user_data = reg;
2865 
2866  control = gnc_split_register_control_new ();
2867  control->user_data = reg;
2868 
2869  reg->table = gnc_table_new (layout, model, control);
2870 
2871  gnc_split_register_config_cells (reg);
2872 
2873  /* Set up header */
2874  {
2875  VirtualCellLocation vcell_loc = { 0, 0 };
2876  CellBlock* header;
2877 
2878  header = gnc_table_layout_get_cursor (reg->table->layout, CURSOR_HEADER);
2879 
2880  gnc_table_set_vcell (reg->table, header, NULL, TRUE, TRUE, vcell_loc);
2881  }
2882 
2883  /* Set up first and only initial row */
2884  {
2885  VirtualLocation vloc;
2886  CellBlock* cursor;
2887 
2888  vloc.vcell_loc.virt_row = 1;
2889  vloc.vcell_loc.virt_col = 0;
2890  vloc.phys_row_offset = 0;
2891  vloc.phys_col_offset = 0;
2892 
2893  cursor = gnc_table_layout_get_cursor (reg->table->layout,
2894  CURSOR_SINGLE_LEDGER);
2895 
2896  gnc_table_set_vcell (reg->table, cursor, NULL, TRUE, TRUE, vloc.vcell_loc);
2897 
2898  if (gnc_table_find_close_valid_cell (reg->table, &vloc, FALSE))
2899  gnc_table_move_cursor (reg->table, vloc);
2900  else
2901  {
2902  PERR ("Can't find valid initial location");
2903  }
2904  }
2905 }
2906 
2907 SplitRegister*
2909  SplitRegisterStyle style,
2910  gboolean use_double_line,
2911  gboolean is_template,
2912  gboolean mismatched_commodities)
2913 {
2914  SplitRegister* reg;
2915  gboolean default_do_auto_complete = TRUE;
2916 
2917  reg = g_new0 (SplitRegister, 1);
2918 
2919  if (type >= NUM_SINGLE_REGISTER_TYPES)
2920  style = REG_STYLE_JOURNAL;
2921 
2922  gnc_split_register_init (reg,
2923  type,
2924  style,
2925  use_double_line,
2926  default_do_auto_complete,
2927  is_template,
2928  mismatched_commodities);
2929 
2930  return reg;
2931 }
2932 
2933 void
2934 gnc_split_register_config (SplitRegister* reg,
2935  SplitRegisterType newtype,
2936  SplitRegisterStyle newstyle,
2937  gboolean use_double_line)
2938 {
2939  if (!reg) return;
2940 
2941  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2942  if (reg->use_double_line && !use_double_line)
2943  {
2944  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2945  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
2946  {
2947  if (virt_loc.phys_row_offset)
2948  {
2949  gnc_table_move_vertical_position (reg->table, &virt_loc,
2950  -virt_loc.phys_row_offset);
2951  gnc_table_move_cursor_gui (reg->table, virt_loc);
2952  }
2953  }
2954  else
2955  {
2956  /* WTF? Go to a known safe location. */
2957  virt_loc.vcell_loc.virt_row = 1;
2958  virt_loc.vcell_loc.virt_col = 0;
2959  virt_loc.phys_row_offset = 0;
2960  virt_loc.phys_col_offset = 0;
2961  gnc_table_move_cursor_gui (reg->table, virt_loc);
2962  }
2963  }
2964 
2965  reg->type = newtype;
2966 
2967  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
2968  newstyle = REG_STYLE_JOURNAL;
2969 
2970  reg->style = newstyle;
2971  reg->use_double_line = use_double_line;
2972 
2973  gnc_table_realize_gui (reg->table);
2974 }
2975 
2976 void
2977 gnc_split_register_set_reverse_sort (SplitRegister* reg, gboolean reverse_sort)
2978 {
2979  g_return_if_fail (reg);
2980  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
2981 }
2982 
2983 void
2985  gboolean do_auto_complete)
2986 {
2987  g_return_if_fail (reg);
2988  reg->do_auto_complete = do_auto_complete;
2989 }
2990 
2991 static void
2992 gnc_split_register_destroy_info (SplitRegister* reg)
2993 {
2994  SRInfo* info;
2995 
2996  if (reg == NULL)
2997  return;
2998 
2999  if (reg->unrecn_splits != NULL)
3000  {
3001  g_list_free (reg->unrecn_splits);
3002  reg->unrecn_splits = NULL;
3003  }
3004 
3005  info = reg->sr_info;
3006  if (!info)
3007  return;
3008 
3009  g_free (info->tdebit_str);
3010  g_free (info->tcredit_str);
3011 
3012  info->debit_str = NULL;
3013  info->tdebit_str = NULL;
3014  info->credit_str = NULL;
3015  info->tcredit_str = NULL;
3016 
3017  g_free (reg->sr_info);
3018 
3019  reg->sr_info = NULL;
3020 }
3021 
3022 void
3023 gnc_split_register_set_data (SplitRegister* reg, void* user_data,
3024  SRGetParentCallback get_parent)
3025 {
3026  SRInfo* info = gnc_split_register_get_info (reg);
3027 
3028  g_return_if_fail (reg != NULL);
3029 
3030  info->user_data = user_data;
3031  info->get_parent = get_parent;
3032 }
3033 
3034 static void
3035 gnc_split_register_cleanup (SplitRegister* reg)
3036 {
3037  SRInfo* info = gnc_split_register_get_info (reg);
3038  Transaction* pending_trans;
3039  Transaction* blank_trans = NULL;
3040  Split* blank_split;
3041 
3042  ENTER ("reg=%p", reg);
3043 
3044  blank_split = xaccSplitLookup (&info->blank_split_guid,
3045  gnc_get_current_book ());
3046 
3047  pending_trans = xaccTransLookup (&info->pending_trans_guid,
3048  gnc_get_current_book ());
3049 
3050  gnc_suspend_gui_refresh ();
3051 
3052  /* Destroy the transaction containing the "blank split", which was only
3053  * created to support the area for entering a new transaction. Since the
3054  * register is closing, this transaction is no longer needed. */
3055  if (blank_split != NULL)
3056  {
3057  gboolean was_open;
3058 
3059  blank_trans = xaccSplitGetParent (blank_split);
3060 
3061  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
3062  blank_split, blank_trans, pending_trans);
3063 
3064  /* Destroying the transaction will automatically remove its splits. */
3065  was_open = xaccTransIsOpen (blank_trans);
3066  xaccTransDestroy (blank_trans);
3067  if (was_open)
3068  xaccTransCommitEdit (blank_trans);
3069 
3070  /* Update the register info. */
3071  if (blank_trans == pending_trans)
3072  {
3073  info->pending_trans_guid = *guid_null ();
3074  pending_trans = NULL;
3075  }
3076  info->blank_split_guid = *guid_null ();
3077  info->auto_complete = FALSE;
3078  blank_split = NULL;
3079  }
3080 
3081  /* be sure to take care of any open transactions */
3082  if (pending_trans != NULL)
3083  {
3084  g_critical ("BUG DETECTED: pending_trans=%p, blank_split=%p, blank_trans=%p",
3085  pending_trans, blank_split, blank_trans);
3086  g_assert_not_reached ();
3087  info->pending_trans_guid = *guid_null ();
3088  /* CAS: It's not clear to me that we'd really want to commit
3089  here, rather than rollback. But, maybe this is just dead
3090  code. */
3091  if (xaccTransIsOpen (pending_trans))
3092  xaccTransCommitEdit (pending_trans);
3093  else g_assert_not_reached ();
3094 
3095  pending_trans = NULL;
3096  }
3097 
3098  gnc_split_register_destroy_info (reg);
3099 
3100  gnc_resume_gui_refresh ();
3101 
3102  LEAVE (" ");
3103 }
3104 
3105 void
3106 gnc_split_register_destroy (SplitRegister* reg)
3107 {
3108  g_return_if_fail (reg);
3109 
3110  ENTER ("reg=%p", reg);
3111 
3112  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3113  GNC_PREF_ACCOUNTING_LABELS,
3114  split_register_pref_changed,
3115  reg);
3116  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3117  GNC_PREF_ACCOUNT_SEPARATOR,
3118  split_register_pref_changed,
3119  reg);
3120  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3121  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3122  split_register_pref_changed,
3123  reg);
3124  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3125  GNC_PREF_ALT_COLOR_BY_TRANS,
3126  split_register_pref_changed,
3127  reg);
3128  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3129  split_register_book_option_changed,
3130  reg);
3131 
3132  gnc_split_register_cleanup (reg);
3133 
3134  gnc_table_destroy (reg->table);
3135  reg->table = NULL;
3136 
3137  /* free the memory itself */
3138  g_free (reg);
3139  LEAVE (" ");
3140 }
3141 
3142 void
3143 gnc_split_register_set_read_only (SplitRegister* reg, gboolean read_only)
3144 {
3145  gnc_table_model_set_read_only (reg->table->model, read_only);
3146 }
3147 
3150 {
3151  switch (reg->type)
3152  {
3153  case BANK_REGISTER:
3154  case CASH_REGISTER:
3155  case ASSET_REGISTER:
3156  case CREDIT_REGISTER:
3157  case LIABILITY_REGISTER:
3158  case INCOME_REGISTER:
3159  case EXPENSE_REGISTER:
3160  case EQUITY_REGISTER:
3161  case TRADING_REGISTER:
3162  {
3163  return REG_TYPE_GROUP_CURRENCY;
3164  break;
3165  }
3166  case PAYABLE_REGISTER:
3167  case RECEIVABLE_REGISTER:
3168  {
3169  return REG_TYPE_GROUP_APAR;
3170  break;
3171  }
3172  case INCOME_LEDGER:
3173  case GENERAL_JOURNAL:
3174  case SEARCH_LEDGER:
3175  {
3176  return REG_TYPE_GROUP_JOURNAL;
3177  break;
3178  }
3179  case STOCK_REGISTER:
3180  case CURRENCY_REGISTER:
3181  {
3182  return REG_TYPE_GROUP_STOCK;
3183  break;
3184  }
3185  case PORTFOLIO_LEDGER:
3186  {
3187  return REG_TYPE_GROUP_PORTFOLIO;
3188  break;
3189  }
3190  default:
3191  return REG_TYPE_GROUP_UNKNOWN;
3192  PERR ("unknown register type %d\n", reg->type);
3193  break;
3194  }
3195 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;s current cursor.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
void gnc_copy_trans_onto_trans(Transaction *from, Transaction *to, gboolean use_cut_semantics, gboolean do_commit)
Private function – outsiders must not use this.
Public declarations for GncLedgerDisplay class.
The RecnCell object implements a cell handler that will cycle through a series of single-character va...
Definition: recncell.h:47
gpointer vcell_data
Array of physical cells.
Definition: table-allgui.h:135
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:381
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
The CompletionCell object implements a cell handler with a "combination-box" pull-down menu in it...
const char * gnc_split_register_get_credit_string(SplitRegister *reg)
Return the credit string used in the register.
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4638
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
void gnc_split_register_set_reverse_sort(SplitRegister *reg, gboolean reverse_sort)
Sets a split register&#39;s reverse sort order based on register.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Account * gnc_ui_new_accounts_from_name_window(GtkWindow *parent, const char *name)
Display a modal window for creating a new account.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Date and Time handling routines.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.
Definition: gnc-prefs.c:128
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
This file contains the functions to present a gui to the user for creating a new account or editing a...
void gnc_split_register_destroy(SplitRegister *reg)
Destroys a split register.
void gnc_split_register_unvoid_current_trans(SplitRegister *reg)
Unvoids the transaction associated with the current cursor, if non-NULL.
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false. ...
Definition: Account.cpp:4506
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
Expand the current transaction if it is collapsed.
Expense accounts are used to denote expenses.
Definition: Account.h:143
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
void gnc_split_register_set_trans_visible(SplitRegister *reg, VirtualCellLocation vcell_loc, gboolean visible, gboolean only_blank_split)
Set the visibility of the split rows belonging to a transaction located at vcell_loc.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1472
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2716
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
STRUCTS.
SplitRegisterTypeGroup gnc_split_register_get_register_group(SplitRegister *reg)
Group registers for common layouts.
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
holds information about each virtual cell.
Definition: table-allgui.h:132
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
TableControl specialized for the SplitRegister.
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
gboolean gnc_split_register_full_refresh_ok(SplitRegister *reg)
Private function – outsiders must not use this.
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_set_num_action&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
Save handlers for the SplitRegister Model and Template SplitRegister model.
void xaccTransRecordPrice(Transaction *trans, PriceSource source)
The xaccTransRecordPrice() method iterates through the splits and and record the non-currency equival...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
TableModels specialized for SplitRegister and template SplitRegister.
Use any denominator which gives an exactly correct ratio of numerator to denominator.
Definition: gnc-numeric.h:188
Create the actual register visual layout.
void gnc_split_register_set_data(SplitRegister *reg, gpointer user_data, SRGetParentCallback get_parent)
Sets the user data and callback hooks for the register.
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL. ...
SplitRegisterTypeGroup
Register group types.
void gnc_split_register_set_read_only(SplitRegister *reg, gboolean read_only)
Sets whether a register window is "read only".
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition: Account.h:110
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4046
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition: qofutil.cpp:187
void gnc_combo_cell_add_ignore_string(ComboCell *cell, const char *ignore_string)
Add a string to a list of strings which, if the cell has that value, will cause the cell to be unedit...
void gnc_table_set_virt_cell_data(Table *table, VirtualCellLocation vcell_loc, gconstpointer vcell_data)
Set the virtual cell data for a particular location.
Definition: table-allgui.c:700
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition: Account.cpp:4647
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
#define VREC
split is void
Definition: Split.h:77
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Account used to record multiple commodity transactions.
Definition: Account.h:155
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
Stock accounts will typically be shown in registers which show three columns: price, number of shares, and value.
Definition: Account.h:122
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:988
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition: Account.cpp:3275
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
const char * gnc_split_register_get_debit_string(SplitRegister *reg)
Return the debit string used in the register.
Find the least common multiple of the arguments&#39; denominators and use that as the denominator of the ...
Definition: gnc-numeric.h:200
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
Definition: combocell.h:52
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
CursorClass
Types of cursors.
Income accounts are used to denote income.
Definition: Account.h:140
#define YREC
The Split has been reconciled.
Definition: Split.h:74
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
The gnc_account_lookup_by_code() subroutine works like gnc_account_lookup_by_name, but uses the account code.
Definition: Account.cpp:3076
char * gnc_get_account_name_for_split_register(const Account *account, gboolean show_leaf_accounts)
Get either the full name of the account or the simple name, depending on the show_leaf_accounts.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
void gnc_split_register_cut_current(SplitRegister *reg)
Equivalent to copying the current entity and the deleting it with the appropriate delete method...
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:54
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
Add a menu item to the list.
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
gboolean gnc_split_register_changed(SplitRegister *reg)
Returns TRUE if the register has changed cells.
void gnc_combo_cell_set_strict(ComboCell *cell, gboolean strict)
Determines whether the cell will accept strings not in the menu.
The bank account type denotes a savings or checking account held at a bank.
Definition: Account.h:107
void gnc_split_register_config(SplitRegister *reg, SplitRegisterType newtype, SplitRegisterStyle newstyle, gboolean use_double_line)
Sets a split register&#39;s type, style or line use.
private declarations for SplitRegister
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void gnc_split_register_void_current_trans(SplitRegister *reg, const char *reason)
Voids the transaction associated with the current cursor, if non-NULL.
TableControl * gnc_split_register_control_new(void)
Create a new TableControl specialized for the SplitRegister.
void gnc_table_set_vcell(Table *table, CellBlock *cursor, gconstpointer vcell_data, gboolean visible, gboolean start_primary_color, VirtualCellLocation vcell_loc)
Indicate what handler should be used for a given virtual block.
Definition: table-allgui.c:664
A/P account type.
Definition: Account.h:151
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
Definition: Split.h:552
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition: Account.cpp:1668
gboolean gnc_split_register_get_split_amount_virt_loc(SplitRegister *reg, Split *split, VirtualLocation *virt_loc)
Searches the split register for the given split and determines the location of either its credit (if ...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
asset (and liability) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:116
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition: Split.cpp:1932
gboolean gnc_table_move_vertical_position(Table *table, VirtualLocation *virt_loc, int phys_row_offset)
Moves away from virtual location virt_loc by phys_row_offset physical rows.
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
API for checkbook register display area.
The currency account type indicates that the account is a currency trading account.
Definition: Account.h:129
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed...
Definition: Account.h:101
void gnc_price_cell_set_fraction(PriceCell *cell, int fraction)
Sets the fraction used for rounding.
Definition: pricecell.c:242
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
gboolean gnc_split_register_is_blank_split(SplitRegister *reg, Split *split)
Return TRUE if split is the blank_split.
Account * gnc_account_lookup_for_register(const Account *base_account, const char *name)
Retrieve the account matching the given name starting from the descendants of base_account.
#define xaccTransGetGUID(X)
Definition: Transaction.h:788
Generic api to store and retrieve preferences.
Split * gnc_split_register_duplicate_current(SplitRegister *reg)
Duplicates either the current transaction or the current split depending on the register mode and cur...
void gnc_split_register_cancel_cursor_trans_changes(SplitRegister *reg)
Cancels any changes made to the current pending transaction, reloads the table from the engine...
The NumCell object implements a number handling cell.
Definition: numcell.h:39
void gnc_split_register_paste_current(SplitRegister *reg)
Pastes a previous copied entity onto the current entity, but only if the copied and current entity ha...
unsigned int visible
Used by higher-level code.
Definition: table-allgui.h:138
void gnc_price_cell_set_print_info(PriceCell *cell, GNCPrintAmountInfo print_info)
set the printing context of the price cell
Definition: pricecell.c:272
liability (and asset) accounts indicate generic, generalized accounts that are none of the above...
Definition: Account.h:119
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4058
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1250
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3371
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
void gnc_completion_cell_set_strict(CompletionCell *cell, gboolean strict)
Determines whether the cell will accept strings not in the menu.
void gnc_split_register_empty_current_trans_except_split(SplitRegister *reg, Split *split)
Deletes the non-transaction splits associated with the current cursor, if both are non-NULL...
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void gnc_split_register_set_auto_complete(SplitRegister *reg, gboolean do_auto_complete)
Sets whether a register uses auto-completion.
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4074
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
Definition: table-allgui.c:737
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Declarations for the Table object.
A/R account type.
Definition: Account.h:149
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
GtkWidget *(* SRGetParentCallback)(gpointer user_data)
Callback function type.
Round to the nearest integer, rounding away from zero when there are two equidistant nearest integers...
Definition: gnc-numeric.h:165
gboolean gnc_price_cell_set_value(PriceCell *cell, gnc_numeric amount)
updates amount, returns TRUE if string representation actually changed
Definition: pricecell.c:219
void gnc_completion_cell_set_autosize(CompletionCell *cell, gboolean autosize)
Determines whether the popup list autosizes itself or uses all available space.
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:260
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
The DateCell object implements a date handling cell.
Definition: datecell.h:91
void gnc_split_register_change_blank_split_ref(SplitRegister *reg, Split *split)
Change the blank_split reference from pointing to split to another split of the transaction.
gboolean gnc_split_register_handle_exchange(SplitRegister *reg, gboolean force_dialog)
If needed display the transfer dialog to get a price/exchange rate and adjust the price cell accordin...
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:962
void gnc_split_register_show_present_divider(SplitRegister *reg, gboolean show_present)
If TRUE, visually indicate the demarcation between splits with post dates prior to the present...
Equity account is used to balance the balance sheet.
Definition: Account.h:146
SplitRegisterType
Register types.
gint gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW...
TableLayout * gnc_split_register_layout_new(SplitRegister *reg)
Generate the split register layout.
Not a type.
Definition: Account.h:105
void gnc_price_cell_set_debt_credit_value(PriceCell *debit, PriceCell *credit, gnc_numeric amount)
updates two cells; the deb cell if amt is negative, the credit cell if amount is positive, and makes the other cell blank.
Definition: pricecell.c:281
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:245
The type used to store guids in C.
Definition: guid.h:75
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition: pricecell.c:208
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
SplitRegister * gnc_split_register_new(SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line, gboolean is_template, gboolean mismatched_commodities)
Creates a new split register.
void gnc_table_move_cursor(Table *table, VirtualLocation new_virt_loc)
will move the cursor (but not the cursor GUI) to the indicated location.
Definition: table-allgui.c:878
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...
SplitRegisterStyle
Register styles.
void gnc_combo_cell_set_autosize(ComboCell *cell, gboolean autosize)
Determines whether the popup list autosizes itself or uses all available space.
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
The Credit card account is used to denote credit (e.g.
Definition: Account.h:113
#define NREC
not reconciled or cleared
Definition: Split.h:76
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69
void gnc_split_register_copy_current(SplitRegister *reg)
Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later...
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2052