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> 50 static QofLogModule log_module = GNC_MOD_LEDGER;
53 check_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."));
90 gnc_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);
234 gnc_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);
271 gnc_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)
301 gnc_split_register_check_account (SplitRegister *reg,
302 const char *cell_name)
310 g_return_val_if_fail (reg, TRUE);
313 if (gnc_cell_name_equal (cell_name, XFRM_CELL))
315 if (gnc_table_layout_get_cell_changed (reg->table->layout,
317 cell = (
ComboCell *) gnc_table_layout_get_cell (reg->table->layout,
320 else if (gnc_cell_name_equal (cell_name, MXFRM_CELL))
322 if (gnc_table_layout_get_cell_changed (reg->table->layout,
324 cell = (
ComboCell *) gnc_table_layout_get_cell (reg->table->layout,
332 name = cell->cell.value;
333 DEBUG(
"Changed to %s", name ? name :
"NULL");
334 if (!name || *name ==
'\0' ||
335 g_strcmp0 (name, SPLIT_TRANS_STR) == 0 ||
336 g_strcmp0 (name, STOCK_SPLIT_STR) == 0)
340 info = gnc_split_register_get_info (reg);
341 new_acct = gnc_split_register_get_account_by_name (reg,
348 gnc_split_register_set_cell_fractions (reg, split);
362 DEBUG(
"Commodity is still %s. Leaving rate unchanged.",
368 DEBUG(
"Commodity now %s (originally %s). Clearing rate.",
373 info->rate_account = new_acct;
374 info->rate_reset = RATE_RESET_REQD;
388 info->rate_account = new_acct;
389 info->rate_reset = RATE_RESET_NOT_REQD;
393 DEBUG(
"Can't get rate. Using zero.");
395 info->rate_account = new_acct;
396 info->rate_reset = RATE_RESET_REQD;
405 is_trading_split (Split *split)
412 gnc_split_register_move_cursor (VirtualLocation *p_new_virt_loc,
415 VirtualLocation new_virt_loc = *p_new_virt_loc;
416 VirtualCellLocation old_trans_split_loc;
417 auto reg =
static_cast<SplitRegister*
>(user_data);
418 Transaction *pending_trans;
419 Transaction *new_trans;
420 Transaction *old_trans;
421 Split *old_trans_split{
nullptr};
422 Split *new_trans_split;
424 Split *old_split{
nullptr};
427 gboolean exact_traversal;
432 ENTER(
"reg=%p, p_new_virt_loc=%p (%d, %d)",
434 new_virt_loc.vcell_loc.virt_row,
435 new_virt_loc.vcell_loc.virt_col);
439 LEAVE(
"no register");
443 info = gnc_split_register_get_info (reg);
450 !is_trading_split (s))
455 exact_traversal = info->exact_traversal;
457 if (info->traverse_to_new)
459 if (old_class == CURSOR_CLASS_SPLIT)
460 new_trans = old_trans;
465 new_trans_split = NULL;
466 new_class = CURSOR_CLASS_NONE;
468 else if (!info->hint_set_by_traverse)
471 new_trans = gnc_split_register_get_trans (reg, new_virt_loc.vcell_loc);
474 new_split = gnc_split_register_get_split (reg, new_virt_loc.vcell_loc);
477 new_trans_split = gnc_split_register_get_trans_split (reg,
478 new_virt_loc.vcell_loc,
482 new_virt_loc.vcell_loc);
486 new_trans = info->cursor_hint_trans;
487 new_split = info->cursor_hint_split;
488 new_trans_split = info->cursor_hint_trans_split;
489 new_class = info->cursor_hint_cursor_class;
492 info->hint_set_by_traverse = FALSE;
493 info->reg_loaded = FALSE;
495 gnc_suspend_gui_refresh ();
500 gnc_get_current_book ());
502 gnc_get_current_book ());
505 if ((old_class == CURSOR_CLASS_SPLIT) &&
507 (old_split != new_split) &&
508 gnc_split_register_old_split_empty_p (reg, old_split))
521 current_row = reg->table->current_cursor_loc.vcell_loc.virt_row;
522 if (new_virt_loc.vcell_loc.virt_row > current_row)
523 new_virt_loc.vcell_loc.virt_row--;
526 else if ((pending_trans != NULL) &&
527 (pending_trans == old_trans) &&
528 (pending_trans != blank_trans) &&
529 (old_trans != new_trans))
531 if (gnc_split_register_balance_trans (reg, pending_trans))
534 new_trans = old_trans;
535 new_split = old_split;
536 new_trans_split = old_trans_split;
537 new_class = old_class;
538 new_virt_loc = reg->table->current_cursor_loc;
543 info->pending_trans_guid = *
guid_null ();
546 else g_assert_not_reached ();
548 pending_trans = NULL;
552 else if (old_trans &&
553 (old_trans != new_trans) &&
556 gnc_split_register_balance_trans (reg, old_trans))
559 new_trans = old_trans;
560 new_split = old_split;
561 new_trans_split = old_trans_split;
562 new_class = old_class;
563 new_virt_loc = reg->table->current_cursor_loc;
568 info->cursor_hint_trans = new_trans;
569 info->cursor_hint_split = new_split;
570 info->cursor_hint_trans_split = new_trans_split;
571 info->cursor_hint_cursor_class = new_class;
575 if (old_class != new_class)
576 info->change_confirmed = FALSE;
578 if (old_split != new_split)
580 info->change_confirmed = FALSE;
581 info->rate_account = NULL;
582 info->rate_reset = RATE_RESET_NOT_REQD;
585 gnc_resume_gui_refresh ();
590 VirtualCellLocation vcell_loc;
592 if (!info->reg_loaded)
597 if (gnc_split_register_find_split (reg, new_trans, new_trans_split,
598 new_split, new_class, &vcell_loc))
600 new_virt_loc.vcell_loc = vcell_loc;
603 new_virt_loc.vcell_loc = reg->table->current_cursor_loc.vcell_loc;
605 new_trans = gnc_split_register_get_trans (reg, new_virt_loc.vcell_loc);
606 new_split = gnc_split_register_get_split (reg, new_virt_loc.vcell_loc);
607 new_trans_split = gnc_split_register_get_trans_split (reg,
608 new_virt_loc.vcell_loc,
611 new_virt_loc.vcell_loc);
613 else if (info->traverse_to_new)
615 new_trans = info->cursor_hint_trans;
616 new_split = info->cursor_hint_split;
617 new_trans_split = info->cursor_hint_trans_split;
618 new_class = info->cursor_hint_cursor_class;
623 *p_new_virt_loc = new_virt_loc;
625 PINFO(
"after move %d %d",
626 new_virt_loc.vcell_loc.virt_row,
627 new_virt_loc.vcell_loc.virt_col);
633 gnc_split_register_set_cell_fractions (reg, new_split);
642 (old_trans_split != new_trans_split))
644 VirtualCellLocation vc_loc;
646 vc_loc = old_trans_split_loc;
648 gnc_split_register_get_passive_cursor (reg));
650 reg->style == REG_STYLE_JOURNAL);
652 if ((REG_STYLE_AUTO_LEDGER == reg->style) ||
653 (REG_STYLE_JOURNAL == reg->style))
655 gnc_split_register_get_trans_split (reg, new_virt_loc.vcell_loc,
658 gnc_split_register_get_active_cursor (reg));
660 reg->style == REG_STYLE_JOURNAL);
663 info->trans_expanded = FALSE;
670 info->cursor_hint_trans = new_trans;
671 info->cursor_hint_split = new_split;
672 info->cursor_hint_trans_split = new_trans_split;
673 info->cursor_hint_cursor_class = new_class;
675 gnc_split_register_set_cell_fractions (reg, new_split);
682 VirtualCellLocation vc_loc;
685 gnc_table_leave_update (reg->table, reg->table->current_cursor_loc);
687 gnc_split_register_get_trans_split (reg, p_new_virt_loc->vcell_loc,
689 gnc_split_register_show_trans (reg, vc_loc);
696 gnc_find_split_in_trans_by_memo (Transaction *trans,
const char *memo,
701 auto split = GNC_SPLIT(n->data);
703 if (!(split && xaccTransStillHasSplit (trans, split)))
722 gnc_find_split_in_account_by_memo (
Account *account,
const char *memo,
725 if (account ==
nullptr)
return nullptr;
727 const auto& splits = xaccAccountGetSplits (account);
728 for (
auto it = splits.rbegin(); it != splits.rend(); it++)
737 gnc_find_split_in_reg_by_memo (SplitRegister *reg,
const char *memo,
740 int virt_row, virt_col;
741 int num_rows, num_cols;
742 Transaction *last_trans;
744 if (!reg || !reg->table)
747 num_rows = reg->table->num_virt_rows;
748 num_cols = reg->table->num_virt_cols;
752 for (virt_row = num_rows - 1; virt_row >= 0; virt_row--)
753 for (virt_col = num_cols - 1; virt_col >= 0; virt_col--)
757 VirtualCellLocation vcell_loc = { virt_row, virt_col };
759 split = gnc_split_register_get_split (reg, vcell_loc);
762 if (trans == last_trans)
765 split = gnc_find_split_in_trans_by_memo (trans, memo, unit_price);
776 gnc_find_trans_in_reg_by_desc (SplitRegister *reg,
const char *description)
778 int virt_row, virt_col;
779 int num_rows, num_cols;
780 Transaction *last_trans;
782 if (!reg || !reg->table)
785 num_rows = reg->table->num_virt_rows;
786 num_cols = reg->table->num_virt_cols;
790 for (virt_row = num_rows - 1; virt_row >= 0; virt_row--)
791 for (virt_col = num_cols - 1; virt_col >= 0; virt_col--)
795 VirtualCellLocation vcell_loc = { virt_row, virt_col };
797 split = gnc_split_register_get_split (reg, vcell_loc);
800 if (trans == last_trans)
815 gnc_split_register_auto_completion (SplitRegister *reg,
816 gncTableTraversalDir dir,
817 VirtualLocation *p_new_virt_loc)
819 SRInfo *info = gnc_split_register_get_info (reg);
820 VirtualLocation new_virt_loc;
822 Transaction *pending_trans;
823 Transaction *blank_trans;
824 const char *cell_name;
831 if (!reg->do_auto_complete)
835 gnc_get_current_book ());
839 gnc_get_current_book ());
842 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
851 cell_name = gnc_table_get_current_cell_name (reg->table);
853 switch (cursor_class)
855 case CURSOR_CLASS_TRANS:
857 Transaction *auto_trans;
861 if (blank_trans == NULL)
865 if (trans != blank_trans)
869 if (!gnc_cell_name_equal (cell_name, DESC_CELL))
874 if (gnc_table_layout_get_cell_changed (reg->table->layout,
876 gnc_table_layout_get_cell_changed (reg->table->layout,
878 gnc_table_layout_get_cell_changed (reg->table->layout,
880 gnc_table_layout_get_cell_changed (reg->table->layout,
882 gnc_table_layout_get_cell_changed (reg->table->layout,
884 gnc_table_layout_get_cell_changed (reg->table->layout,
886 gnc_table_layout_get_cell_changed (reg->table->layout,
888 gnc_table_layout_get_cell_changed (reg->table->layout,
893 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
898 desc = gnc_table_layout_get_cell_value (reg->table->layout, DESC_CELL);
899 if ((desc == NULL) || (*desc ==
'\0'))
903 if (gnc_split_register_get_default_account (reg) != NULL)
905 Account *account = gnc_split_register_get_default_account (reg);
910 auto_trans = gnc_find_trans_in_reg_by_desc (reg, desc);
912 if (auto_trans == NULL)
915 gnc_suspend_gui_refresh ();
921 if (pending_trans != trans)
927 if (pending_trans != NULL)
931 else g_assert_not_reached ();
936 gnc_get_current_book ());
937 g_assert (pending_trans == trans);
940 gnc_get_current_book ());
948 if (gnc_split_register_get_default_account (reg) != NULL)
950 Account *default_account = gnc_split_register_get_default_account (reg);
959 auto s = GNC_SPLIT(n->data);
960 if (s && xaccTransStillHasSplit (trans, s) &&
970 if (blank_split == NULL)
975 DEBUG(
"blank_split=%p", blank_split);
977 info->blank_split_edited = TRUE;
982 sd = gnc_split_register_save_data_new (trans, blank_split,
984 gnc_table_save_cells (reg->table, sd);
985 gnc_split_register_save_data_destroy (sd);
988 gnc_resume_gui_refresh ();
992 GNC_PREF_TAB_TRANS_MEMORISED))
997 if (gnc_table_get_current_cell_location (reg->table, cell_name, &new_virt_loc))
998 *p_new_virt_loc = new_virt_loc;
1004 case CURSOR_CLASS_SPLIT:
1008 gboolean unit_price;
1016 if (!gnc_cell_name_equal (cell_name, MEMO_CELL))
1021 if (gnc_table_layout_get_cell_changed (reg->table->layout,
1023 gnc_table_layout_get_cell_changed (reg->table->layout,
1024 MXFRM_CELL, TRUE) ||
1025 gnc_table_layout_get_cell_changed (reg->table->layout,
1027 gnc_table_layout_get_cell_changed (reg->table->layout,
1029 gnc_table_layout_get_cell_changed (reg->table->layout,
1034 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1039 memo = gnc_table_layout_get_cell_value (reg->table->layout, MEMO_CELL);
1040 if ((memo == NULL) || (*memo ==
'\0'))
1045 unit_price = !gnc_table_get_current_cell_location (reg->table,
1049 if (gnc_split_register_get_default_account (reg) != NULL)
1051 Account *account = gnc_split_register_get_default_account (reg);
1053 auto_split = gnc_find_split_in_account_by_memo (account, memo,
1057 auto_split = gnc_find_split_in_reg_by_memo (reg, memo, unit_price);
1059 if (auto_split == NULL)
1065 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1068 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1069 gnc_combo_cell_set_value ((
ComboCell *) cell,
1070 gnc_get_num_action (NULL, auto_split));
1074 cell = gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
1077 reg->show_leaf_accounts);
1078 gnc_combo_cell_set_value ((
ComboCell *) cell, account_name);
1079 g_free (account_name);
1081 gnc_basic_cell_set_changed (cell, TRUE);
1083 if (!gnc_table_layout_get_cell_changed (reg->table->layout,
1085 !gnc_table_layout_get_cell_changed (reg->table->layout,
1088 BasicCell *debit_cell;
1089 BasicCell *credit_cell;
1093 debit_cell = gnc_table_layout_get_cell (reg->table->layout,
1095 credit_cell = gnc_table_layout_get_cell (reg->table->layout,
1102 gnc_basic_cell_set_changed (debit_cell, TRUE);
1103 gnc_basic_cell_set_changed (credit_cell, TRUE);
1113 if (gnc_table_get_current_cell_location (reg->table, cell_name,
1115 *p_new_virt_loc = new_virt_loc;
1128 gnc_split_register_check_stock_action (SplitRegister *reg,
1129 const char *cell_name)
1136 if (!gnc_cell_name_equal (cell_name, ACTN_CELL) ||
1137 !gnc_table_layout_get_cell_changed (reg->table->layout,
1141 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1145 if ((name == NULL) || (*name ==
'\0'))
1148 buy = g_strcmp0 (name, ACTION_BUY_STR) == 0;
1149 sell = g_strcmp0 (name, ACTION_SELL_STR) == 0;
1153 cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1162 gnc_basic_cell_set_changed (cell, TRUE);
1167 gnc_split_register_check_stock_shares (SplitRegister *reg,
1168 const char *cell_name)
1175 if (!gnc_cell_name_equal (cell_name, SHRS_CELL) ||
1176 !gnc_table_layout_get_cell_changed (reg->table->layout,
1180 cell = gnc_table_layout_get_cell (reg->table->layout, SHRS_CELL);
1188 cell = gnc_table_layout_get_cell (reg->table->layout, ACTN_CELL);
1193 if (!g_strcmp0 (name,
"") ||
1194 !g_strcmp0 (name, buy ? ACTION_SELL_STR : ACTION_BUY_STR))
1196 gnc_combo_cell_set_value ((
ComboCell *)cell,
1197 buy ? ACTION_BUY_STR : ACTION_SELL_STR);
1198 gnc_basic_cell_set_changed (cell, TRUE);
1208 gnc_split_register_check_cell (SplitRegister *reg,
const char *cell_name)
1210 ENTER(
"reg=%p, cell_name=%s", reg, cell_name ? cell_name :
"NULL");
1213 if (!gnc_split_register_check_account (reg, cell_name))
1215 LEAVE(
"account check failed");
1220 if (!gnc_split_register_check_debcred (reg, cell_name))
1222 LEAVE(
"debit/credit check failed");
1227 if ((reg->type == STOCK_REGISTER) ||
1228 (reg->type == PORTFOLIO_LEDGER) ||
1229 (reg->type == CURRENCY_REGISTER))
1231 gnc_split_register_check_stock_action (reg, cell_name);
1232 gnc_split_register_check_stock_shares (reg, cell_name);
1240 gnc_split_register_get_account_always (SplitRegister *reg,
1241 const char *cell_name)
1246 cell = gnc_table_layout_get_cell (reg->table->layout, cell_name);
1249 name = gnc_basic_cell_get_value (cell);
1253 if (!g_strcmp0 (name, SPLIT_TRANS_STR))
1256 return gnc_split_register_get_account_by_name (reg, cell, name);
1263 gnc_split_register_xfer_dialog (SplitRegister *reg, Transaction *txn,
1270 g_return_val_if_fail (reg, NULL);
1271 g_return_val_if_fail (reg->table, NULL);
1273 cur = reg->table->current_cursor;
1276 xfer = gnc_xfer_dialog (gnc_split_register_get_parent (reg), NULL);
1277 g_return_val_if_fail (xfer, NULL);
1282 gnc_xfer_dialog_set_description (xfer, gnc_basic_cell_get_value (cell));
1286 gnc_xfer_dialog_set_description (xfer, str ? str :
"");
1292 gnc_xfer_dialog_set_memo (xfer, gnc_basic_cell_get_value (cell));
1296 gnc_xfer_dialog_set_memo (xfer, str ? str :
"");
1302 gnc_xfer_dialog_set_num (xfer, gnc_basic_cell_get_value (cell));
1305 const char *str = gnc_get_num_action (txn, split);
1306 gnc_xfer_dialog_set_num (xfer, str ? str :
"");
1315 gnc_xfer_dialog_set_date (xfer, time);
1336 Split *split, *osplit;
1338 gnc_commodity *txn_cur, *xfer_com, *reg_com;
1339 gnc_numeric amount, exch_rate;
1341 gboolean expanded = FALSE;
1343 const char *message;
1346 ENTER(
"reg=%p, force_dialog=%s", reg, force_dialog ?
"TRUE" :
"FALSE" );
1349 if (reg->is_template)
1351 LEAVE(
"Template transaction, rate makes no sense.");
1360 message = _(
"This register does not support editing exchange rates.");
1361 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1363 LEAVE(
"no rate cell");
1367 rate_cell = (
PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL);
1373 message = _(
"This register does not support editing exchange rates.");
1374 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1376 LEAVE(
"null rate cell");
1381 info = gnc_split_register_get_info (reg);
1384 info->rate_reset != RATE_RESET_REQD)
1386 LEAVE(
"rate already non-zero");
1395 if (expanded && cursor_class == CURSOR_CLASS_TRANS)
1399 message = _(
"You need to select a split in order to modify its exchange " 1401 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1403 LEAVE(
"expanded with transaction cursor; nothing to do");
1408 xfer_acc = gnc_split_register_get_account_always (reg,
1409 expanded ? XFRM_CELL : MXFRM_CELL);
1412 if (force_dialog && !expanded && !xfer_acc)
1414 message = _(
"You need to expand the transaction in order to modify its " 1416 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1417 LEAVE(
"%s", message);
1426 message = _(
"The entered account could not be found.");
1427 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1429 LEAVE(
"no xfer account");
1439 reg_acc = gnc_split_register_get_default_account (reg);
1454 LEAVE(
"txn and account currencies match, and not forcing");
1459 if (expanded || osplit == NULL)
1461 message = _(
"The two currencies involved equal each other.");
1462 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1463 LEAVE(
"register is expanded or osplit == NULL; not forcing dialog");
1474 message = _(
"The two currencies involved equal each other.");
1475 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1476 LEAVE(
"reg commodity == txn commodity; not forcing");
1485 if (!expanded && osplit &&
1486 gnc_split_register_split_needs_amount (reg, split) &&
1487 gnc_split_register_split_needs_amount (reg, osplit))
1489 message = _(
"You need to expand the transaction in order to modify its " 1493 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1495 LEAVE(
"%s", message);
1506 if (!expanded && osplit &&
1516 amount = gnc_split_register_debcred_cell_value (reg);
1526 message = _(
"The split's amount is zero, so no exchange rate is needed.");
1527 gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)),
"%s", message);
1529 LEAVE(
"amount is zero; no exchange rate needed");
1538 info->rate_reset != RATE_RESET_REQD &&
1541 LEAVE(
"gain/loss split; no exchange rate needed");
1546 xfer = gnc_split_register_xfer_dialog (reg, txn, split);
1547 gnc_xfer_dialog_is_exchange_dialog (xfer, &exch_rate);
1548 if (gnc_xfer_dialog_run_exchange_dialog (xfer, &exch_rate, amount,
1549 reg_acc, txn, xfer_com, expanded))
1552 LEAVE(
"leaving rate unchanged");
1559 gnc_basic_cell_set_changed (&rate_cell->cell, TRUE);
1560 info->rate_account = xfer_acc;
1561 info->rate_reset = RATE_RESET_DONE;
1568 transaction_changed_confirm (VirtualLocation *p_new_virt_loc,
1569 VirtualLocation *virt_loc,
1570 SplitRegister *reg, Transaction *new_trans,
1571 gboolean exact_traversal)
1573 GtkWidget *dialog, *window;
1575 const char *title = _(
"Save the changed transaction?");
1576 const char *message =
1577 _(
"The current transaction has been changed. Would you like to " 1578 "record the changes before moving to a new transaction, discard the " 1579 "changes, or return to the changed transaction?");
1581 window = gnc_split_register_get_parent (reg);
1582 dialog = gtk_message_dialog_new (GTK_WINDOW(window),
1583 GTK_DIALOG_DESTROY_WITH_PARENT,
1584 GTK_MESSAGE_QUESTION,
1587 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1589 gtk_dialog_add_buttons (GTK_DIALOG(dialog),
1590 _(
"_Discard Changes"), GTK_RESPONSE_REJECT,
1591 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1592 _(
"_Record Changes"), GTK_RESPONSE_ACCEPT,
1594 response = gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_TRANS_MOD);
1595 gtk_widget_destroy (dialog);
1599 case GTK_RESPONSE_ACCEPT:
1602 case GTK_RESPONSE_REJECT:
1604 VirtualCellLocation vcell_loc;
1610 if (reg->unrecn_splits != NULL)
1612 g_list_free (reg->unrecn_splits);
1613 reg->unrecn_splits = NULL;
1616 new_split = gnc_split_register_get_split (reg, virt_loc->vcell_loc);
1617 trans_split = gnc_split_register_get_trans_split (reg,
1618 virt_loc->vcell_loc,
1621 virt_loc->vcell_loc);
1625 if (gnc_split_register_find_split (reg, new_trans, trans_split,
1626 new_split, new_class, &vcell_loc))
1627 virt_loc->vcell_loc = vcell_loc;
1632 *p_new_virt_loc = *virt_loc;
1636 case GTK_RESPONSE_CANCEL:
1657 gnc_split_register_traverse (VirtualLocation *p_new_virt_loc,
1658 gncTableTraversalDir dir,
1661 auto reg =
static_cast<SplitRegister*
>(user_data);
1662 Transaction *pending_trans;
1663 VirtualLocation virt_loc;
1664 Transaction *trans, *new_trans;
1668 const char *cell_name;
1670 g_return_val_if_fail (p_new_virt_loc, TRUE);
1672 ENTER(
"reg=%p, p_new_virt_loc=%p (%d,%d), dir=%d",
1673 reg, p_new_virt_loc,
1674 (*p_new_virt_loc).vcell_loc.virt_row,
1675 (*p_new_virt_loc).vcell_loc.virt_col, dir);
1679 LEAVE(
"no register");
1683 info = gnc_split_register_get_info (reg);
1685 if (info->first_pass)
1687 LEAVE(
"first pass");
1692 gnc_get_current_book ());
1693 virt_loc = *p_new_virt_loc;
1695 info->exact_traversal = (dir == GNC_TABLE_TRAVERSE_POINTER);
1701 LEAVE(
"no transaction");
1706 changed = gnc_table_current_cursor_changed (reg->table, FALSE);
1707 if (!changed && (pending_trans != trans))
1710 info->exact_traversal);
1712 *p_new_virt_loc = virt_loc;
1714 LEAVE(
"no changes");
1719 cell_name = gnc_table_get_current_cell_name (reg->table);
1720 if (!gnc_split_register_check_cell (reg, cell_name))
1722 LEAVE(
"check cell");
1729 VirtualLocation virt_loc;
1731 if (!changed && !info->blank_split_edited)
1734 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
1737 virt_loc = reg->table->current_cursor_loc;
1741 virt_loc = reg->table->current_cursor_loc;
1742 if (gnc_table_move_tab (reg->table, &virt_loc, TRUE))
1748 LEAVE(
"no exchange rate");
1752 *p_new_virt_loc = reg->table->current_cursor_loc;
1753 (p_new_virt_loc->vcell_loc.virt_row)++;
1754 p_new_virt_loc->phys_row_offset = 0;
1755 p_new_virt_loc->phys_col_offset = 0;
1757 info->traverse_to_new = TRUE;
1759 LEAVE(
"off end of last line");
1769 if (gnc_split_register_auto_completion (reg, dir, p_new_virt_loc))
1771 info->auto_complete = TRUE;
1772 LEAVE(
"auto-complete");
1780 VirtualLocation virt_loc;
1789 if (dir != GNC_TABLE_TRAVERSE_RIGHT)
1792 virt_loc = reg->table->current_cursor_loc;
1793 old_virt_row = virt_loc.vcell_loc.virt_row;
1795 if (gnc_table_move_tab (reg->table, &virt_loc, TRUE) &&
1796 old_virt_row == virt_loc.vcell_loc.virt_row)
1809 LEAVE(
"no exchange rate");
1813 info->cursor_hint_trans = trans;
1814 info->cursor_hint_split = split;
1815 info->cursor_hint_trans_split =
1817 info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1818 info->hint_set_by_traverse = TRUE;
1820 LEAVE(
"off end of blank split");
1827 int old_virt_row = reg->table->current_cursor_loc.vcell_loc.virt_row;
1831 info->exact_traversal);
1835 if (virt_loc.vcell_loc.virt_row != old_virt_row)
1839 LEAVE(
"no exchange rate");
1846 new_trans = gnc_split_register_get_trans (reg, virt_loc.vcell_loc);
1847 if (trans == new_trans)
1849 *p_new_virt_loc = virt_loc;
1851 LEAVE(
"staying within txn");
1858 LEAVE(
"txn change");
1859 return transaction_changed_confirm (p_new_virt_loc, &virt_loc, reg,
1860 new_trans, info->exact_traversal);
1868 control->move_cursor = gnc_split_register_move_cursor;
1869 control->traverse = gnc_split_register_traverse;
1875 gnc_split_register_recn_cell_confirm (
char old_flag, gpointer data)
1877 auto reg =
static_cast<SplitRegister*
>(data);
1878 GtkWidget *dialog, *window;
1880 const gchar *title = _(
"Mark split as unreconciled?");
1881 const gchar *message =
1882 _(
"You are about to mark a reconciled split as unreconciled. Doing " 1883 "so might make future reconciliation difficult! Continue " 1884 "with this change?");
1886 if (old_flag !=
YREC)
1890 window = gnc_split_register_get_parent (reg);
1891 dialog = gtk_message_dialog_new (GTK_WINDOW(window),
1892 GTK_DIALOG_DESTROY_WITH_PARENT,
1893 GTK_MESSAGE_WARNING,
1896 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG(dialog),
1898 gtk_dialog_add_button (GTK_DIALOG(dialog),
1901 response = gnc_dialog_run (GTK_DIALOG(dialog), GNC_PREF_WARN_REG_RECD_SPLIT_UNREC);
1902 gtk_widget_destroy (dialog);
1903 return (response == GTK_RESPONSE_YES);
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
Equivalence predicate: Returns TRUE (1) if a and b represent the same number.
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...
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
int gnc_commodity_get_fraction(const gnc_commodity *cm)
Retrieve the fraction for the specified commodity.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction's split list.
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
const char * gnc_commodity_get_mnemonic(const gnc_commodity *cm)
Retrieve the mnemonic for the specified commodity.
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
#define PINFO(format, args...)
Print an informational note.
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.
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
gboolean xaccSplitDestroy(Split *split)
Destructor.
int xaccAccountGetCommoditySCU(const Account *acc)
Return the SCU for the account.
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
#define DEBUG(format, args...)
Print a debugging message.
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
TableControl specialized for the SplitRegister.
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
Save handlers for the SplitRegister Model and Template SplitRegister model.
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...
gboolean gnc_numeric_zero_p(gnc_numeric a)
Returns 1 if the given gnc_numeric is 0 (zero), else returns 0.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
void gnc_copy_trans_onto_trans(Transaction *from, Transaction *to, gboolean use_cut_semantics, Account *template_account, gboolean do_commit)
Private function – outsiders must not use this.
#define ENTER(format, args...)
Print a function entry debugging message.
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
Account used to record multiple commodity transactions.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
convert single-entry accounts to clean double-entry
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Transaction * xaccAccountFindTransByDesc(const Account *acc, const char *description)
Returns a pointer to the transaction, not a copy.
CursorClass
Types of cursors.
Account public routines (C++ api)
#define YREC
The Split has been reconciled.
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.
The PriceCell object implements a cell handler that stores a single double-precision value...
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
void gnc_monetary_list_free(MonetaryList *list)
Free a MonetaryList and all the monetaries it points to.
void gnc_date_cell_get_date(DateCell *cell, time64 *time, gboolean warn)
Set a time64 to the value in the DateCell.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
private declarations for SplitRegister
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
TableControl * gnc_split_register_control_new(void)
Create a new TableControl specialized for the SplitRegister.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
Division.
#define xaccSplitGetGUID(X)
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Returns the price of the split, that is, the value divided by the amount.
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.
API for checkbook register display area.
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
#define xaccTransGetGUID(X)
Generic api to store and retrieve preferences.
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...
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction's commodity.
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account's commodity.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
The xaccTransGetImbalance method returns a list giving the value of the transaction in each currency ...
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.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Declarations for the Table object.
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
gboolean gnc_price_cell_set_value(PriceCell *cell, gnc_numeric amount)
updates amount, returns TRUE if string representation actually changed
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
Check for error signal in value.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
The DateCell object implements a date handling cell.
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...
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to...
void gnc_price_cell_set_debt_credit_value(PriceCell *debit, PriceCell *credit, gnc_numeric amount)
updates two cells; the deb cell if amt is negative, the credit cell if amount is positive, and makes the other cell blank.
#define GNC_DENOM_AUTO
Values that can be passed as the 'denom' argument.
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
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.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account's commodity.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...