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)
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 }
1157 
1158 void
1160 {
1161  SRInfo* info = gnc_split_register_get_info (reg);
1162  Transaction* pending_trans;
1163  Transaction* trans;
1164  Split* blank_split;
1165  Split* split;
1166 
1167  if (!reg) return;
1168 
1169  blank_split = xaccSplitLookup (&info->blank_split_guid,
1170  gnc_get_current_book ());
1171 
1172  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1173  gnc_get_current_book ());
1174 
1175  /* get the current split based on cursor position */
1177  if (split == NULL)
1178  return;
1179 
1180  /* If we are deleting the blank split, just cancel. The user is
1181  * allowed to delete the blank split as a method for discarding
1182  * any edits they may have made to it. */
1183  if (split == blank_split)
1184  {
1186  return;
1187  }
1188 
1189  gnc_suspend_gui_refresh ();
1190 
1191  trans = xaccSplitGetParent (split);
1192 
1193  /* Check pending transaction */
1194  if (trans == pending_trans)
1195  {
1196  g_assert (xaccTransIsOpen (trans));
1197  }
1198  else
1199  {
1200  g_assert (!pending_trans);
1201  if (gnc_split_register_begin_edit_or_warn (info, trans))
1202  {
1203  gnc_resume_gui_refresh ();
1204  return;
1205  }
1206  }
1207  xaccSplitDestroy (split);
1208 
1209  gnc_resume_gui_refresh ();
1211 }
1212 
1213 void
1215 {
1216  SRInfo* info = gnc_split_register_get_info (reg);
1217  Transaction* pending_trans;
1218  Transaction* trans;
1219  Split* blank_split;
1220  Split* split;
1221  gboolean was_open;
1222 
1223  ENTER ("reg=%p", reg);
1224  if (!reg)
1225  {
1226  LEAVE ("no register");
1227  return;
1228  }
1229 
1230  blank_split = xaccSplitLookup (&info->blank_split_guid,
1231  gnc_get_current_book ());
1232  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1233  gnc_get_current_book ());
1234 
1235  /* get the current split based on cursor position */
1237  if (split == NULL)
1238  {
1239  LEAVE ("no split");
1240  return;
1241  }
1242 
1243  gnc_suspend_gui_refresh ();
1244  trans = xaccSplitGetParent (split);
1245 
1246  /* If we just deleted the blank split, clean up. The user is
1247  * allowed to delete the blank split as a method for discarding
1248  * any edits they may have made to it. */
1249  if (split == blank_split)
1250  {
1251  DEBUG ("deleting blank split");
1252  info->blank_split_guid = *guid_null ();
1253  info->auto_complete = FALSE;
1254  }
1255  else
1256  {
1257  info->trans_expanded = FALSE;
1258  }
1259 
1260  /* Check pending transaction */
1261  if (trans == pending_trans)
1262  {
1263  DEBUG ("clearing pending trans");
1264  info->pending_trans_guid = *guid_null ();
1265  pending_trans = NULL;
1266  }
1267 
1268  was_open = xaccTransIsOpen (trans);
1269  xaccTransDestroy (trans);
1270  if (was_open)
1271  {
1272  DEBUG ("committing");
1273  xaccTransCommitEdit (trans);
1274  }
1275  gnc_resume_gui_refresh ();
1277  LEAVE (" ");
1278 }
1279 
1280 void
1281 gnc_split_register_void_current_trans (SplitRegister* reg, const char* reason)
1282 {
1283  SRInfo* info = gnc_split_register_get_info (reg);
1284  Transaction* pending_trans;
1285  Transaction* trans;
1286  Split* blank_split;
1287  Split* split;
1288 
1289  if (!reg) return;
1290 
1291  blank_split = xaccSplitLookup (&info->blank_split_guid,
1292  gnc_get_current_book ());
1293  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1294  gnc_get_current_book ());
1295 
1296  /* get the current split based on cursor position */
1298  if (split == NULL)
1299  return;
1300 
1301  /* Bail if trying to void the blank split. */
1302  if (split == blank_split)
1303  return;
1304 
1305  /* already voided. */
1306  if (xaccSplitGetReconcile (split) == VREC)
1307  return;
1308 
1309  info->trans_expanded = FALSE;
1310 
1311  gnc_suspend_gui_refresh ();
1312 
1313  trans = xaccSplitGetParent (split);
1314  xaccTransVoid (trans, reason);
1315 
1316  /* Check pending transaction */
1317  if (trans == pending_trans)
1318  {
1319  info->pending_trans_guid = *guid_null ();
1320  pending_trans = NULL;
1321  }
1322  if (xaccTransIsOpen (trans))
1323  {
1324  PERR ("We should not be voiding an open transaction.");
1325  xaccTransCommitEdit (trans);
1326  }
1327  gnc_resume_gui_refresh ();
1328 }
1329 
1330 void
1332 {
1333  SRInfo* info = gnc_split_register_get_info (reg);
1334  Transaction* pending_trans;
1335  Transaction* trans;
1336  Split* blank_split;
1337  Split* split;
1338 
1339  if (!reg) return;
1340 
1341  blank_split = xaccSplitLookup (&info->blank_split_guid,
1342  gnc_get_current_book ());
1343  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1344  gnc_get_current_book ());
1345 
1346  /* get the current split based on cursor position */
1348  if (split == NULL)
1349  return;
1350 
1351  /* Bail if trying to unvoid the blank split. */
1352  if (split == blank_split)
1353  return;
1354 
1355  /* not voided. */
1356  if (xaccSplitGetReconcile (split) != VREC)
1357  return;
1358 
1359  info->trans_expanded = FALSE;
1360 
1361  gnc_suspend_gui_refresh ();
1362 
1363  trans = xaccSplitGetParent (split);
1364 
1365  xaccTransUnvoid (trans);
1366 
1367  /* Check pending transaction */
1368  if (trans == pending_trans)
1369  {
1370  info->pending_trans_guid = *guid_null ();
1371  pending_trans = NULL;
1372  }
1373 
1374  gnc_resume_gui_refresh ();
1375 }
1376 
1377 void
1379  Split* split)
1380 {
1381  SRInfo* info;
1382  Transaction* trans;
1383  Transaction* pending;
1384  int i = 0;
1385  Split* s;
1386 
1387  if ((reg == NULL) || (split == NULL))
1388  return;
1389 
1390  gnc_suspend_gui_refresh ();
1391  info = gnc_split_register_get_info (reg);
1392  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1393 
1394  trans = xaccSplitGetParent (split);
1395  if (!pending)
1396  {
1397  if (gnc_split_register_begin_edit_or_warn (info, trans))
1398  {
1399  gnc_resume_gui_refresh ();
1400  return;
1401  }
1402  }
1403  else if (pending == trans)
1404  {
1405  g_assert (xaccTransIsOpen (trans));
1406  }
1407  else g_assert_not_reached ();
1408 
1409  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1410  {
1411  if (s != split)
1412  xaccSplitDestroy (s);
1413  else i++;
1414  }
1415 
1416  gnc_resume_gui_refresh ();
1418 }
1419 
1420 void
1421 gnc_split_register_empty_current_trans (SplitRegister* reg)
1422 {
1423  Split* split;
1424 
1425  /* get the current split based on cursor position */
1428 }
1429 
1430 void
1432 {
1433  VirtualLocation virt_loc;
1434 
1435  if (reg == NULL)
1436  return;
1437 
1438  virt_loc = reg->table->current_cursor_loc;
1439 
1440  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1441  return;
1442 
1443  /* We're just cancelling the current split here, not the transaction.
1444  * When cancelling edits, reload the cursor from the transaction. */
1445  gnc_table_clear_current_cursor_changes (reg->table);
1446 
1447  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1448  gnc_table_move_cursor_gui (reg->table, virt_loc);
1449 
1450  gnc_table_refresh_gui (reg->table, TRUE);
1451 }
1452 
1453 void
1455 {
1456  SRInfo* info = gnc_split_register_get_info (reg);
1457  Transaction* pending_trans, *blank_trans;
1458  gboolean refresh_all = FALSE;
1459 
1460  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1461  gnc_get_current_book ());
1462 
1464 
1465  if (pending_trans == blank_trans)
1466  refresh_all = TRUE;
1467 
1468  /* Get the currently open transaction, rollback the edits on it, and
1469  * then repaint everything. To repaint everything, make a note of
1470  * all of the accounts that will be affected by this rollback. */
1471  if (!xaccTransIsOpen (pending_trans))
1472  {
1474  return;
1475  }
1476 
1477  if (!pending_trans)
1478  return;
1479 
1480  gnc_suspend_gui_refresh ();
1481 
1482  xaccTransRollbackEdit (pending_trans);
1483 
1484  info->pending_trans_guid = *guid_null ();
1485 
1486  gnc_resume_gui_refresh ();
1487 
1488  if (refresh_all)
1489  gnc_gui_refresh_all (); // force a refresh of all registers
1490  else
1492 }
1493 
1494 void
1495 gnc_split_register_redraw (SplitRegister* reg)
1496 {
1497  gnc_ledger_display_refresh_by_split_register (reg);
1498 }
1499 
1500 /* Copy from the register object to scheme. This needs to be
1501  * in sync with gnc_split_register_save and xaccSRSaveChangedCells. */
1502 static gboolean
1503 gnc_split_register_save_to_copy_buffer (SplitRegister *reg,
1504  FloatingTxn *ft, FloatingSplit *fs,
1505  gboolean use_cut_semantics)
1506 {
1507  FloatingSplit *other_fs = NULL;
1508  Transaction *trans;
1509 
1510  /* use the changed flag to avoid heavy-weight updates
1511  * of the split & transaction fields. This will help
1512  * cut down on unnecessary register redraws. */
1513  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1514  return FALSE;
1515 
1516  /* get the handle to the current split and transaction */
1518  if (trans == NULL)
1519  return FALSE;
1520 
1521  /* copy the contents from the cursor to the split */
1522  if (gnc_table_layout_get_cell_changed (reg->table->layout, DATE_CELL, TRUE))
1523  {
1524  BasicCell* cell;
1525  time64 time;
1526  cell = gnc_table_layout_get_cell (reg->table->layout, DATE_CELL);
1527  gnc_date_cell_get_date ((DateCell*) cell, &time, TRUE);
1529  }
1530 
1531  if (gnc_table_layout_get_cell_changed (reg->table->layout, NUM_CELL, TRUE))
1532  {
1533  const char* value;
1534 
1535  value = gnc_table_layout_get_cell_value (reg->table->layout, NUM_CELL);
1536  if (reg->use_tran_num_for_num_field)
1537  xaccTransSetNum (trans, value);
1538  /* else this contains the same as ACTN_CELL which is already handled below *
1539  * and the TNUM_CELL contains transaction number which is handled in next *
1540  * if statement. */
1541  }
1542 
1543  if (gnc_table_layout_get_cell_changed (reg->table->layout, TNUM_CELL, TRUE))
1544  {
1545  const char* value;
1546 
1547  value = gnc_table_layout_get_cell_value (reg->table->layout, TNUM_CELL);
1548  if (!reg->use_tran_num_for_num_field)
1549  xaccTransSetNum (trans, value);
1550  /* else this cell is not used */
1551  }
1552 
1553  if (gnc_table_layout_get_cell_changed (reg->table->layout, DESC_CELL, TRUE))
1554  {
1555  const char* value;
1556 
1557  value = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
1558  xaccTransSetDescription (trans, value);
1559  }
1560 
1561  if (gnc_table_layout_get_cell_changed (reg->table->layout, NOTES_CELL, TRUE))
1562  {
1563  const char* value;
1564 
1565  value = gnc_table_layout_get_cell_value (reg->table->layout, NOTES_CELL);
1566  xaccTransSetNotes (trans, value);
1567  }
1568 
1569  if (gnc_table_layout_get_cell_changed (reg->table->layout, RECN_CELL, TRUE))
1570  {
1571  BasicCell* cell;
1572  char flag;
1573 
1574  cell = gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
1575  flag = gnc_recn_cell_get_flag ((RecnCell*) cell);
1576 
1577  gnc_float_split_set_reconcile_state (fs, flag);
1578  }
1579 
1580  if (gnc_table_layout_get_cell_changed (reg->table->layout, ACTN_CELL, TRUE))
1581  {
1582  const char* value;
1583 
1584  value = gnc_table_layout_get_cell_value (reg->table->layout, ACTN_CELL);
1585  gnc_float_split_set_action (fs, value);
1586  }
1587 
1588  if (gnc_table_layout_get_cell_changed (reg->table->layout, MEMO_CELL, TRUE))
1589  {
1590  const char* value;
1591 
1592  value = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
1593  gnc_float_split_set_memo (fs, value);
1594  }
1595 
1596  if (gnc_table_layout_get_cell_changed (reg->table->layout, XFRM_CELL, TRUE))
1597  {
1598  Account* new_account;
1599 
1600  new_account = gnc_split_register_get_account (reg, XFRM_CELL);
1601 
1602  if (new_account != NULL)
1603  gnc_float_split_set_account (fs, new_account);
1604  }
1605 
1606  if (reg->style == REG_STYLE_LEDGER)
1607  other_fs = gnc_float_txn_get_other_float_split (ft, fs);
1608 
1609  if (gnc_table_layout_get_cell_changed (reg->table->layout, MXFRM_CELL, TRUE))
1610  {
1611  other_fs = gnc_float_txn_get_other_float_split (ft, fs);
1612 
1613  if (!other_fs)
1614  {
1615  if (ft && g_list_length (ft->m_splits) == 1)
1616  {
1617  Split* temp_split;
1618 
1619  temp_split = xaccMallocSplit (gnc_get_current_book ());
1620  other_fs = gnc_split_to_float_split (temp_split);
1621  xaccSplitDestroy (temp_split);
1622 
1623  gnc_float_txn_append_float_split (ft, other_fs);
1624  }
1625  }
1626 
1627  if (other_fs)
1628  {
1629  Account* new_account;
1630 
1631  new_account = gnc_split_register_get_account (reg, MXFRM_CELL);
1632 
1633  if (new_account != NULL)
1634  gnc_float_split_set_account (other_fs, new_account);
1635  }
1636  }
1637 
1638  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1639  DEBT_CELL, TRUE) ||
1640  gnc_table_layout_get_cell_changed (reg->table->layout,
1641  CRED_CELL, TRUE))
1642  {
1643  BasicCell* cell;
1644  gnc_numeric new_value;
1645  gnc_numeric credit;
1646  gnc_numeric debit;
1647 
1648  cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
1649  credit = gnc_price_cell_get_value ((PriceCell*) cell);
1650 
1651  cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
1652  debit = gnc_price_cell_get_value ((PriceCell*) cell);
1653 
1654  new_value = gnc_numeric_sub_fixed (debit, credit);
1655 
1656  gnc_float_split_set_value (fs, new_value);
1657  }
1658 
1659  if (gnc_table_layout_get_cell_changed (reg->table->layout, PRIC_CELL, TRUE))
1660  {
1661  /* do nothing for now */
1662  }
1663 
1664  if (gnc_table_layout_get_cell_changed (reg->table->layout, SHRS_CELL, TRUE))
1665  {
1666  BasicCell* cell;
1667  gnc_numeric shares;
1668 
1669  cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1670 
1671  shares = gnc_price_cell_get_value ((PriceCell*) cell);
1672 
1673  gnc_float_split_set_amount (fs, shares);
1674  }
1675 
1676  if (gnc_table_layout_get_cell_changed (reg->table->layout,
1677  DEBT_CELL, TRUE) ||
1678  gnc_table_layout_get_cell_changed (reg->table->layout,
1679  CRED_CELL, TRUE) ||
1680  gnc_table_layout_get_cell_changed (reg->table->layout,
1681  PRIC_CELL, TRUE) ||
1682  gnc_table_layout_get_cell_changed (reg->table->layout,
1683  SHRS_CELL, TRUE))
1684  {
1685  if (other_fs)
1686  {
1687  gnc_numeric num;
1688 
1689  num = gnc_float_split_get_amount (fs);
1690  gnc_float_split_set_amount (other_fs, gnc_numeric_neg (num));
1691 
1692  num = gnc_float_split_get_value (fs);
1693  gnc_float_split_set_value (other_fs, gnc_numeric_neg (num));
1694  }
1695  }
1696 
1697  return TRUE;
1698 }
1699 static void
1700 unreconcile_splits (SplitRegister* reg)
1701 {
1702  if (reg->unrecn_splits == NULL)
1703  return; //Nothing to do.
1704  PINFO ("Unreconcile %d splits of reconciled transaction",
1705  g_list_length (reg->unrecn_splits));
1706 
1707  for (GList* node = reg->unrecn_splits; node; node = node->next)
1708  {
1709  Split* split = node->data;
1710  Transaction* txn = xaccSplitGetParent (split);
1711  if (!xaccTransIsOpen (txn))
1712  PWARN ("Unreconcile of split failed because its parent transaction wasn't open for editing");
1713  else if (xaccSplitGetReconcile (split) == YREC)
1714  xaccSplitSetReconcile (split, NREC);
1715  }
1716  g_list_free (reg->unrecn_splits);
1717  reg->unrecn_splits = NULL;
1718 }
1719 
1720 gboolean
1721 gnc_split_register_save (SplitRegister* reg, gboolean do_commit)
1722 {
1723  SRInfo* info = gnc_split_register_get_info (reg);
1724  Transaction* pending_trans;
1725  Transaction* blank_trans;
1726  Transaction* trans;
1727  Account* account;
1728  Split* blank_split;
1729  const char* memo;
1730  const char* desc;
1731  Split* split;
1732 
1733  ENTER ("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
1734 
1735  if (!reg)
1736  {
1737  LEAVE ("no register");
1738  return FALSE;
1739  }
1740 
1741  blank_split = xaccSplitLookup (&info->blank_split_guid,
1742  gnc_get_current_book ());
1743 
1744  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1745  gnc_get_current_book ());
1746 
1747  blank_trans = xaccSplitGetParent (blank_split);
1748 
1749  /* get the handle to the current split and transaction */
1752  if (trans == NULL)
1753  {
1754  LEAVE ("no transaction");
1755  return FALSE;
1756  }
1757 
1758  /* use the changed flag to avoid heavy-weight updates
1759  * of the split & transaction fields. This will help
1760  * cut down on unnecessary register redraws. */
1761  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1762  {
1763  if (!do_commit)
1764  {
1765  LEAVE ("commit unnecessary");
1766  return FALSE;
1767  }
1768 
1769  if (!xaccTransIsOpen (trans))
1770  {
1771  LEAVE ("transaction not open");
1772  return FALSE;
1773  }
1774 
1775  if (trans == pending_trans ||
1776  (trans == blank_trans && info->blank_split_edited))
1777  {
1778  /* We are going to commit. */
1779 
1780  gnc_suspend_gui_refresh ();
1781 
1782  if (trans == blank_trans)
1783  {
1784  /* We have to clear the blank split before the
1785  * refresh or a new one won't be created. */
1786  info->last_date_entered = xaccTransGetDate (trans);
1787  info->blank_split_guid = *guid_null ();
1788  info->blank_split_edited = FALSE;
1789  info->auto_complete = FALSE;
1790  }
1791 
1792  /* We have to clear the pending guid *before* committing the
1793  * trans, because the event handler will find it otherwise. */
1794  if (trans == pending_trans)
1795  info->pending_trans_guid = *guid_null ();
1796 
1797  PINFO ("committing trans (%p)", trans);
1798  unreconcile_splits (reg);
1799  xaccTransCommitEdit (trans);
1800  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1801 
1802  gnc_resume_gui_refresh ();
1803  }
1804  else
1805  DEBUG ("leaving trans (%p) open", trans);
1806 
1807  LEAVE ("unchanged cursor");
1808  return TRUE;
1809  }
1810 
1811  DEBUG ("save split=%p", split);
1812  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
1813  blank_split, blank_trans, pending_trans, trans);
1814 
1815  /* Act on any changes to the current cell before the save. */
1816  if (!gnc_split_register_check_cell (reg,
1817  gnc_table_get_current_cell_name (reg->table)))
1818  {
1819  LEAVE ("need another go at changing cell");
1820  return FALSE;
1821  }
1822 
1823  if (!gnc_split_register_auto_calc (reg, split))
1824  {
1825  LEAVE ("auto calc failed");
1826  return FALSE;
1827  }
1828 
1829  /* Validate the transfer account names */
1830  (void)gnc_split_register_get_account (reg, MXFRM_CELL);
1831  (void)gnc_split_register_get_account (reg, XFRM_CELL);
1832 
1833  /* Maybe deal with exchange-rate transfers */
1834  if (gnc_split_register_handle_exchange (reg, FALSE))
1835  {
1836  LEAVE ("no exchange rate");
1837  return TRUE;
1838  }
1839 
1840  gnc_suspend_gui_refresh ();
1841 
1842  /* determine whether we should commit the pending transaction */
1843  if (pending_trans != trans)
1844  {
1845  // FIXME: How could the pending transaction not be open?
1846  // FIXME: For that matter, how could an open pending
1847  // transaction ever not be the current trans?
1848  if (xaccTransIsOpen (pending_trans))
1849  {
1850  g_warning ("Impossible? committing pending %p", pending_trans);
1851  unreconcile_splits (reg);
1852  xaccTransCommitEdit (pending_trans);
1853  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1854  }
1855  else if (pending_trans)
1856  {
1857  g_critical ("BUG DETECTED! pending transaction (%p) not open",
1858  pending_trans);
1859  g_assert_not_reached ();
1860  }
1861 
1862  if (trans == blank_trans)
1863  {
1864  /* Don't begin editing the blank trans, because it's
1865  already open, but mark it pending now. */
1866  g_assert (xaccTransIsOpen (blank_trans));
1867  /* This is now the pending transaction */
1868  info->pending_trans_guid = *xaccTransGetGUID (blank_trans);
1869  }
1870  else
1871  {
1872  PINFO ("beginning edit of trans %p", trans);
1873  if (gnc_split_register_begin_edit_or_warn (info, trans))
1874  {
1875  gnc_resume_gui_refresh ();
1876  LEAVE ("transaction opened elsewhere");
1877  return FALSE;
1878  }
1879  }
1880  pending_trans = trans;
1881  }
1882  g_assert (xaccTransIsOpen (trans));
1883 
1884  /* If we are saving a brand new transaction and the blank split hasn't
1885  * been edited, then we need to give it a default account. */
1886  /* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
1887  * even better? What if there were some way that we could be on
1888  * a row other than the transaction row or blank split row, but
1889  * the blank split still hasn't been edited? It seems to be assumed
1890  * that it isn't possible, but... -Charles, Jan 2009 */
1891  if (split == blank_split && !info->blank_split_edited)
1892  {
1893  /* If we've reached this point, it means that the blank split is
1894  * anchoring the transaction - see gnc_split_register_add_transaction ()
1895  * for an explanation - and the transaction has been edited (as evidenced
1896  * by the earlier check for a changed cursor.) Since the blank split
1897  * itself has not been edited, we'll have to assign a default account. */
1898  account = gnc_split_register_get_default_account (reg);
1899  if (account)
1900  xaccSplitSetAccount (blank_split, account);
1901  xaccTransSetDateEnteredSecs (trans, gnc_time (NULL));
1902  }
1903 
1904  if (split == NULL)
1905  {
1906  /* If we were asked to save data for a row for which there is no
1907  * associated split, then assume that this was an "empty" row - see
1908  * gnc_split_register_add_transaction () for an explanation. This row
1909  * is used to add splits to an existing transaction, or to add the
1910  * 2nd through nth split rows to a brand new transaction.
1911  * xaccSRGetCurrent will handle this case, too. We will create
1912  * a new split, copy the row contents to that split, and append
1913  * the split to the pre-existing transaction. */
1914  Split* trans_split;
1915 
1916  split = xaccMallocSplit (gnc_get_current_book ());
1917  xaccTransAppendSplit (trans, split);
1918 
1919  gnc_table_set_virt_cell_data (reg->table,
1920  reg->table->current_cursor_loc.vcell_loc,
1921  xaccSplitGetGUID (split));
1922  DEBUG ("assigned cell to new split=%p", split);
1923 
1924  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
1925  if ((info->cursor_hint_trans == trans) &&
1926  (info->cursor_hint_trans_split == trans_split) &&
1927  (info->cursor_hint_split == NULL))
1928  {
1929  info->cursor_hint_split = split;
1930  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1931  }
1932  }
1933 
1934  DEBUG ("updating trans=%p", trans);
1935 
1936  {
1937  SRSaveData* sd;
1938 
1939  sd = gnc_split_register_save_data_new (
1940  trans, split, (info->trans_expanded ||
1941  reg->style == REG_STYLE_AUTO_LEDGER ||
1942  reg->style == REG_STYLE_JOURNAL));
1943  gnc_table_save_cells (reg->table, sd);
1944  gnc_split_register_save_data_destroy (sd);
1945  }
1946 
1947  memo = xaccSplitGetMemo (split);
1948  memo = memo ? memo : "(null)";
1949  desc = xaccTransGetDescription (trans);
1950  desc = desc ? desc : "(null)";
1951  PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
1952 
1953  /* If the modified split is the "blank split", then it is now an
1954  * official part of the account. Set the blank split to NULL, so we
1955  * can be sure of getting a new blank split. Also, save the date
1956  * for the new blank split. */
1957  if (trans == blank_trans)
1958  {
1959  if (do_commit)
1960  {
1961  info->blank_split_guid = *guid_null ();
1962  info->auto_complete = FALSE;
1963  blank_split = NULL;
1964  info->last_date_entered = xaccTransGetDate (trans);
1965  }
1966  else
1967  info->blank_split_edited = TRUE;
1968  }
1969 
1970  /* If requested, commit the current transaction and set the pending
1971  * transaction to NULL. */
1972  if (do_commit)
1973  {
1974  g_assert (trans == blank_trans || trans == pending_trans);
1975  if (pending_trans == trans)
1976  {
1977  pending_trans = NULL;
1978  info->pending_trans_guid = *guid_null ();
1979  }
1980  unreconcile_splits (reg);
1981  xaccTransCommitEdit (trans);
1982  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1983  }
1984 
1985  gnc_table_clear_current_cursor_changes (reg->table);
1986 
1987  gnc_resume_gui_refresh ();
1988 
1989  LEAVE (" ");
1990  return TRUE;
1991 }
1992 
1993 
1994 Account*
1995 gnc_split_register_get_account_by_name (SplitRegister* reg, BasicCell* bcell,
1996  const char* name)
1997 {
1998  const char* placeholder = _ ("The account %s does not allow transactions.");
1999  const char* missing = _ ("The account %s does not exist. "
2000  "Would you like to create it?");
2001  char* account_name;
2002  ComboCell* cell = (ComboCell*) bcell;
2003  Account* account;
2004  static gboolean creating_account = FALSE;
2005  GtkWindow* parent = GTK_WINDOW (gnc_split_register_get_parent (reg));
2006 
2007  if (!name || (strlen (name) == 0))
2008  return NULL;
2009 
2010  /* Find the account */
2011  account = gnc_account_lookup_for_register (gnc_get_current_root_account (),
2012  name);
2013  if (!account)
2014  account = gnc_account_lookup_by_code (gnc_get_current_root_account (), name);
2015 
2016  /* if gnc_ui_new_accounts_from_name_window is used, there is a call to
2017  * refresh which subsequently calls this function again, that's the
2018  * reason for static creating_account. */
2019 
2020  if (!account && !creating_account)
2021  {
2022  /* Ask if they want to create a new one. */
2023  if (!gnc_verify_dialog (parent, TRUE, missing, name))
2024  return NULL;
2025  creating_account = TRUE;
2026  /* User said yes, they want to create a new account. */
2027  account = gnc_ui_new_accounts_from_name_window (parent, name);
2028  creating_account = FALSE;
2029  if (!account)
2030  return NULL;
2031  }
2032 
2033  if (!creating_account)
2034  {
2035  /* Now have the account. */
2036  account_name = gnc_get_account_name_for_split_register (account,
2037  reg->show_leaf_accounts);
2038  if (g_strcmp0 (account_name, gnc_basic_cell_get_value (bcell)))
2039  {
2040  /* The name has changed. Update the cell. */
2041  gnc_combo_cell_set_value (cell, account_name);
2042  gnc_basic_cell_set_changed (&cell->cell, TRUE);
2043  }
2044  g_free (account_name);
2045 
2046  /* See if the account (either old or new) is a placeholder. */
2047  if (account && xaccAccountGetPlaceholder (account))
2048  {
2049  gchar* fullname = gnc_account_get_full_name (account);
2050  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
2051  placeholder, fullname);
2052  g_free (fullname);
2053  return NULL;
2054  }
2055  }
2056 
2057  /* Be seeing you. */
2058  return account;
2059 }
2060 
2061 Account*
2062 gnc_split_register_get_account (SplitRegister* reg, const char* cell_name)
2063 {
2064  BasicCell* cell;
2065  const char* name;
2066 
2067  if (!gnc_table_layout_get_cell_changed (reg->table->layout, cell_name, TRUE))
2068  return NULL;
2069 
2070  cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
2071  if (!cell)
2072  return NULL;
2073  name = gnc_basic_cell_get_value (cell);
2074  return gnc_split_register_get_account_by_name (reg, cell, name);
2075 }
2076 
2077 static gnc_numeric
2078 calculate_value (SplitRegister* reg)
2079 {
2080  gnc_numeric credit;
2081  gnc_numeric debit;
2082 
2083  PriceCell* cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
2084  CRED_CELL);
2085  credit = gnc_price_cell_get_value (cell);
2086 
2087  cell = (PriceCell*)gnc_table_layout_get_cell (reg->table->layout,
2088  DEBT_CELL);
2089  debit = gnc_price_cell_get_value (cell);
2090 
2091  return gnc_numeric_sub_fixed (debit, credit);
2092 }
2093 
2094 
2095 static int
2096 recalc_message_box (SplitRegister* reg, gboolean shares_changed,
2097  gboolean price_changed, gboolean value_changed)
2098 {
2099  int choice;
2100  int default_value;
2101  GList* node;
2102  GList* radio_list = NULL;
2103  const char* title = _ ("Recalculate Transaction");
2104  const char* message = _ ("The values entered for this transaction "
2105  "are inconsistent. Which value would you "
2106  "like to have recalculated?");
2107 
2108  if (shares_changed)
2109  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2110  _ ("_Shares"),
2111  _ ("Changed")));
2112  else
2113  radio_list = g_list_append (radio_list, g_strdup (_ ("_Shares")));
2114 
2115  if (price_changed)
2116  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2117  _ ("_Price"),
2118  _ ("Changed")));
2119  else
2120  radio_list = g_list_append (radio_list, g_strdup (_ ("_Price")));
2121 
2122  if (value_changed)
2123  radio_list = g_list_append (radio_list, g_strdup_printf ("%s (%s)",
2124  _ ("_Value"),
2125  _ ("Changed")));
2126  else
2127  radio_list = g_list_append (radio_list, g_strdup (_ ("_Value")));
2128 
2129  if (price_changed) default_value = 2; /* change the value */
2130  else default_value = 1; /* change the value */
2131 
2132  choice = gnc_choose_radio_option_dialog
2133  (gnc_split_register_get_parent (reg),
2134  title,
2135  message,
2136  _ ("_Recalculate"),
2137  default_value,
2138  radio_list);
2139 
2140  for (node = radio_list; node; node = node->next)
2141  g_free (node->data);
2142 
2143  g_list_free (radio_list);
2144 
2145  return choice;
2146 }
2147 
2148 static void
2149 recalculate_shares (Split* split, SplitRegister* reg,
2150  gnc_numeric value, gnc_numeric price, gboolean value_changed)
2151 {
2152  gint64 denom = gnc_split_get_amount_denom (split);
2153  gnc_numeric amount = gnc_numeric_div (value, price, denom,
2155 
2156  BasicCell* cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
2157  gnc_price_cell_set_value ((PriceCell*) cell, amount);
2158  gnc_basic_cell_set_changed (cell, TRUE);
2159 
2160  if (value_changed)
2161  {
2162  cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
2163  gnc_basic_cell_set_changed (cell, FALSE);
2164  }
2165 }
2166 
2167 static void
2168 recalculate_price (Split* split, SplitRegister* reg,
2169  gnc_numeric value, gnc_numeric amount)
2170 {
2171  BasicCell* price_cell;
2172  gnc_numeric price = gnc_numeric_div (value, amount,
2175 
2176  if (gnc_numeric_negative_p (price))
2177  {
2178  BasicCell* debit_cell;
2179  BasicCell* credit_cell;
2180 
2181  debit_cell = gnc_table_layout_get_cell (reg->table->layout,
2182  DEBT_CELL);
2183 
2184  credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2185  CRED_CELL);
2186 
2187  price = gnc_numeric_neg (price);
2188 
2190  (PriceCell*) credit_cell,
2191  gnc_numeric_neg (value));
2192 
2193  gnc_basic_cell_set_changed (debit_cell, TRUE);
2194  gnc_basic_cell_set_changed (credit_cell, TRUE);
2195  }
2196 
2197  price_cell = gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL);
2198  gnc_price_cell_set_value ((PriceCell*) price_cell, price);
2199  gnc_basic_cell_set_changed (price_cell, TRUE);
2200 }
2201 
2202 static void
2203 recalculate_value (Split* split, SplitRegister* reg,
2204  gnc_numeric price, gnc_numeric amount, gboolean shares_changed)
2205 {
2206  BasicCell* debit_cell = gnc_table_layout_get_cell (reg->table->layout,
2207  DEBT_CELL);
2208  BasicCell* credit_cell = gnc_table_layout_get_cell (reg->table->layout,
2209  CRED_CELL);
2210  gint64 denom = gnc_split_get_value_denom (split);
2211  gnc_numeric value = gnc_numeric_mul (price, amount, denom,
2213 
2215  (PriceCell*) credit_cell, value);
2216 
2217  gnc_basic_cell_set_changed (debit_cell, TRUE);
2218  gnc_basic_cell_set_changed (credit_cell, TRUE);
2219 
2220  if (shares_changed)
2221  {
2222  BasicCell* cell = gnc_table_layout_get_cell (reg->table->layout,
2223  PRIC_CELL);
2224  gnc_basic_cell_set_changed (cell, FALSE);
2225  }
2226 }
2227 
2228 static gboolean
2229 gnc_split_register_auto_calc (SplitRegister* reg, Split* split)
2230 {
2231  PriceCell* cell = NULL;
2232  gboolean recalc_shares = FALSE;
2233  gboolean recalc_price = FALSE;
2234  gboolean recalc_value = FALSE;
2235  gboolean price_changed;
2236  gboolean value_changed;
2237  gboolean shares_changed;
2238  gnc_numeric calc_value;
2239  gnc_numeric value;
2240  gnc_numeric price;
2241  gnc_numeric amount;
2242  Account* account;
2243  int denom;
2244  int choice;
2245 
2246  if (STOCK_REGISTER != reg->type &&
2247  CURRENCY_REGISTER != reg->type &&
2248  PORTFOLIO_LEDGER != reg->type)
2249  return TRUE;
2250 
2251  account = gnc_split_register_get_account (reg, XFRM_CELL);
2252 
2253  if (!account)
2254  account = xaccSplitGetAccount (split);
2255 
2256  if (!account)
2257  account = gnc_split_register_get_default_account (reg);
2258 
2259  if (!xaccAccountIsPriced (account))
2260  return TRUE;
2261 
2262  price_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2263  PRIC_CELL, TRUE);
2264  value_changed = (gnc_table_layout_get_cell_changed (reg->table->layout,
2265  DEBT_CELL, TRUE) ||
2266  gnc_table_layout_get_cell_changed (reg->table->layout,
2267  CRED_CELL, TRUE));
2268  shares_changed = gnc_table_layout_get_cell_changed (reg->table->layout,
2269  SHRS_CELL, TRUE);
2270 
2271  if (!price_changed && !value_changed && !shares_changed)
2272  return TRUE;
2273 
2274  /* If we are using commodity trading accounts then the value may
2275  not really be the value. Punt if so. */
2277  {
2278  gnc_commodity* acc_commodity;
2279  acc_commodity = xaccAccountGetCommodity (account);
2280  if (! (xaccAccountIsPriced (account) ||
2281  !gnc_commodity_is_iso (acc_commodity)))
2282  return TRUE;
2283  }
2284 
2285  if (shares_changed)
2286  {
2287  cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
2288  SHRS_CELL);
2289  amount = gnc_price_cell_get_value (cell);
2290  }
2291  else
2292  amount = xaccSplitGetAmount (split);
2293 
2294  if (price_changed)
2295  {
2296  cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
2297  PRIC_CELL);
2298  price = gnc_price_cell_get_value (cell);
2299  }
2300  else
2301  price = xaccSplitGetSharePrice (split);
2302 
2303  if (value_changed)
2304  value = calculate_value (reg);
2305  else
2306  value = xaccSplitGetValue (split);
2307 
2308 
2309  /* Check if shares and price are BOTH zero (and value is non-zero).
2310  * If so, we can assume that this is an income-correcting split
2311  */
2312  if (gnc_numeric_zero_p (amount) && gnc_numeric_zero_p (price) &&
2313  !gnc_numeric_zero_p (value))
2314  {
2315  return TRUE;
2316  }
2317 
2318  /* Check if precisely one value is zero. If so, we can assume that the
2319  * zero value needs to be recalculated. */
2320 
2321  if (!gnc_numeric_zero_p (amount))
2322  {
2323  if (gnc_numeric_zero_p (price))
2324  {
2325  if (!gnc_numeric_zero_p (value))
2326  recalc_price = TRUE;
2327  }
2328  else if (gnc_numeric_zero_p (value))
2329  recalc_value = TRUE;
2330  }
2331  else if (!gnc_numeric_zero_p (price))
2332  if (!gnc_numeric_zero_p (value))
2333  recalc_shares = TRUE;
2334 
2335  /* If we have not already flagged a recalc, check if this is a split
2336  * which has 2 of the 3 values changed. */
2337 
2338  if ((!recalc_shares) &&
2339  (!recalc_price) &&
2340  (!recalc_value))
2341  {
2342  if (price_changed && value_changed)
2343  {
2344  if (!shares_changed)
2345  recalc_shares = TRUE;
2346  }
2347  else if (value_changed && shares_changed)
2348  recalc_price = TRUE;
2349  else if (price_changed && shares_changed)
2350  recalc_value = TRUE;
2351  }
2352 
2353  calc_value = gnc_numeric_mul (price, amount,
2355 
2356  denom = gnc_split_get_value_denom (split);
2357 
2358  /* Now, if we have not flagged one of the recalcs, and value and
2359  * calc_value are not the same number, then we need to ask for
2360  * help from the user. */
2361 
2362  if (!recalc_shares &&
2363  !recalc_price &&
2364  !recalc_value &&
2365  !gnc_numeric_same (value, calc_value, denom, GNC_HOW_RND_ROUND_HALF_UP))
2366  {
2367  choice = recalc_message_box (reg, shares_changed,
2368  price_changed,
2369  value_changed);
2370  switch (choice)
2371  {
2372  case 0: /* Modify number of shares */
2373  recalc_shares = TRUE;
2374  break;
2375  case 1: /* Modify the share price */
2376  recalc_price = TRUE;
2377  break;
2378  case 2: /* Modify total value */
2379  recalc_value = TRUE;
2380  break;
2381  default: /* Cancel */
2382  return FALSE;
2383  }
2384  }
2385 
2386  if (recalc_shares && !gnc_numeric_zero_p (price))
2387  recalculate_shares (split, reg, value, price, value_changed);
2388 
2389  if (recalc_price && !gnc_numeric_zero_p (amount))
2390  {
2391  recalculate_price (split, reg, value, amount);
2392  price_changed = TRUE;
2393  }
2394  if (recalc_value)
2395  recalculate_value (split, reg, price, amount, shares_changed);
2396 
2397  return TRUE;
2398 }
2399 
2400 static GNCAccountType
2401 gnc_split_register_type_to_account_type (SplitRegisterType sr_type)
2402 {
2403  switch (sr_type)
2404  {
2405  case BANK_REGISTER:
2406  return ACCT_TYPE_BANK;
2407  case CASH_REGISTER:
2408  return ACCT_TYPE_CASH;
2409  case ASSET_REGISTER:
2410  return ACCT_TYPE_ASSET;
2411  case CREDIT_REGISTER:
2412  return ACCT_TYPE_CREDIT;
2413  case LIABILITY_REGISTER:
2414  return ACCT_TYPE_LIABILITY;
2415  case PAYABLE_REGISTER:
2416  return ACCT_TYPE_PAYABLE;
2417  case RECEIVABLE_REGISTER:
2418  return ACCT_TYPE_RECEIVABLE;
2419  case INCOME_LEDGER:
2420  case INCOME_REGISTER:
2421  return ACCT_TYPE_INCOME;
2422  case EXPENSE_REGISTER:
2423  return ACCT_TYPE_EXPENSE;
2424  case STOCK_REGISTER:
2425  case PORTFOLIO_LEDGER:
2426  return ACCT_TYPE_STOCK;
2427  case CURRENCY_REGISTER:
2428  return ACCT_TYPE_CURRENCY;
2429  case TRADING_REGISTER:
2430  return ACCT_TYPE_TRADING;
2431  case GENERAL_JOURNAL:
2432  return ACCT_TYPE_NONE;
2433  case EQUITY_REGISTER:
2434  return ACCT_TYPE_EQUITY;
2435  case SEARCH_LEDGER:
2436  return ACCT_TYPE_NONE;
2437  default:
2438  return ACCT_TYPE_NONE;
2439  }
2440 }
2441 
2442 const char*
2444 {
2445  SRInfo* info = gnc_split_register_get_info (reg);
2446 
2447  if (!reg)
2448  return NULL;
2449 
2450  if (info->debit_str)
2451  return info->debit_str;
2452 
2453  info->debit_str =
2455  (gnc_split_register_type_to_account_type (reg->type));
2456 
2457  if (info->debit_str)
2458  return info->debit_str;
2459 
2460  info->debit_str = g_strdup (_ ("Debit"));
2461 
2462  return info->debit_str;
2463 }
2464 
2465 const char*
2467 {
2468  SRInfo* info = gnc_split_register_get_info (reg);
2469 
2470  if (!reg)
2471  return NULL;
2472 
2473  if (info->credit_str)
2474  return info->credit_str;
2475 
2476  info->credit_str =
2478  (gnc_split_register_type_to_account_type (reg->type));
2479 
2480  if (info->credit_str)
2481  return info->credit_str;
2482 
2483  info->credit_str = g_strdup (_ ("Credit"));
2484 
2485  return info->credit_str;
2486 }
2487 
2488 gboolean
2489 gnc_split_register_changed (SplitRegister* reg)
2490 {
2491  SRInfo* info = gnc_split_register_get_info (reg);
2492  Transaction* pending_trans;
2493 
2494  ENTER ("reg=%p", reg);
2495 
2496  if (reg == NULL)
2497  {
2498  LEAVE ("no register");
2499  return FALSE;
2500  }
2501 
2502  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2503  {
2504  LEAVE ("cursor changed");
2505  return TRUE;
2506  }
2507 
2508  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2509  gnc_get_current_book ());
2510  if (xaccTransIsOpen (pending_trans))
2511  {
2512  LEAVE ("open and pending txn");
2513  return TRUE;
2514  }
2515 
2516  LEAVE ("register unchanged");
2517  return FALSE;
2518 }
2519 
2520 void
2522  gboolean show_present)
2523 {
2524  SRInfo* info = gnc_split_register_get_info (reg);
2525 
2526  if (reg == NULL)
2527  return;
2528 
2529  info->show_present_divider = show_present;
2530 }
2531 
2532 gboolean
2534 {
2535  SRInfo* info = gnc_split_register_get_info (reg);
2536 
2537  if (!info)
2538  return FALSE;
2539 
2540  return info->full_refresh;
2541 }
2542 
2543 /* configAction strings into the action cell */
2544 /* hack alert -- this stuff really, really should be in a config file ... */
2545 static void
2546 gnc_split_register_config_action (SplitRegister* reg)
2547 {
2548  ComboCell* cell;
2549 
2550  cell = (ComboCell*) gnc_table_layout_get_cell (reg->table->layout,
2551  ACTN_CELL);
2552 
2553  /* setup strings in the action pull-down */
2554  switch (reg->type)
2555  {
2556  case BANK_REGISTER:
2557  /* broken ! FIXME bg */
2558  case SEARCH_LEDGER:
2559  gnc_combo_cell_add_menu_item (cell, C_ ("Action Column", "Deposit"));
2560  gnc_combo_cell_add_menu_item (cell, _ ("Withdraw"));
2561  gnc_combo_cell_add_menu_item (cell, _ ("Check"));
2562  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2563  gnc_combo_cell_add_menu_item (cell, _ ("ATM Deposit"));
2564  gnc_combo_cell_add_menu_item (cell, _ ("ATM Draw"));
2565  gnc_combo_cell_add_menu_item (cell, _ ("Teller"));
2566  gnc_combo_cell_add_menu_item (cell, _ ("Charge"));
2567  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2568  gnc_combo_cell_add_menu_item (cell, _ ("Receipt"));
2569  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2570  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2571  /* Action: Point Of Sale */
2572  gnc_combo_cell_add_menu_item (cell, _ ("POS"));
2573  gnc_combo_cell_add_menu_item (cell, _ ("Phone"));
2574  gnc_combo_cell_add_menu_item (cell, _ ("Online"));
2575  /* Action: Automatic Deposit ?!? */
2576  gnc_combo_cell_add_menu_item (cell, _ ("AutoDep"));
2577  gnc_combo_cell_add_menu_item (cell, _ ("Wire"));
2578  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2579  gnc_combo_cell_add_menu_item (cell, _ ("Direct Debit"));
2580  gnc_combo_cell_add_menu_item (cell, _ ("Transfer"));
2581  break;
2582  case CASH_REGISTER:
2583  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2584  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2585  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2586  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2587  break;
2588  case ASSET_REGISTER:
2589  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2590  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2591  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2592  break;
2593  case CREDIT_REGISTER:
2594  gnc_combo_cell_add_menu_item (cell, _ ("ATM Deposit"));
2595  gnc_combo_cell_add_menu_item (cell, _ ("ATM Draw"));
2596  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2597  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2598  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2599  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2600  gnc_combo_cell_add_menu_item (cell, _ ("Online"));
2601  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2602  break;
2603  case LIABILITY_REGISTER:
2604  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2605  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2606  gnc_combo_cell_add_menu_item (cell, _ ("Loan"));
2607  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2608  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2609  break;
2610  case RECEIVABLE_REGISTER:
2611  case PAYABLE_REGISTER:
2612  gnc_combo_cell_add_menu_item (cell, _ ("Invoice"));
2613  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2614  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2615  gnc_combo_cell_add_menu_item (cell, _ ("Credit"));
2616  break;
2617  case INCOME_LEDGER:
2618  case INCOME_REGISTER:
2619  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2620  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2621  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2622  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2623  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2624  gnc_combo_cell_add_menu_item (cell, _ ("Payment"));
2625  gnc_combo_cell_add_menu_item (cell, _ ("Rebate"));
2626  gnc_combo_cell_add_menu_item (cell, _ ("Paycheck"));
2627  break;
2628  case EXPENSE_REGISTER:
2629  case TRADING_REGISTER:
2630  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2631  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2632  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2633  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2634  break;
2635  case GENERAL_JOURNAL:
2636  case EQUITY_REGISTER:
2637  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2638  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2639  gnc_combo_cell_add_menu_item (cell, _ ("Equity"));
2640  break;
2641  case STOCK_REGISTER:
2642  case PORTFOLIO_LEDGER:
2643  case CURRENCY_REGISTER:
2644  gnc_combo_cell_add_menu_item (cell, ACTION_BUY_STR);
2645  gnc_combo_cell_add_menu_item (cell, ACTION_SELL_STR);
2646  gnc_combo_cell_add_menu_item (cell, _ ("Price"));
2647  gnc_combo_cell_add_menu_item (cell, _ ("Fee"));
2648  /* Action: Dividend */
2649  gnc_combo_cell_add_menu_item (cell, _ ("Dividend"));
2650  gnc_combo_cell_add_menu_item (cell, _ ("Interest"));
2651  /* Action: Long Term Capital Gains */
2652  gnc_combo_cell_add_menu_item (cell, _ ("LTCG"));
2653  /* Action: Short Term Capital Gains */
2654  gnc_combo_cell_add_menu_item (cell, _ ("STCG"));
2655  gnc_combo_cell_add_menu_item (cell, _ ("Income"));
2656  /* Action: Distribution */
2657  gnc_combo_cell_add_menu_item (cell, _ ("Dist"));
2658  gnc_combo_cell_add_menu_item (cell, C_ ("Action Column", "Split"));
2659  break;
2660 
2661  default:
2662  gnc_combo_cell_add_menu_item (cell, _ ("Increase"));
2663  gnc_combo_cell_add_menu_item (cell, _ ("Decrease"));
2664  gnc_combo_cell_add_menu_item (cell, _ ("Buy"));
2665  gnc_combo_cell_add_menu_item (cell, _ ("Sell"));
2666  break;
2667  }
2668 }
2669 
2670 static void
2671 gnc_split_register_config_cells (SplitRegister* reg)
2672 {
2674  ((ComboCell*)
2675  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2676  SPLIT_TRANS_STR);
2677 
2679  ((ComboCell*)
2680  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL),
2681  STOCK_SPLIT_STR);
2682 
2683  /* the action cell */
2685  ((ComboCell*)
2686  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), TRUE);
2687 
2688  /* the description cell */
2690  ((CompletionCell*)
2691  gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), TRUE);
2692 
2693  /* Use GNC_COMMODITY_MAX_FRACTION for prices and "exchange rates" */
2695  ((PriceCell*)
2696  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
2698 
2699  /* Initialize shares and share balance cells */
2701  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL),
2702  gnc_default_share_print_info ());
2703 
2705  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, TSHRS_CELL),
2706  gnc_default_share_print_info ());
2707 
2708  /* Initialize the rate cell
2709  * use a share_print_info to make sure we don't have rounding errors
2710  */
2712  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL),
2713  gnc_default_share_print_info ());
2714 
2715  /* The action cell should accept strings not in the list */
2717  ((ComboCell*)
2718  gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL), FALSE);
2719 
2720  /* The description cell should accept strings not in the list */
2722  ((CompletionCell*)
2723  gnc_table_layout_get_cell (reg->table->layout, DESC_CELL), FALSE);
2724 
2725  /* number format for share quantities in stock ledgers */
2726  switch (reg->type)
2727  {
2728  case CURRENCY_REGISTER:
2729  case STOCK_REGISTER:
2730  case PORTFOLIO_LEDGER:
2732  ((PriceCell*)
2733  gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
2734  gnc_default_price_print_info (gnc_default_currency ()));
2735  break;
2736 
2737  default:
2738  break;
2739  }
2740 
2741  /* add menu items for the action cell */
2742  gnc_split_register_config_action (reg);
2743 }
2744 
2745 static void
2746 split_register_pref_changed (gpointer prefs, gchar* pref, gpointer user_data)
2747 {
2748  SplitRegister* reg = user_data;
2749  SRInfo* info;
2750 
2751  g_return_if_fail (pref);
2752  if (reg == NULL)
2753  return;
2754 
2755  info = reg->sr_info;
2756  if (!info)
2757  return;
2758 
2759  if (g_str_has_suffix (pref, GNC_PREF_ACCOUNTING_LABELS))
2760  {
2761  /* Release current strings. Will be reloaded at next reference. */
2762  g_free (info->tdebit_str);
2763  g_free (info->tcredit_str);
2764 
2765  info->debit_str = NULL;
2766  info->tdebit_str = NULL;
2767  info->credit_str = NULL;
2768  info->tcredit_str = NULL;
2769 
2770  }
2771  else if (g_str_has_suffix (pref, GNC_PREF_ACCOUNT_SEPARATOR))
2772  {
2773  info->separator_changed = TRUE;
2774  }
2775  else if (g_str_has_suffix (pref, GNC_PREF_SHOW_LEAF_ACCT_NAMES))
2776  {
2777  reg->show_leaf_accounts = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2778  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
2779  }
2780  else if (g_str_has_suffix (pref, GNC_PREF_ALT_COLOR_BY_TRANS))
2781  {
2782  reg->double_alt_color = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2783  GNC_PREF_ALT_COLOR_BY_TRANS);
2784  }
2785  else
2786  {
2787  g_warning ("split_register_pref_changed: Unknown preference %s", pref);
2788  }
2789 }
2790 
2791 static void
2792 split_register_book_option_changed (gpointer new_val, gpointer user_data)
2793 {
2794  SplitRegister* reg = user_data;
2795  gboolean* new_data = (gboolean*)new_val;
2796 
2797  if (reg == NULL)
2798  return;
2799 
2800  reg->use_tran_num_for_num_field = (*new_data ? FALSE : TRUE);
2801 }
2802 
2803 static void
2804 gnc_split_register_init (SplitRegister* reg,
2805  SplitRegisterType type,
2806  SplitRegisterStyle style,
2807  gboolean use_double_line,
2808  gboolean do_auto_complete,
2809  gboolean is_template,
2810  gboolean mismatched_commodities)
2811 {
2812  TableLayout* layout;
2813  TableModel* model;
2814  TableControl* control;
2815 
2816  /* Register 'destroy' callback */
2817  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2818  GNC_PREF_ACCOUNTING_LABELS,
2819  split_register_pref_changed,
2820  reg);
2821  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL,
2822  GNC_PREF_ACCOUNT_SEPARATOR,
2823  split_register_pref_changed,
2824  reg);
2825  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
2826  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
2827  split_register_pref_changed,
2828  reg);
2829  gnc_prefs_register_cb (GNC_PREFS_GROUP_GENERAL_REGISTER,
2830  GNC_PREF_ALT_COLOR_BY_TRANS,
2831  split_register_pref_changed,
2832  reg);
2833  gnc_book_option_register_cb (OPTION_NAME_NUM_FIELD_SOURCE,
2834  split_register_book_option_changed,
2835  reg);
2836 
2837  reg->sr_info = NULL;
2838 
2839  reg->unrecn_splits = NULL;
2840 
2841  reg->show_leaf_accounts = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2842  GNC_PREF_SHOW_LEAF_ACCT_NAMES);
2843  reg->double_alt_color = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
2844  GNC_PREF_ALT_COLOR_BY_TRANS);
2845 
2846  reg->type = type;
2847  reg->style = style;
2848  reg->use_double_line = use_double_line;
2849  reg->do_auto_complete = do_auto_complete;
2850  reg->is_template = is_template;
2851  reg->mismatched_commodities = mismatched_commodities;
2852  reg->use_tran_num_for_num_field =
2853  (qof_book_use_split_action_for_num_field (gnc_get_current_book ())
2854  ? FALSE : TRUE);
2855 
2856  layout = gnc_split_register_layout_new (reg);
2857 
2858  if (is_template)
2859  model = gnc_template_register_model_new ();
2860  else
2861  model = gnc_split_register_model_new ();
2862  model->handler_user_data = reg;
2863 
2864  control = gnc_split_register_control_new ();
2865  control->user_data = reg;
2866 
2867  reg->table = gnc_table_new (layout, model, control);
2868 
2869  gnc_split_register_config_cells (reg);
2870 
2871  /* Set up header */
2872  {
2873  VirtualCellLocation vcell_loc = { 0, 0 };
2874  CellBlock* header;
2875 
2876  header = gnc_table_layout_get_cursor (reg->table->layout, CURSOR_HEADER);
2877 
2878  gnc_table_set_vcell (reg->table, header, NULL, TRUE, TRUE, vcell_loc);
2879  }
2880 
2881  /* Set up first and only initial row */
2882  {
2883  VirtualLocation vloc;
2884  CellBlock* cursor;
2885 
2886  vloc.vcell_loc.virt_row = 1;
2887  vloc.vcell_loc.virt_col = 0;
2888  vloc.phys_row_offset = 0;
2889  vloc.phys_col_offset = 0;
2890 
2891  cursor = gnc_table_layout_get_cursor (reg->table->layout,
2892  CURSOR_SINGLE_LEDGER);
2893 
2894  gnc_table_set_vcell (reg->table, cursor, NULL, TRUE, TRUE, vloc.vcell_loc);
2895 
2896  if (gnc_table_find_close_valid_cell (reg->table, &vloc, FALSE))
2897  gnc_table_move_cursor (reg->table, vloc);
2898  else
2899  {
2900  PERR ("Can't find valid initial location");
2901  }
2902  }
2903 }
2904 
2905 SplitRegister*
2907  SplitRegisterStyle style,
2908  gboolean use_double_line,
2909  gboolean is_template,
2910  gboolean mismatched_commodities)
2911 {
2912  SplitRegister* reg;
2913  gboolean default_do_auto_complete = TRUE;
2914 
2915  reg = g_new0 (SplitRegister, 1);
2916 
2917  if (type >= NUM_SINGLE_REGISTER_TYPES)
2918  style = REG_STYLE_JOURNAL;
2919 
2920  gnc_split_register_init (reg,
2921  type,
2922  style,
2923  use_double_line,
2924  default_do_auto_complete,
2925  is_template,
2926  mismatched_commodities);
2927 
2928  return reg;
2929 }
2930 
2931 void
2932 gnc_split_register_config (SplitRegister* reg,
2933  SplitRegisterType newtype,
2934  SplitRegisterStyle newstyle,
2935  gboolean use_double_line)
2936 {
2937  if (!reg) return;
2938 
2939  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2940  if (reg->use_double_line && !use_double_line)
2941  {
2942  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2943  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
2944  {
2945  if (virt_loc.phys_row_offset)
2946  {
2947  gnc_table_move_vertical_position (reg->table, &virt_loc,
2948  -virt_loc.phys_row_offset);
2949  gnc_table_move_cursor_gui (reg->table, virt_loc);
2950  }
2951  }
2952  else
2953  {
2954  /* WTF? Go to a known safe location. */
2955  virt_loc.vcell_loc.virt_row = 1;
2956  virt_loc.vcell_loc.virt_col = 0;
2957  virt_loc.phys_row_offset = 0;
2958  virt_loc.phys_col_offset = 0;
2959  gnc_table_move_cursor_gui (reg->table, virt_loc);
2960  }
2961  }
2962 
2963  reg->type = newtype;
2964 
2965  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
2966  newstyle = REG_STYLE_JOURNAL;
2967 
2968  reg->style = newstyle;
2969  reg->use_double_line = use_double_line;
2970 
2971  gnc_table_realize_gui (reg->table);
2972 }
2973 
2974 void
2975 gnc_split_register_set_reverse_sort (SplitRegister* reg, gboolean reverse_sort)
2976 {
2977  g_return_if_fail (reg);
2978  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
2979 }
2980 
2981 void
2983  gboolean do_auto_complete)
2984 {
2985  g_return_if_fail (reg);
2986  reg->do_auto_complete = do_auto_complete;
2987 }
2988 
2989 static void
2990 gnc_split_register_destroy_info (SplitRegister* reg)
2991 {
2992  SRInfo* info;
2993 
2994  if (reg == NULL)
2995  return;
2996 
2997  if (reg->unrecn_splits != NULL)
2998  {
2999  g_list_free (reg->unrecn_splits);
3000  reg->unrecn_splits = NULL;
3001  }
3002 
3003  info = reg->sr_info;
3004  if (!info)
3005  return;
3006 
3007  g_free (info->tdebit_str);
3008  g_free (info->tcredit_str);
3009 
3010  info->debit_str = NULL;
3011  info->tdebit_str = NULL;
3012  info->credit_str = NULL;
3013  info->tcredit_str = NULL;
3014 
3015  g_free (reg->sr_info);
3016 
3017  reg->sr_info = NULL;
3018 }
3019 
3020 void
3021 gnc_split_register_set_data (SplitRegister* reg, void* user_data,
3022  SRGetParentCallback get_parent)
3023 {
3024  SRInfo* info = gnc_split_register_get_info (reg);
3025 
3026  g_return_if_fail (reg != NULL);
3027 
3028  info->user_data = user_data;
3029  info->get_parent = get_parent;
3030 }
3031 
3032 static void
3033 gnc_split_register_cleanup (SplitRegister* reg)
3034 {
3035  SRInfo* info = gnc_split_register_get_info (reg);
3036  Transaction* pending_trans;
3037  Transaction* blank_trans = NULL;
3038  Split* blank_split;
3039 
3040  ENTER ("reg=%p", reg);
3041 
3042  blank_split = xaccSplitLookup (&info->blank_split_guid,
3043  gnc_get_current_book ());
3044 
3045  pending_trans = xaccTransLookup (&info->pending_trans_guid,
3046  gnc_get_current_book ());
3047 
3048  gnc_suspend_gui_refresh ();
3049 
3050  /* Destroy the transaction containing the "blank split", which was only
3051  * created to support the area for entering a new transaction. Since the
3052  * register is closing, this transaction is no longer needed. */
3053  if (blank_split != NULL)
3054  {
3055  gboolean was_open;
3056 
3057  blank_trans = xaccSplitGetParent (blank_split);
3058 
3059  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
3060  blank_split, blank_trans, pending_trans);
3061 
3062  /* Destroying the transaction will automatically remove its splits. */
3063  was_open = xaccTransIsOpen (blank_trans);
3064  xaccTransDestroy (blank_trans);
3065  if (was_open)
3066  xaccTransCommitEdit (blank_trans);
3067 
3068  /* Update the register info. */
3069  if (blank_trans == pending_trans)
3070  {
3071  info->pending_trans_guid = *guid_null ();
3072  pending_trans = NULL;
3073  }
3074  info->blank_split_guid = *guid_null ();
3075  info->auto_complete = FALSE;
3076  blank_split = NULL;
3077  }
3078 
3079  /* be sure to take care of any open transactions */
3080  if (pending_trans != NULL)
3081  {
3082  g_critical ("BUG DETECTED: pending_trans=%p, blank_split=%p, blank_trans=%p",
3083  pending_trans, blank_split, blank_trans);
3084  g_assert_not_reached ();
3085  info->pending_trans_guid = *guid_null ();
3086  /* CAS: It's not clear to me that we'd really want to commit
3087  here, rather than rollback. But, maybe this is just dead
3088  code. */
3089  if (xaccTransIsOpen (pending_trans))
3090  xaccTransCommitEdit (pending_trans);
3091  else g_assert_not_reached ();
3092 
3093  pending_trans = NULL;
3094  }
3095 
3096  gnc_split_register_destroy_info (reg);
3097 
3098  gnc_resume_gui_refresh ();
3099 
3100  LEAVE (" ");
3101 }
3102 
3103 void
3104 gnc_split_register_destroy (SplitRegister* reg)
3105 {
3106  g_return_if_fail (reg);
3107 
3108  ENTER ("reg=%p", reg);
3109 
3110  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3111  GNC_PREF_ACCOUNTING_LABELS,
3112  split_register_pref_changed,
3113  reg);
3114  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3115  GNC_PREF_ACCOUNT_SEPARATOR,
3116  split_register_pref_changed,
3117  reg);
3118  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3119  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3120  split_register_pref_changed,
3121  reg);
3122  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3123  GNC_PREF_ALT_COLOR_BY_TRANS,
3124  split_register_pref_changed,
3125  reg);
3126  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3127  split_register_book_option_changed,
3128  reg);
3129 
3130  gnc_split_register_cleanup (reg);
3131 
3132  gnc_table_destroy (reg->table);
3133  reg->table = NULL;
3134 
3135  /* free the memory itself */
3136  g_free (reg);
3137  LEAVE (" ");
3138 }
3139 
3140 void
3141 gnc_split_register_set_read_only (SplitRegister* reg, gboolean read_only)
3142 {
3143  gnc_table_model_set_read_only (reg->table->model, read_only);
3144 }
3145 
3148 {
3149  switch (reg->type)
3150  {
3151  case BANK_REGISTER:
3152  case CASH_REGISTER:
3153  case ASSET_REGISTER:
3154  case CREDIT_REGISTER:
3155  case LIABILITY_REGISTER:
3156  case INCOME_REGISTER:
3157  case EXPENSE_REGISTER:
3158  case EQUITY_REGISTER:
3159  case TRADING_REGISTER:
3160  {
3161  return REG_TYPE_GROUP_CURRENCY;
3162  break;
3163  }
3164  case PAYABLE_REGISTER:
3165  case RECEIVABLE_REGISTER:
3166  {
3167  return REG_TYPE_GROUP_APAR;
3168  break;
3169  }
3170  case INCOME_LEDGER:
3171  case GENERAL_JOURNAL:
3172  case SEARCH_LEDGER:
3173  {
3174  return REG_TYPE_GROUP_JOURNAL;
3175  break;
3176  }
3177  case STOCK_REGISTER:
3178  case CURRENCY_REGISTER:
3179  {
3180  return REG_TYPE_GROUP_STOCK;
3181  break;
3182  }
3183  case PORTFOLIO_LEDGER:
3184  {
3185  return REG_TYPE_GROUP_PORTFOLIO;
3186  break;
3187  }
3188  default:
3189  return REG_TYPE_GROUP_UNKNOWN;
3190  PERR ("unknown register type %d\n", reg->type);
3191  break;
3192  }
3193 }
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:4622
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:4490
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:1471
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition: Account.cpp:2696
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:4030
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:4631
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:1070
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:3246
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:3056
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 a, gnc_numeric b, 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:1648
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:1928
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:4042
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:1244
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:3359
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:4058
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:261
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.
int 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:2032