GnuCash c935c2f+
Loading...
Searching...
No Matches
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"
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. */
63static QofLogModule log_module = GNC_MOD_LEDGER;
64
65/* The copied split or transaction, if any */
66typedef 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;
78
79static ft_fs_store copied_item = { 0, { NULL } };
80
83static gboolean gnc_split_register_save_to_copy_buffer (SplitRegister *reg,
84 FloatingTxn *ft,
85 FloatingSplit *fs,
86 gboolean use_cut_semantics);
87static gboolean gnc_split_register_auto_calc (SplitRegister *reg,
88 Split *split);
89
90
93static void
94clear_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
108gboolean
110{
111 return copied_item.ft || copied_item.fs;
112}
113
114static void
115gnc_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
136void
137gnc_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
163static int
164gnc_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
182static int
183gnc_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 */
200gboolean
201gnc_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
242void
243gnc_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
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
302gboolean
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
317Transaction*
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
341Split*
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
351Split*
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
361gboolean
362gnc_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
401gboolean
402gnc_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
439Split*
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
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
759static void
760gnc_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
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
891void
893{
894 gnc_split_register_copy_current_internal (reg, FALSE);
895}
896
897void
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
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
940void
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
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
1169gboolean
1170gnc_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
1182void
1183gnc_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
1214void
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
1269void
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
1336void
1337gnc_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
1386void
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
1433void
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
1476void
1477gnc_split_register_empty_current_trans (SplitRegister* reg)
1478{
1479 Split* split;
1480
1481 /* get the current split based on cursor position */
1484}
1485
1486void
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
1509void
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
1550void
1551gnc_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. */
1558static gboolean
1559gnc_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}
1755static void
1756unreconcile_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
1776gboolean
1777gnc_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
2050Account*
2051gnc_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
2117Account*
2118gnc_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
2133static gnc_numeric
2134calculate_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
2151static int
2152recalc_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
2204static void
2205recalculate_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,
2210 GNC_HOW_RND_ROUND_HALF_UP);
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
2223static void
2224recalculate_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,
2230 GNC_HOW_DENOM_EXACT);
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
2258static void
2259recalculate_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,
2268 GNC_HOW_RND_ROUND_HALF_UP);
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
2284static gboolean
2285gnc_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,
2410 GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD);
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
2456static GNCAccountType
2457gnc_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
2498const 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
2521const 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
2544gboolean
2545gnc_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
2576void
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
2588gboolean
2589gnc_split_register_full_refresh_ok (SplitRegister* reg)
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 ... */
2601static void
2602gnc_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
2726static void
2727gnc_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
2801static void
2802split_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
2847static void
2848split_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
2859static void
2860gnc_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
2961SplitRegister*
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
2987void
2988gnc_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
3030void
3031gnc_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
3037void
3039 gboolean do_auto_complete)
3040{
3041 g_return_if_fail (reg);
3042 reg->do_auto_complete = do_auto_complete;
3043}
3044
3045static void
3046gnc_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
3076void
3077gnc_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
3088static void
3089gnc_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
3159void
3160gnc_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
3196void
3197gnc_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}
This file contains the functions to present a gui to the user for creating a new account or editing a...
Date and Time handling routines.
Public declarations for GncLedgerDisplay class.
Generic api to store and retrieve preferences.
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed.
Definition Account.h:103
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:3305
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
Definition Account.cpp:2745
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false.
Definition Account.cpp:4551
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition Account.cpp:4692
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition Account.cpp:4683
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition Account.cpp:1666
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Definition Account.cpp:3408
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
@ ACCT_TYPE_INCOME
Income accounts are used to denote income.
Definition Account.h:140
@ ACCT_TYPE_TRADING
Account used to record multiple commodity transactions.
Definition Account.h:155
@ ACCT_TYPE_EXPENSE
Expense accounts are used to denote expenses.
Definition Account.h:143
@ ACCT_TYPE_BANK
The bank account type denotes a savings or checking account held at a bank.
Definition Account.h:107
@ ACCT_TYPE_PAYABLE
A/P account type.
Definition Account.h:151
@ ACCT_TYPE_ASSET
asset (and liability) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:116
@ ACCT_TYPE_CURRENCY
The currency account type indicates that the account is a currency trading account.
Definition Account.h:129
@ ACCT_TYPE_RECEIVABLE
A/R account type.
Definition Account.h:149
@ ACCT_TYPE_CASH
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition Account.h:110
@ ACCT_TYPE_LIABILITY
liability (and asset) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:119
@ ACCT_TYPE_EQUITY
Equity account is used to balance the balance sheet.
Definition Account.h:146
@ ACCT_TYPE_CREDIT
The Credit card account is used to denote credit (e.g.
Definition Account.h:113
@ ACCT_TYPE_STOCK
Stock accounts will typically be shown in registers which show three columns: price,...
Definition Account.h:122
@ ACCT_TYPE_NONE
Not a type.
Definition Account.h:105
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition qofbook.cpp:1006
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition qofbook.cpp:974
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the 'Num' field, FALSE if it uses transaction nu...
void gnc_combo_cell_set_autosize(ComboCell *cell, gboolean autosize)
Determines whether the popup list autosizes itself or uses all available space.
void gnc_combo_cell_set_strict(ComboCell *cell, gboolean strict)
Determines whether the cell will accept strings not in the menu.
void gnc_completion_cell_set_strict(CompletionCell *cell, gboolean strict)
Determines whether the cell will accept strings not in the menu.
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition pricecell.c:208
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,...
Definition pricecell.c:281
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_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_price_cell_set_fraction(PriceCell *cell, int fraction)
Sets the fraction used for rounding.
Definition pricecell.c:242
void gnc_price_cell_set_print_info(PriceCell *cell, GNCPrintAmountInfo print_info)
set the printing context of the price cell
Definition pricecell.c:272
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
void gnc_completion_cell_set_autosize(CompletionCell *cell, gboolean autosize)
Determines whether the popup list autosizes itself or uses all available space.
void gnc_combo_cell_add_menu_item(ComboCell *cell, const char *menustr)
Add a menu item to the list.
#define GNC_COMMODITY_MAX_FRACTION
Max fraction is 10^9 because 10^10 would require changing it to an int64_t.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
gboolean gnc_commodity_is_iso(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency.
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time(time64 *tbuf)
get the current time
Definition gnc-date.cpp:262
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition Account.cpp:4103
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition Account.cpp:4119
void xaccTransSetDescription(Transaction *trans, const char *desc)
Sets the transaction Description.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition Account.cpp:4091
void xaccTransSetNum(Transaction *trans, const char *xnum)
Sets the transaction Number (or ID) field; rather than use this function directly,...
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing.
#define xaccTransGetGUID(X)
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id,...
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3)).
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...
void xaccTransRecordPrice(Transaction *trans, PriceSource source)
The xaccTransRecordPrice() method iterates through the splits and and record the non-currency equival...
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
void xaccTransSetNotes(Transaction *trans, const char *notes)
Sets the transaction Notes.
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,...
Definition Account.cpp:3106
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition guid.cpp:165
Account * gnc_ui_new_accounts_from_name_window(GtkWindow *parent, const char *name)
Display a modal window for creating a new account.
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.
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_commodity * gnc_default_currency(void)
Return the default currency set by the user.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
int gnc_numeric_same(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Equivalence predicate: Convert both a and b to denom using the specified DENOM and method HOW,...
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
gnc_numeric gnc_numeric_mul(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Multiply a times b, returning the product.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
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 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.
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.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
GtkWidget *(* SRGetParentCallback)(gpointer user_data)
Callback function type.
SplitRegisterStyle
Register styles.
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 gnc_split_register_set_read_only(SplitRegister *reg, gboolean read_only)
Sets whether a register window is "read only".
SplitRegisterType
Register types.
gboolean gnc_split_register_changed(SplitRegister *reg)
Returns TRUE if the register has changed cells.
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.
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,...
SplitRegisterTypeGroup
Register group types.
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
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...
SplitRegisterTypeGroup gnc_split_register_get_register_group(SplitRegister *reg)
Group registers for common layouts.
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...
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
const char * gnc_split_register_get_credit_string(SplitRegister *reg)
Return the credit string used in the register.
TableLayout * gnc_split_register_layout_new(SplitRegister *reg)
Generate the split register layout.
gboolean gnc_split_register_has_copied_item(void)
Return TRUE if copied_item holds a transaction or split.
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,...
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
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...
void gnc_split_register_unvoid_current_trans(SplitRegister *reg)
Unvoids the transaction associated with the current cursor, if non-NULL.
void gnc_split_register_set_auto_complete(SplitRegister *reg, gboolean do_auto_complete)
Sets whether a register uses auto-completion.
void gnc_split_register_cut_current(SplitRegister *reg)
Equivalent to copying the current entity and the deleting it with the appropriate delete method.
const char * gnc_split_register_get_debit_string(SplitRegister *reg)
Return the debit string used in the register.
void gnc_split_register_void_current_trans(SplitRegister *reg, const char *reason)
Voids the transaction associated with the current cursor, if non-NULL.
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.
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
void gnc_split_register_expand_current_trans(SplitRegister *reg, gboolean expand)
Expand the current transaction if it is collapsed.
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.
TableControl * gnc_split_register_control_new(void)
Create a new TableControl specialized for the 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,...
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...
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
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_split_register_set_reverse_sort(SplitRegister *reg, gboolean reverse_sort)
Sets a split register's reverse sort order based on register.
gboolean gnc_split_register_is_blank_split(SplitRegister *reg, Split *split)
Return TRUE if split is the blank_split.
void gnc_split_register_config(SplitRegister *reg, SplitRegisterType newtype, SplitRegisterStyle newstyle, gboolean use_double_line)
Sets a split register's type, style or line use.
CursorClass
Types of cursors.
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
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.
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_destroy(SplitRegister *reg)
Destroys a split register.
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL.
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
void gnc_table_move_cursor(Table *table, VirtualLocation new_virt_loc)
will move the cursor (but not the cursor GUI) to the indicated location.
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
void gnc_table_set_virt_cell_data(Table *table, VirtualCellLocation vcell_loc, gconstpointer vcell_data)
Set the virtual cell data for a particular location.
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
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.
#define CURSOR_HEADER
Standard Cursor Names.
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
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.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition Split.cpp:1506
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id,...
Definition Split.cpp:1091
#define xaccSplitGetGUID(X)
Definition Split.h:579
Split * xaccMallocSplit(QofBook *book)
Constructor.
#define VREC
split is void
Definition Split.h:77
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Definition Split.cpp:1995
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
#define NREC
not reconciled or cleared
Definition Split.h:76
#define YREC
The Split has been reconciled.
Definition Split.h:74
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition qofutil.cpp:187
TableControl specialized for the SplitRegister.
Create the actual register visual layout.
Save handlers for the SplitRegister Model and Template SplitRegister model.
TableModels specialized for SplitRegister and template SplitRegister.
private declarations for SplitRegister
API for checkbook register display area.
STRUCTS.
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it.
Definition combocell.h:53
The CompletionCell object implements a cell handler with a "combination-box" pull-down menu in it.
The DateCell object implements a date handling cell.
Definition datecell.h:92
The type used to store guids in C.
Definition guid.h:75
The NumCell object implements a number handling cell.
Definition numcell.h:40
The PriceCell object implements a cell handler that stores a single double-precision value,...
Definition pricecell.h:55
The RecnCell object implements a cell handler that will cycle through a series of single-character va...
Definition recncell.h:48
holds information about each virtual cell.
gpointer vcell_data
Array of physical cells.
unsigned int visible
Used by higher-level code.
Declarations for the Table object.