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