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