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