27#include <glib/gi18n.h>
32#include "gnc-component-manager.h"
35#include "gnc-warnings.h"
38#include "dialog-transfer.h"
39#include "dialog-utils.h"
45#include "engine-helpers.h"
46#include <gnc-gui-query.h>
50static QofLogModule log_module = GNC_MOD_LEDGER;
53check_imbalance_fraction (
const SplitRegister *reg,
54 const gnc_monetary *imbal_mon,
55 const Transaction *trans)
58 auto denom_diff = imbal_mon->value.denom > commodity_fraction;
61 const auto imbal_comm = imbal_mon->commodity;
63 node = g_list_next (node))
65 auto split{GNC_SPLIT(node->data)};
67 if (!(split && xaccTransStillHasSplit (trans, split)))
84 _(
"This transaction cannot be balanced: The imbalance is a fraction smaller than the commodity allows."));
90gnc_split_register_balance_trans (SplitRegister *reg, Transaction *trans)
97 GList *radio_list = NULL;
98 const char *title =
_(
"Rebalance Transaction");
99 const char *message =
_(
"The current transaction is not balanced.");
102 gboolean two_accounts;
103 gboolean multi_currency;
110 MonetaryList *imbal_list;
111 gnc_monetary *imbal_mon;
119 multi_currency = TRUE;
122 imbal_mon =
static_cast<gnc_monetary*
>(imbal_list->data);
123 if (!imbal_list->next &&
126 multi_currency = FALSE;
128 multi_currency = TRUE;
130 if (multi_currency && check_imbalance_fraction (reg, imbal_mon, trans))
139 multi_currency = FALSE;
144 if (other_split == NULL)
153 if (other_split == NULL || multi_currency)
155 two_accounts = FALSE;
156 other_account = NULL;
164 default_account = gnc_split_register_get_default_account (reg);
170 if (default_account == other_account)
177 if (default_account == other_account)
178 two_accounts = FALSE;
180 radio_list = g_list_append (radio_list,
181 _(
"Balance it _manually"));
182 radio_list = g_list_append (radio_list,
183 _(
"Let GnuCash _add an adjusting split"));
185 if (reg->type < NUM_SINGLE_REGISTER_TYPES && !multi_currency)
187 radio_list = g_list_append (radio_list,
188 _(
"Adjust current account _split total"));
193 radio_list = g_list_append (radio_list,
194 _(
"Adjust _other account split total"));
201 choice = gnc_choose_radio_option_dialog (gnc_split_register_get_parent (reg),
208 g_list_free (radio_list);
234gnc_split_register_old_split_empty_p (SplitRegister *reg, Split *split)
240 string = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
241 if ((
string != NULL) && (*
string !=
'\0'))
244 string = gnc_table_layout_get_cell_value (reg->table->layout, XFRM_CELL);
245 if ((
string != NULL) && (*
string !=
'\0'))
248 cell = gnc_table_layout_get_cell (reg->table->layout, CRED_CELL);
256 cell = gnc_table_layout_get_cell (reg->table->layout, DEBT_CELL);
271gnc_split_register_check_debcred (SplitRegister *reg,
272 const char *cell_name)
274 if ((gnc_cell_name_equal (cell_name, DEBT_CELL) &&
275 gnc_table_layout_get_cell_changed (reg->table->layout, DEBT_CELL, FALSE)) ||
276 (gnc_cell_name_equal (cell_name, CRED_CELL) &&
277 gnc_table_layout_get_cell_changed (reg->table->layout, CRED_CELL, FALSE)))
279 SRInfo *info = gnc_split_register_get_info (reg);
285 info->rate_reset = RATE_RESET_REQD;
286 if (info->auto_complete)
301gnc_split_register_check_account (SplitRegister *reg,
302 const char *cell_name)
304 g_return_val_if_fail (reg, TRUE);
309 if (gnc_cell_name_equal (cell_name, XFRM_CELL))
311 if (gnc_table_layout_get_cell_changed (reg->table->layout,
313 cell = gnc_table_layout_get_cell (reg->table->layout,
316 else if (gnc_cell_name_equal (cell_name, MXFRM_CELL))
318 if (gnc_table_layout_get_cell_changed (reg->table->layout,
320 cell = gnc_table_layout_get_cell (reg->table->layout,
327 auto name = gnc_basic_cell_get_value (cell);
331 auto changed = g_strcmp0 (name, orig_name);
335 gnc_basic_cell_set_changed (cell, FALSE);
340 DEBUG(
"Changed to %s", name ? name :
"NULL");
341 if (!name || *name ==
'\0' ||
342 g_strcmp0 (name, SPLIT_TRANS_STR) == 0 ||
343 g_strcmp0 (name, STOCK_SPLIT_STR) == 0)
347 auto *new_acct = gnc_split_register_get_account_by_name (reg, cell, name);
351 gnc_split_register_set_cell_fractions (reg, split);
356 auto *info = gnc_split_register_get_info (reg);
357 auto rate_cell = (
PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
365 DEBUG(
"Commodity is still %s. Leaving rate unchanged.",
371 DEBUG(
"Commodity now %s (originally %s). Clearing rate.",
376 info->rate_account = new_acct;
377 info->rate_reset = RATE_RESET_REQD;
385 GNC_HOW_DENOM_REDUCE);
387 if (!gnc_numeric_check (orig_rate))
391 info->rate_account = new_acct;
392 info->rate_reset = RATE_RESET_NOT_REQD;
396 DEBUG(
"Can't get rate. Using zero.");
398 info->rate_account = new_acct;
399 info->rate_reset = RATE_RESET_REQD;
408is_trading_split (Split *split)
415gnc_split_register_move_cursor (VirtualLocation *p_new_virt_loc,
418 VirtualLocation new_virt_loc = *p_new_virt_loc;
419 VirtualCellLocation old_trans_split_loc;
420 auto reg =
static_cast<SplitRegister*
>(user_data);
421 Transaction *pending_trans;
422 Transaction *new_trans;
423 Transaction *old_trans;
424 Split *old_trans_split{
nullptr};
425 Split *new_trans_split;
427 Split *old_split{
nullptr};
430 gboolean exact_traversal;
435 ENTER(
"reg=%p, p_new_virt_loc=%p (%d, %d)",
437 new_virt_loc.vcell_loc.virt_row,
438 new_virt_loc.vcell_loc.virt_col);
442 LEAVE(
"no register");
446 info = gnc_split_register_get_info (reg);
453 !is_trading_split (s))
458 exact_traversal = info->exact_traversal;
460 if (info->traverse_to_new)
462 if (old_class == CURSOR_CLASS_SPLIT)
463 new_trans = old_trans;
468 new_trans_split = NULL;
469 new_class = CURSOR_CLASS_NONE;
471 else if (!info->hint_set_by_traverse)
474 new_trans = gnc_split_register_get_trans (reg, new_virt_loc.vcell_loc);
477 new_split = gnc_split_register_get_split (reg, new_virt_loc.vcell_loc);
480 new_trans_split = gnc_split_register_get_trans_split (reg,
481 new_virt_loc.vcell_loc,
485 new_virt_loc.vcell_loc);
489 new_trans = info->cursor_hint_trans;
490 new_split = info->cursor_hint_split;
491 new_trans_split = info->cursor_hint_trans_split;
492 new_class = info->cursor_hint_cursor_class;
495 info->hint_set_by_traverse = FALSE;
496 info->reg_loaded = FALSE;
498 gnc_suspend_gui_refresh ();
503 gnc_get_current_book ());
505 gnc_get_current_book ());
508 if ((old_class == CURSOR_CLASS_SPLIT) &&
510 (old_split != new_split) &&
511 gnc_split_register_old_split_empty_p (reg, old_split))
524 current_row = reg->table->current_cursor_loc.vcell_loc.virt_row;
525 if (new_virt_loc.vcell_loc.virt_row > current_row)
526 new_virt_loc.vcell_loc.virt_row--;
529 else if ((pending_trans != NULL) &&
530 (pending_trans == old_trans) &&
531 (pending_trans != blank_trans) &&
532 (old_trans != new_trans))
534 if (gnc_split_register_balance_trans (reg, pending_trans))
537 new_trans = old_trans;
538 new_split = old_split;
539 new_trans_split = old_trans_split;
540 new_class = old_class;
541 new_virt_loc = reg->table->current_cursor_loc;
546 info->pending_trans_guid = *
guid_null ();
549 else g_assert_not_reached ();
551 pending_trans = NULL;
555 else if (old_trans &&
556 (old_trans != new_trans) &&
559 gnc_split_register_balance_trans (reg, old_trans))
562 new_trans = old_trans;
563 new_split = old_split;
564 new_trans_split = old_trans_split;
565 new_class = old_class;
566 new_virt_loc = reg->table->current_cursor_loc;
571 info->cursor_hint_trans = new_trans;
572 info->cursor_hint_split = new_split;
573 info->cursor_hint_trans_split = new_trans_split;
574 info->cursor_hint_cursor_class = new_class;
578 if (old_class != new_class)
579 info->change_confirmed = FALSE;
581 if (old_split != new_split)
583 info->change_confirmed = FALSE;
584 info->rate_account = NULL;
585 info->rate_reset = RATE_RESET_NOT_REQD;
588 gnc_resume_gui_refresh ();
593 VirtualCellLocation vcell_loc;
595 if (!info->reg_loaded)
600 if (gnc_split_register_find_split (reg, new_trans, new_trans_split,
601 new_split, new_class, &vcell_loc))
603 new_virt_loc.vcell_loc = vcell_loc;
606 new_virt_loc.vcell_loc = reg->table->current_cursor_loc.vcell_loc;
608 new_trans = gnc_split_register_get_trans (reg, new_virt_loc.vcell_loc);
609 new_split = gnc_split_register_get_split (reg, new_virt_loc.vcell_loc);
610 new_trans_split = gnc_split_register_get_trans_split (reg,
611 new_virt_loc.vcell_loc,
614 new_virt_loc.vcell_loc);
616 else if (info->traverse_to_new)
618 new_trans = info->cursor_hint_trans;
619 new_split = info->cursor_hint_split;
620 new_trans_split = info->cursor_hint_trans_split;
621 new_class = info->cursor_hint_cursor_class;
626 *p_new_virt_loc = new_virt_loc;
628 PINFO(
"after move %d %d",
629 new_virt_loc.vcell_loc.virt_row,
630 new_virt_loc.vcell_loc.virt_col);
636 gnc_split_register_set_cell_fractions (reg, new_split);
645 (old_trans_split != new_trans_split))
647 VirtualCellLocation vc_loc;
649 vc_loc = old_trans_split_loc;
651 gnc_split_register_get_passive_cursor (reg));
653 reg->style == REG_STYLE_JOURNAL);
655 if ((REG_STYLE_AUTO_LEDGER == reg->style) ||
656 (REG_STYLE_JOURNAL == reg->style))
658 gnc_split_register_get_trans_split (reg, new_virt_loc.vcell_loc,
661 gnc_split_register_get_active_cursor (reg));
663 reg->style == REG_STYLE_JOURNAL);
666 info->trans_expanded = FALSE;
673 info->cursor_hint_trans = new_trans;
674 info->cursor_hint_split = new_split;
675 info->cursor_hint_trans_split = new_trans_split;
676 info->cursor_hint_cursor_class = new_class;
678 gnc_split_register_set_cell_fractions (reg, new_split);
685 VirtualCellLocation vc_loc;
688 gnc_table_leave_update (reg->table, reg->table->current_cursor_loc);
690 gnc_split_register_get_trans_split (reg, p_new_virt_loc->vcell_loc,
692 gnc_split_register_show_trans (reg, vc_loc);
699gnc_find_split_in_trans_by_memo (Transaction *trans,
const char *memo,
704 auto split = GNC_SPLIT(n->data);
706 if (!(split && xaccTransStillHasSplit (trans, split)))
725gnc_find_split_in_account_by_memo (
Account *account,
const char *memo,
728 if (account ==
nullptr)
return nullptr;
730 const auto& splits = xaccAccountGetSplits (account);
731 for (
auto it = splits.rbegin(); it != splits.rend(); it++)
740gnc_find_split_in_reg_by_memo (SplitRegister *reg,
const char *memo,
743 int virt_row, virt_col;
744 int num_rows, num_cols;
745 Transaction *last_trans;
747 if (!reg || !reg->table)
750 num_rows = reg->table->num_virt_rows;
751 num_cols = reg->table->num_virt_cols;
755 for (virt_row = num_rows - 1; virt_row >= 0; virt_row--)
756 for (virt_col = num_cols - 1; virt_col >= 0; virt_col--)
760 VirtualCellLocation vcell_loc = { virt_row, virt_col };
762 split = gnc_split_register_get_split (reg, vcell_loc);
765 if (trans == last_trans)
768 split = gnc_find_split_in_trans_by_memo (trans, memo, unit_price);
779gnc_find_trans_in_reg_by_desc (SplitRegister *reg,
const char *description)
781 int virt_row, virt_col;
782 int num_rows, num_cols;
783 Transaction *last_trans;
785 if (!reg || !reg->table)
788 num_rows = reg->table->num_virt_rows;
789 num_cols = reg->table->num_virt_cols;
793 for (virt_row = num_rows - 1; virt_row >= 0; virt_row--)
794 for (virt_col = num_cols - 1; virt_col >= 0; virt_col--)
798 VirtualCellLocation vcell_loc = { virt_row, virt_col };
800 split = gnc_split_register_get_split (reg, vcell_loc);
803 if (trans == last_trans)
818gnc_split_register_auto_completion (SplitRegister *reg,
819 gncTableTraversalDir dir,
820 VirtualLocation *p_new_virt_loc)
822 SRInfo *info = gnc_split_register_get_info (reg);
823 VirtualLocation new_virt_loc;
825 Transaction *pending_trans;
826 Transaction *blank_trans;
827 const char *cell_name;
834 if (!reg->do_auto_complete)
838 gnc_get_current_book ());
842 gnc_get_current_book ());
845 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
854 cell_name = gnc_table_get_current_cell_name (reg->table);
856 switch (cursor_class)
858 case CURSOR_CLASS_TRANS:
860 Transaction *auto_trans;
864 if (blank_trans == NULL)
868 if (trans != blank_trans)
872 if (!gnc_cell_name_equal (cell_name, DESC_CELL))
877 if (gnc_table_layout_get_cell_changed (reg->table->layout,
879 gnc_table_layout_get_cell_changed (reg->table->layout,
881 gnc_table_layout_get_cell_changed (reg->table->layout,
883 gnc_table_layout_get_cell_changed (reg->table->layout,
885 gnc_table_layout_get_cell_changed (reg->table->layout,
887 gnc_table_layout_get_cell_changed (reg->table->layout,
889 gnc_table_layout_get_cell_changed (reg->table->layout,
891 gnc_table_layout_get_cell_changed (reg->table->layout,
896 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
901 desc = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
902 if ((desc == NULL) || (*desc ==
'\0'))
906 if (gnc_split_register_get_default_account (reg) != NULL)
908 Account *account = gnc_split_register_get_default_account (reg);
913 auto_trans = gnc_find_trans_in_reg_by_desc (reg, desc);
915 if (auto_trans == NULL)
918 gnc_suspend_gui_refresh ();
924 if (pending_trans != trans)
930 if (pending_trans != NULL)
934 else g_assert_not_reached ();
939 gnc_get_current_book ());
940 g_assert (pending_trans == trans);
943 gnc_get_current_book ());
945 gnc_copy_trans_onto_trans (auto_trans, trans, FALSE, template_account, FALSE);
951 if (gnc_split_register_get_default_account (reg) != NULL)
953 Account *default_account = gnc_split_register_get_default_account (reg);
962 auto s = GNC_SPLIT(n->data);
963 if (s && xaccTransStillHasSplit (trans, s) &&
973 if (blank_split == NULL)
978 DEBUG(
"blank_split=%p", blank_split);
980 info->blank_split_edited = TRUE;
985 sd = gnc_split_register_save_data_new (trans, blank_split,
987 gnc_table_save_cells (reg->table, sd);
988 gnc_split_register_save_data_destroy (sd);
991 gnc_resume_gui_refresh ();
995 GNC_PREF_TAB_TRANS_MEMORISED))
1000 if (gnc_table_get_current_cell_location (reg->table, cell_name, &new_virt_loc))
1001 *p_new_virt_loc = new_virt_loc;
1007 case CURSOR_CLASS_SPLIT:
1011 gboolean unit_price;
1019 if (!gnc_cell_name_equal (cell_name, MEMO_CELL))
1024 if (gnc_table_layout_get_cell_changed (reg->table->layout,
1026 gnc_table_layout_get_cell_changed (reg->table->layout,
1027 MXFRM_CELL, TRUE) ||
1028 gnc_table_layout_get_cell_changed (reg->table->layout,
1030 gnc_table_layout_get_cell_changed (reg->table->layout,
1032 gnc_table_layout_get_cell_changed (reg->table->layout,
1037 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1042 memo = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
1043 if ((memo == NULL) || (*memo ==
'\0'))
1048 unit_price = !gnc_table_get_current_cell_location (reg->table,
1052 if (gnc_split_register_get_default_account (reg) != NULL)
1054 Account *account = gnc_split_register_get_default_account (reg);
1056 auto_split = gnc_find_split_in_account_by_memo (account, memo,
1060 auto_split = gnc_find_split_in_reg_by_memo (reg, memo, unit_price);
1062 if (auto_split == NULL)
1068 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1071 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1072 gnc_combo_cell_set_value ((
ComboCell *) cell,
1073 gnc_get_num_action (NULL, auto_split));
1077 cell = gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
1080 reg->show_leaf_accounts);
1081 gnc_combo_cell_set_value ((
ComboCell *) cell, account_name);
1082 g_free (account_name);
1084 gnc_basic_cell_set_changed (cell, TRUE);
1086 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1088 !gnc_table_layout_get_cell_changed (reg->table->layout,
1091 BasicCell *debit_cell;
1092 BasicCell *credit_cell;
1096 debit_cell = gnc_table_layout_get_cell (reg->table->layout,
1098 credit_cell = gnc_table_layout_get_cell (reg->table->layout,
1105 gnc_basic_cell_set_changed (debit_cell, TRUE);
1106 gnc_basic_cell_set_changed (credit_cell, TRUE);
1116 if (gnc_table_get_current_cell_location (reg->table, cell_name,
1118 *p_new_virt_loc = new_virt_loc;
1131gnc_split_register_check_stock_action (SplitRegister *reg,
1132 const char *cell_name)
1139 if (!gnc_cell_name_equal (cell_name, ACTN_CELL) ||
1140 !gnc_table_layout_get_cell_changed (reg->table->layout,
1144 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1148 if ((name == NULL) || (*name ==
'\0'))
1151 buy = g_strcmp0 (name, ACTION_BUY_STR) == 0;
1152 sell = g_strcmp0 (name, ACTION_SELL_STR) == 0;
1156 cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1165 gnc_basic_cell_set_changed (cell, TRUE);
1170gnc_split_register_check_stock_shares (SplitRegister *reg,
1171 const char *cell_name)
1178 if (!gnc_cell_name_equal (cell_name, SHRS_CELL) ||
1179 !gnc_table_layout_get_cell_changed (reg->table->layout,
1183 cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1191 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1196 if (g_strcmp0 (name,
"") == 0 ||
1197 g_strcmp0 (name, buy ? ACTION_SELL_STR : ACTION_BUY_STR) == 0)
1199 gnc_combo_cell_set_value ((
ComboCell *)cell,
1200 buy ? ACTION_BUY_STR : ACTION_SELL_STR);
1201 gnc_basic_cell_set_changed (cell, TRUE);
1211gnc_split_register_check_cell (SplitRegister *reg,
const char *cell_name)
1213 ENTER(
"reg=%p, cell_name=%s", reg, cell_name ? cell_name :
"NULL");
1216 if (!gnc_split_register_check_account (reg, cell_name))
1218 LEAVE(
"account check failed");
1223 if (!gnc_split_register_check_debcred (reg, cell_name))
1225 LEAVE(
"debit/credit check failed");
1230 if ((reg->type == STOCK_REGISTER) ||
1231 (reg->type == PORTFOLIO_LEDGER) ||
1232 (reg->type == CURRENCY_REGISTER))
1234 gnc_split_register_check_stock_action (reg, cell_name);
1235 gnc_split_register_check_stock_shares (reg, cell_name);
1243gnc_split_register_get_account_always (SplitRegister *reg,
1244 const char *cell_name)
1249 cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
1252 name = gnc_basic_cell_get_value (cell);
1256 if (g_strcmp0 (name, SPLIT_TRANS_STR) == 0)
1259 return gnc_split_register_get_account_by_name (reg, cell, name);
1266gnc_split_register_xfer_dialog (SplitRegister *reg, Transaction *txn,
1273 g_return_val_if_fail (reg, NULL);
1274 g_return_val_if_fail (reg->table, NULL);
1276 cur = reg->table->current_cursor;
1279 xfer = gnc_xfer_dialog (gnc_split_register_get_parent (reg), NULL);
1280 g_return_val_if_fail (xfer, NULL);
1285 gnc_xfer_dialog_set_description (xfer, gnc_basic_cell_get_value (cell));
1289 gnc_xfer_dialog_set_description (xfer, str ? str :
"");
1295 gnc_xfer_dialog_set_memo (xfer, gnc_basic_cell_get_value (cell));
1299 gnc_xfer_dialog_set_memo (xfer, str ? str :
"");
1305 gnc_xfer_dialog_set_num (xfer, gnc_basic_cell_get_value (cell));
1308 const char *str = gnc_get_num_action (txn, split);
1309 gnc_xfer_dialog_set_num (xfer, str ? str :
"");
1318 gnc_xfer_dialog_set_date (xfer, time);
1339 Split *split, *osplit;
1341 gnc_commodity *txn_cur, *xfer_com, *reg_com;
1342 gnc_numeric amount, exch_rate;
1344 gboolean expanded = FALSE;
1346 const char *message;
1349 ENTER(
"reg=%p, force_dialog=%s", reg, force_dialog ?
"TRUE" :
"FALSE" );
1352 if (reg->is_template)
1354 LEAVE(
"Template transaction, rate makes no sense.");
1370 message = _(
"Edit prices/exchange rates directly in the split line.");
1371 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1373 LEAVE(
"no rate cell");
1377 rate_cell = (
PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL);
1383 message = _(
"Edit prices/exchange rates directly in the split line.");
1384 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1386 LEAVE(
"null rate cell");
1391 info = gnc_split_register_get_info (reg);
1394 info->rate_reset != RATE_RESET_REQD)
1396 LEAVE(
"rate already non-zero");
1405 if (expanded && cursor_class == CURSOR_CLASS_TRANS)
1409 message = _(
"You need to select a split in order to modify its exchange "
1411 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1413 LEAVE(
"expanded with transaction cursor; nothing to do");
1418 xfer_acc = gnc_split_register_get_account_always (reg,
1419 expanded ? XFRM_CELL : MXFRM_CELL);
1422 if (force_dialog && !expanded && !xfer_acc)
1424 message = _(
"You need to expand the transaction in order to modify its "
1426 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1427 LEAVE(
"%s", message);
1436 message = _(
"The entered account could not be found.");
1437 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1439 LEAVE(
"no xfer account");
1449 reg_acc = gnc_split_register_get_default_account (reg);
1464 LEAVE(
"txn and account currencies match, and not forcing");
1469 if (expanded || osplit == NULL)
1471 message = _(
"The two currencies involved equal each other.");
1472 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1473 LEAVE(
"register is expanded or osplit == NULL; not forcing dialog");
1484 message = _(
"The two currencies involved equal each other.");
1485 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1486 LEAVE(
"reg commodity == txn commodity; not forcing");
1495 if (!expanded && osplit &&
1496 gnc_split_register_split_needs_amount (reg, split) &&
1497 gnc_split_register_split_needs_amount (reg, osplit))
1499 message = _(
"You need to expand the transaction in order to modify its "
1503 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1505 LEAVE(
"%s", message);
1516 if (!expanded && osplit &&
1526 amount = gnc_split_register_debcred_cell_value (reg);
1536 message = _(
"The split's amount is zero, so no exchange rate is needed.");
1537 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1539 LEAVE(
"amount is zero; no exchange rate needed");
1548 info->rate_reset != RATE_RESET_REQD &&
1551 LEAVE(
"gain/loss split; no exchange rate needed");
1556 xfer = gnc_split_register_xfer_dialog (reg, txn, split);
1557 gnc_xfer_dialog_is_exchange_dialog (xfer, &exch_rate);
1558 if (gnc_xfer_dialog_run_exchange_dialog (xfer, &exch_rate, amount,
1559 reg_acc, txn, xfer_com, expanded))
1562 LEAVE(
"leaving rate unchanged");
1569 gnc_basic_cell_set_changed (&rate_cell->cell, TRUE);
1570 info->rate_account = xfer_acc;
1571 info->rate_reset = RATE_RESET_DONE;
1578transaction_changed_confirm (VirtualLocation *p_new_virt_loc,
1579 VirtualLocation *virt_loc,
1580 SplitRegister *reg, Transaction *new_trans,
1581 gboolean exact_traversal)
1583 GtkWidget *dialog, *window;
1585 const char *title =
_(
"Save the changed transaction?");
1586 const char *message =
1587 _(
"The current transaction has been changed. Would you like to "
1588 "record the changes before moving to a new transaction, discard the "
1589 "changes, or return to the changed transaction?");
1591 window = gnc_split_register_get_parent (reg);
1592 dialog = gtk_message_dialog_new (GTK_WINDOW(window),
1593 GTK_DIALOG_DESTROY_WITH_PARENT,
1594 GTK_MESSAGE_QUESTION,
1597 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1599 gtk_dialog_add_buttons (GTK_DIALOG(dialog),
1600 _(
"_Discard Changes"), GTK_RESPONSE_REJECT,
1601 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1602 _(
"_Record Changes"), GTK_RESPONSE_ACCEPT,
1604 response = gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_MOD);
1605 gtk_widget_destroy (dialog);
1609 case GTK_RESPONSE_ACCEPT:
1612 case GTK_RESPONSE_REJECT:
1614 VirtualCellLocation vcell_loc;
1620 if (reg->unrecn_splits != NULL)
1622 g_list_free (reg->unrecn_splits);
1623 reg->unrecn_splits = NULL;
1626 new_split = gnc_split_register_get_split (reg, virt_loc->vcell_loc);
1627 trans_split = gnc_split_register_get_trans_split (reg,
1628 virt_loc->vcell_loc,
1631 virt_loc->vcell_loc);
1635 if (gnc_split_register_find_split (reg, new_trans, trans_split,
1636 new_split, new_class, &vcell_loc))
1637 virt_loc->vcell_loc = vcell_loc;
1642 *p_new_virt_loc = *virt_loc;
1646 case GTK_RESPONSE_CANCEL:
1667gnc_split_register_traverse (VirtualLocation *p_new_virt_loc,
1668 gncTableTraversalDir dir,
1671 auto reg =
static_cast<SplitRegister*
>(user_data);
1672 Transaction *pending_trans;
1673 VirtualLocation virt_loc;
1674 Transaction *trans, *new_trans;
1678 const char *cell_name;
1680 g_return_val_if_fail (p_new_virt_loc, TRUE);
1682 ENTER(
"reg=%p, p_new_virt_loc=%p (%d,%d), dir=%d",
1683 reg, p_new_virt_loc,
1684 (*p_new_virt_loc).vcell_loc.virt_row,
1685 (*p_new_virt_loc).vcell_loc.virt_col, dir);
1689 LEAVE(
"no register");
1693 info = gnc_split_register_get_info (reg);
1695 if (info->first_pass)
1697 LEAVE(
"first pass");
1702 gnc_get_current_book ());
1703 virt_loc = *p_new_virt_loc;
1705 info->exact_traversal = (dir == GNC_TABLE_TRAVERSE_POINTER);
1711 LEAVE(
"no transaction");
1716 changed = gnc_table_current_cursor_changed (reg->table, FALSE);
1717 if (!changed && (pending_trans != trans))
1720 info->exact_traversal);
1722 *p_new_virt_loc = virt_loc;
1724 LEAVE(
"no changes");
1729 cell_name = gnc_table_get_current_cell_name (reg->table);
1730 if (!gnc_split_register_check_cell (reg, cell_name))
1732 LEAVE(
"check cell");
1739 VirtualLocation virt_loc;
1741 if (!changed && !info->blank_split_edited)
1744 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
1747 virt_loc = reg->table->current_cursor_loc;
1751 virt_loc = reg->table->current_cursor_loc;
1752 if (gnc_table_move_tab (reg->table, &virt_loc, TRUE))
1758 LEAVE(
"no exchange rate");
1762 *p_new_virt_loc = reg->table->current_cursor_loc;
1763 (p_new_virt_loc->vcell_loc.virt_row)++;
1764 p_new_virt_loc->phys_row_offset = 0;
1765 p_new_virt_loc->phys_col_offset = 0;
1767 info->traverse_to_new = TRUE;
1769 LEAVE(
"off end of last line");
1779 if (gnc_split_register_auto_completion (reg, dir, p_new_virt_loc))
1781 info->auto_complete = TRUE;
1782 LEAVE(
"auto-complete");
1790 VirtualLocation virt_loc;
1799 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
1802 virt_loc = reg->table->current_cursor_loc;
1803 old_virt_row = virt_loc.vcell_loc.virt_row;
1805 if (gnc_table_move_tab (reg->table, &virt_loc, TRUE) &&
1806 old_virt_row == virt_loc.vcell_loc.virt_row)
1819 LEAVE(
"no exchange rate");
1823 info->cursor_hint_trans = trans;
1824 info->cursor_hint_split = split;
1825 info->cursor_hint_trans_split =
1827 info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1828 info->hint_set_by_traverse = TRUE;
1830 LEAVE(
"off end of blank split");
1837 int old_virt_row = reg->table->current_cursor_loc.vcell_loc.virt_row;
1841 info->exact_traversal);
1845 if (virt_loc.vcell_loc.virt_row != old_virt_row)
1849 LEAVE(
"no exchange rate");
1856 new_trans = gnc_split_register_get_trans (reg, virt_loc.vcell_loc);
1857 if (trans == new_trans)
1859 *p_new_virt_loc = virt_loc;
1861 LEAVE(
"staying within txn");
1868 LEAVE(
"txn change");
1869 return transaction_changed_confirm (p_new_virt_loc, &virt_loc, reg,
1870 new_trans, info->exact_traversal);
1878 control->move_cursor = gnc_split_register_move_cursor;
1879 control->traverse = gnc_split_register_traverse;
1885gnc_split_register_recn_cell_confirm (
char old_flag, gpointer data)
1887 auto reg =
static_cast<SplitRegister*
>(data);
1888 GtkWidget *dialog, *window;
1890 const gchar *title =
_(
"Mark split as unreconciled?");
1891 const gchar *message =
1892 _(
"You are about to mark a reconciled split as unreconciled. Doing "
1893 "so might make future reconciliation difficult! Continue "
1894 "with this change?");
1896 if (old_flag !=
YREC)
1900 window = gnc_split_register_get_parent (reg);
1901 dialog = gtk_message_dialog_new (GTK_WINDOW(window),
1902 GTK_DIALOG_DESTROY_WITH_PARENT,
1903 GTK_MESSAGE_WARNING,
1906 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1908 gtk_dialog_add_button (GTK_DIALOG(dialog),
1911 response = gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_RECD_SPLIT_UNREC);
1912 gtk_widget_destroy (dialog);
1913 return (response == GTK_RESPONSE_YES);
Account public routines (C++ api)
convert single-entry accounts to clean double-entry
Generic api to store and retrieve preferences.
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to.
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
@ ACCT_TYPE_TRADING
Account used to record multiple commodity transactions.
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
void gnc_price_cell_set_debt_credit_value(PriceCell *debit, PriceCell *credit, gnc_numeric amount)
updates two cells; the deb cell if amt is negative, the credit cell if amount is positive,...
gboolean gnc_price_cell_set_value(PriceCell *cell, gnc_numeric amount)
updates amount, returns TRUE if string representation actually changed
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
BasicCell * gnc_cellblock_get_cell_by_name(CellBlock *cellblock, const char *cell_name, int *row, int *col)
Searches by name for a particular cell in a CellBlock.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
void gnc_monetary_list_free(MonetaryList *list)
Free a MonetaryList and all the monetaries it points to.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
The xaccTransGetImbalance method returns a list giving the value of the transaction in each currency ...
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing.
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
#define xaccTransGetGUID(X)
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id,...
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Transaction * xaccAccountFindTransByDesc(const Account *acc, const char *description)
Returns a pointer to the transaction, not a copy.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
char * gnc_get_account_name_for_split_register(const Account *account, gboolean show_leaf_accounts)
Get either the full name of the account or the simple name, depending on the show_leaf_accounts.
#define PINFO(format, args...)
Print an informational note.
#define DEBUG(format, args...)
Print a debugging message.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define ENTER(format, args...)
Print a function entry debugging message.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
@ GNC_HOW_DENOM_REDUCE
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
void gnc_split_register_cancel_cursor_trans_changes(SplitRegister *reg)
Cancels any changes made to the current pending transaction, reloads the table from the engine,...
void gnc_split_register_set_trans_visible(SplitRegister *reg, VirtualCellLocation vcell_loc, gboolean visible, gboolean only_blank_split)
Set the visibility of the split rows belonging to a transaction located at vcell_loc.
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
TableControl * gnc_split_register_control_new(void)
Create a new TableControl specialized for the SplitRegister.
gboolean gnc_split_register_handle_exchange(SplitRegister *reg, gboolean force_dialog)
If needed display the transfer dialog to get a price/exchange rate and adjust the price cell accordin...
gboolean gnc_split_reg_has_rate_cell(SplitRegisterType type)
Determine if we need to perform any conversion on the splits in this transaction, and if so,...
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
CursorClass
Types of cursors.
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
gboolean gnc_table_virtual_cell_out_of_bounds(Table *table, VirtualCellLocation vcell_loc)
checks the given location and returns true if it is out of bounds of the table.
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
gboolean gnc_table_move_vertical_position(Table *table, VirtualLocation *virt_loc, int phys_row_offset)
Moves away from virtual location virt_loc by phys_row_offset physical rows.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gboolean xaccSplitDestroy(Split *split)
Destructor.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id,...
#define xaccSplitGetGUID(X)
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits.
#define YREC
The Split has been reconciled.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
TableControl specialized for the SplitRegister.
Save handlers for the SplitRegister Model and Template SplitRegister model.
private declarations for SplitRegister
API for checkbook register display area.
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it.
The DateCell object implements a date handling cell.
The PriceCell object implements a cell handler that stores a single double-precision value,...
Declarations for the Table object.