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