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