GnuCash  4.12-11-g8193d7f23a+
Files | Data Structures | Macros | Typedefs | Enumerations | Functions

GnuCash-specific ledger and journal displays based on RegisterCore. More...

Files

file  split-register-control.h
 TableControl specialized for the SplitRegister.
 
file  split-register-layout.h
 Create the actual register visual layout.
 
file  split-register-model-save.h
 Save handlers for the SplitRegister Model and Template SplitRegister model.
 
file  split-register-model.h
 TableModels specialized for SplitRegister and template SplitRegister.
 
file  split-register-p.h
 private declarations for SplitRegister
 
file  split-register.h
 API for checkbook register display area.
 

Data Structures

struct  SRInfo
 
struct  SplitRegister
 The type, style and table for the register. More...
 

Macros

#define SPLIT_TRANS_STR   _("-- Split Transaction --")
 
#define STOCK_SPLIT_STR   _("-- Stock Split --")
 
#define ACTION_BUY_STR   _("Buy")
 
#define ACTION_SELL_STR   _("Sell")
 

Typedefs

typedef GtkWidget *(* SRGetParentCallback) (gpointer user_data)
 Callback function type.
 

Enumerations

enum  RateReset_t { RATE_RESET_NOT_REQD = 0, RATE_RESET_REQD = 1, RATE_RESET_DONE = 2 }
 
enum  SplitRegisterType {
  BANK_REGISTER, CASH_REGISTER, ASSET_REGISTER, CREDIT_REGISTER,
  LIABILITY_REGISTER, INCOME_REGISTER, EXPENSE_REGISTER, EQUITY_REGISTER,
  STOCK_REGISTER, CURRENCY_REGISTER, RECEIVABLE_REGISTER, PAYABLE_REGISTER,
  TRADING_REGISTER, NUM_SINGLE_REGISTER_TYPES, GENERAL_JOURNAL = NUM_SINGLE_REGISTER_TYPES, INCOME_LEDGER,
  PORTFOLIO_LEDGER, SEARCH_LEDGER, NUM_REGISTER_TYPES
}
 Register types. More...
 
enum  SplitRegisterTypeGroup {
  REG_TYPE_GROUP_UNKNOWN, REG_TYPE_GROUP_CURRENCY, REG_TYPE_GROUP_APAR, REG_TYPE_GROUP_STOCK,
  REG_TYPE_GROUP_JOURNAL, REG_TYPE_GROUP_PORTFOLIO
}
 Register group types. More...
 
enum  SplitRegisterStyle { REG_STYLE_LEDGER, REG_STYLE_AUTO_LEDGER, REG_STYLE_JOURNAL }
 Register styles.
 
enum  CursorClass { CURSOR_CLASS_NONE = -1, CURSOR_CLASS_SPLIT, CURSOR_CLASS_TRANS, NUM_CURSOR_CLASSES }
 Types of cursors.
 

Functions

TableControlgnc_split_register_control_new (void)
 Create a new TableControl specialized for the SplitRegister. More...
 
TableLayout * gnc_split_register_layout_new (SplitRegister *reg)
 Generate the split register layout. More...
 
void gnc_split_register_model_add_save_handlers (TableModel *model)
 
void gnc_template_register_model_add_save_handlers (TableModel *model)
 
SRSaveData * gnc_split_register_save_data_new (Transaction *trans, Split *split, gboolean expanded)
 
void gnc_split_register_save_data_destroy (SRSaveData *sd)
 
TableModelgnc_split_register_model_new (void)
 
TableModelgnc_template_register_model_new (void)
 
SRInfo * gnc_split_register_get_info (SplitRegister *reg)
 
GtkWidget * gnc_split_register_get_parent (SplitRegister *reg)
 
Split * gnc_split_register_get_split (SplitRegister *reg, VirtualCellLocation vcell_loc)
 
Accountgnc_split_register_get_default_account (SplitRegister *reg)
 
Transaction * gnc_split_register_get_trans (SplitRegister *reg, VirtualCellLocation vcell_loc)
 
Split * gnc_split_register_get_trans_split (SplitRegister *reg, VirtualCellLocation vcell_loc, VirtualCellLocation *trans_split_loc)
 
gboolean gnc_split_register_find_split (SplitRegister *reg, Transaction *trans, Split *trans_split, Split *split, CursorClass cursor_class, VirtualCellLocation *vcell_loc)
 
void gnc_split_register_show_trans (SplitRegister *reg, VirtualCellLocation start_loc)
 
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. More...
 
void gnc_split_register_set_cell_fractions (SplitRegister *reg, Split *split)
 
CellBlockgnc_split_register_get_passive_cursor (SplitRegister *reg)
 
CellBlockgnc_split_register_get_active_cursor (SplitRegister *reg)
 
void gnc_split_register_set_last_num (SplitRegister *reg, const char *num)
 
Accountgnc_split_register_get_account_by_name (SplitRegister *reg, BasicCell *cell, const char *name)
 
Accountgnc_split_register_get_account (SplitRegister *reg, const char *cell_name)
 
gboolean gnc_split_register_recn_cell_confirm (char old_flag, gpointer data)
 
gboolean gnc_split_register_check_cell (SplitRegister *reg, const char *cell_name)
 
CursorClass gnc_split_register_cursor_name_to_class (const char *cursor_name)
 
gnc_numeric gnc_split_register_debcred_cell_value (SplitRegister *reg)
 
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, what conversion we need.
 
gboolean gnc_split_register_split_needs_amount (SplitRegister *reg, Split *split)
 
gboolean gnc_split_register_needs_conv_rate (SplitRegister *reg, Transaction *txn, Account *acc)
 
SplitRegister * gnc_split_register_new (SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line, gboolean is_template, gboolean mismatched_commodities)
 Creates a new split register. More...
 
void gnc_split_register_destroy (SplitRegister *reg)
 Destroys a split register. More...
 
void gnc_split_register_config (SplitRegister *reg, SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line)
 Sets a split register's type, style or line use. More...
 
void gnc_split_register_set_auto_complete (SplitRegister *reg, gboolean do_auto_complete)
 Sets whether a register uses auto-completion. More...
 
void gnc_split_register_set_read_only (SplitRegister *reg, gboolean read_only)
 Sets whether a register window is "read only". More...
 
SplitRegisterTypeGroup gnc_split_register_get_register_group (SplitRegister *reg)
 Group registers for common layouts. More...
 
void gnc_split_register_set_template_account (SplitRegister *reg, Account *template_account)
 Set the template account for use in a template register. More...
 
void gnc_split_register_set_data (SplitRegister *reg, gpointer user_data, SRGetParentCallback get_parent)
 Sets the user data and callback hooks for the register. More...
 
CursorClass gnc_split_register_get_current_cursor_class (SplitRegister *reg)
 Returns the class of a register's current cursor. More...
 
CursorClass gnc_split_register_get_cursor_class (SplitRegister *reg, VirtualCellLocation vcell_loc)
 Returns the class of the cursor at the given virtual cell location. More...
 
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 of its splits. More...
 
Split * gnc_split_register_get_current_trans_split (SplitRegister *reg, VirtualCellLocation *vcell_loc)
 Gets the anchoring split of the transaction at the current cursor location, which may be on the transaction itself or on any of its splits. More...
 
Split * gnc_split_register_get_current_split (SplitRegister *reg)
 Returns the split at which the cursor is currently located. More...
 
Split * gnc_split_register_get_blank_split (SplitRegister *reg)
 Gets the blank split for a register. More...
 
gboolean gnc_split_register_get_split_virt_loc (SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
 Searches the split register for a given split. More...
 
gboolean gnc_split_register_get_split_amount_virt_loc (SplitRegister *reg, Split *split, VirtualLocation *virt_loc)
 Searches the split register for the given split and determines the location of either its credit (if non-zero) or debit cell. More...
 
Split * gnc_split_register_duplicate_current (SplitRegister *reg)
 Duplicates either the current transaction or the current split depending on the register mode and cursor position. More...
 
void gnc_split_register_copy_current (SplitRegister *reg)
 Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later. More...
 
void gnc_split_register_cut_current (SplitRegister *reg)
 Equivalent to copying the current entity and the deleting it with the appropriate delete method. More...
 
void gnc_split_register_paste_current (SplitRegister *reg)
 Pastes a previous copied entity onto the current entity, but only if the copied and current entity have the same type. More...
 
void gnc_split_register_delete_current_split (SplitRegister *reg)
 Deletes the split associated with the current cursor, if both are non-NULL. More...
 
void gnc_split_register_delete_current_trans (SplitRegister *reg)
 Deletes the transaction associated with the current cursor, if both are non-NULL. More...
 
void gnc_split_register_void_current_trans (SplitRegister *reg, const char *reason)
 Voids the transaction associated with the current cursor, if non-NULL. More...
 
void gnc_split_register_unvoid_current_trans (SplitRegister *reg)
 Unvoids the transaction associated with the current cursor, if non-NULL. More...
 
void gnc_split_register_empty_current_trans_except_split (SplitRegister *reg, Split *split)
 Deletes the non-transaction splits associated with the current cursor, if both are non-NULL. More...
 
void gnc_split_register_empty_current_trans (SplitRegister *reg)
 
void gnc_split_register_cancel_cursor_split_changes (SplitRegister *reg)
 Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI. More...
 
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, and updates the GUI. More...
 
void gnc_split_register_load (SplitRegister *reg, GList *slist, Account *default_account)
 Populates the rows of a register. More...
 
gboolean gnc_split_register_save (SplitRegister *reg, gboolean do_commit)
 Copy the contents of the current cursor to a split. More...
 
void gnc_split_register_redraw (SplitRegister *reg)
 Causes a redraw of the register window associated with reg. More...
 
gboolean gnc_split_register_changed (SplitRegister *reg)
 Returns TRUE if the register has changed cells. More...
 
void gnc_split_register_show_present_divider (SplitRegister *reg, gboolean show_present)
 If TRUE, visually indicate the demarcation between splits with post dates prior to the present, and after. More...
 
void gnc_split_register_expand_current_trans (SplitRegister *reg, gboolean expand)
 Expand the current transaction if it is collapsed. More...
 
void gnc_split_register_collapse_current_trans (SplitRegister *reg)
 Mark the current transaction as collapsed, and do callbacks. More...
 
gboolean gnc_split_register_current_trans_expanded (SplitRegister *reg)
 Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER. More...
 
const char * gnc_split_register_get_debit_string (SplitRegister *reg)
 Return the debit string used in the register. More...
 
const char * gnc_split_register_get_credit_string (SplitRegister *reg)
 Return the credit string used in the register. More...
 
gboolean gnc_split_register_is_blank_split (SplitRegister *reg, Split *split)
 Return TRUE if split is the blank_split. More...
 
void gnc_split_register_change_blank_split_ref (SplitRegister *reg, Split *split)
 Change the blank_split reference from pointing to split to another split of the transaction. More...
 
gboolean gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog)
 Pop up the exchange-rate dialog, maybe, for the current split. More...
 
gboolean gnc_split_register_begin_edit_or_warn (SRInfo *info, Transaction *trans)
 

Cell Names

T* cells are transaction summary cells

#define ACTN_CELL   "action"
 
#define DOCLINK_CELL   "doclink"
 
#define BALN_CELL   "balance"
 
#define CRED_CELL   "credit"
 
#define DATE_CELL   "date"
 
#define DDUE_CELL   "date-due"
 
#define DEBT_CELL   "debit"
 
#define DESC_CELL   "description"
 
#define FCRED_CELL   "credit-formula"
 
#define FDEBT_CELL   "debit-formula"
 
#define MEMO_CELL   "memo"
 
#define MXFRM_CELL   "transfer"
 
#define NOTES_CELL   "notes"
 
#define NUM_CELL   "num"
 
#define TNUM_CELL   "trans-num"
 
#define PRIC_CELL   "price"
 
#define RATE_CELL   "exchrate"
 
#define RECN_CELL   "reconcile"
 
#define SHRS_CELL   "shares"
 
#define TBALN_CELL   "trans-balance"
 
#define TCRED_CELL   "trans-credit"
 
#define TDEBT_CELL   "trans-debit"
 
#define TSHRS_CELL   "trans-shares"
 
#define TYPE_CELL   "split-type"
 
#define XFRM_CELL   "account"
 
#define VNOTES_CELL   "void-notes"
 
#define RBALN_CELL   "reg-run-balance"
 

Cursor Names

Cursors ending in 'NUM_ACTN' use the split action field for the NUM_CELL rather than the transaction number field which is shown in the TNUM_CELL

#define CURSOR_SINGLE_LEDGER   "cursor-single-ledger"
 
#define CURSOR_DOUBLE_LEDGER   "cursor-double-ledger"
 
#define CURSOR_DOUBLE_LEDGER_NUM_ACTN   "cursor-double-ledger-num-actn"
 
#define CURSOR_SINGLE_JOURNAL   "cursor-single-journal"
 
#define CURSOR_DOUBLE_JOURNAL   "cursor-double-journal"
 
#define CURSOR_DOUBLE_JOURNAL_NUM_ACTN   "cursor-double-journal-num-actn"
 
#define CURSOR_SPLIT   "cursor-split"
 

Detailed Description

GnuCash-specific ledger and journal displays based on RegisterCore.

The split register is a spreadsheet-like area that looks like a checkbook register. It displays transactions and allows the user to edit them in-place. The register does not contain any of the other window decorations that one might want to have for a free standing window (e.g. menubars, * toolbars, etc.)

The layout of the register is configurable. There's a broad variety of cell types to choose from: date cells that know how to parse dates, price cells that know how to parse prices, etc. These cells can be laid out in any column; even a multi-row layout is supported. The name "split register" is derived from the fact that this register can display multiple rows of transaction splits underneath a transaction title/summary row.

An area for entering new transactions is provided at the bottom of the register.

All user input to the register is handled by the 'cursor', which is mapped onto one of the displayed rows.

Design Notes.
Some notes about the "blank split":
Q: What is the "blank split"?
A: A new, empty split appended to the bottom of the ledger window. The blank split provides an area where the user can type in new split/transaction info. The "blank split" is treated in a special way for a number of reasons:
  • it must always appear as the bottom-most split in the Ledger window,
  • it must be committed if the user edits it, and a new blank split must be created.
  • it must be deleted when the ledger window is closed.
To implement the above, the register "user_data" is used to store an SRInfo structure containing the blank split.
Some notes on Commit/Rollback:
There's an engine component and a gui component to the commit/rollback scheme. On the engine side, one must always call BeginEdit() before starting to edit a transaction. When you think you're done, you can call CommitEdit() to commit the changes, or RollbackEdit() to go back to how things were before you started the edit. Think of it as a one-shot mega-undo for that transaction.
Note that the query engine uses the original values, not the currently edited values, when performing a sort. This allows your to e.g. edit the date without having the transaction hop around in the gui while you do it.
On the gui side, commits are now performed on a per-transaction basis, rather than a per-split (per-journal-entry) basis. This means that if you have a transaction with a lot of splits in it, you can edit them all you want without having to commit one before moving to the next.
Similarly, the "cancel" button will now undo the changes to all of the lines in the transaction display, not just to one line (one split) at a time.
Some notes on Reloads & Redraws:
Reloads and redraws tend to be heavyweight. We try to use change flags as much as possible in this code, but imagine the following scenario:
Create two bank accounts. Transfer money from one to the other. Open two registers, showing each account. Change the amount in one window. Note that the other window also redraws, to show the new correct amount.
Since you changed an amount value, potentially all displayed balances change in both register windows (as well as the ledger balance in the main window). Three or more windows may be involved if you have e.g. windows open for bank, employer, taxes and your entering a paycheck (or correcting a typo in an old paycheck). Changing a date might even cause all entries in all three windows to be re-ordered.
The only thing I can think of is a bit stored with every table entry, stating 'this entry has changed since lst time, redraw it'. But that still doesn't avoid the overhead of reloading the table from the engine.

The Register itself is independent of GnuCash, and is designed so that it can be used with other applications. The Ledger is an adaptation of the Register for use by GnuCash. The Ledger sets up an explicit visual layout, putting certain types of cells in specific locations (e.g. date on left, summary in middle, value at right), and hooks up these cells to the various GnuCash financial objects.

This code is also theoretically independent of the actual GUI toolkit/widget-set (it once worked with both Motif and Gnome). The actual GUI-toolkit specific code is supposed to be in a GUI portability layer. Over the years, some gnome-isms may have snuck in; these should also be cleaned up.

Enumeration Type Documentation

◆ SplitRegisterType

Register types.

"registers" are single-account display windows. "ledgers" are multiple-account display windows

Definition at line 145 of file split-register.h.

146 {
147  BANK_REGISTER,
148  CASH_REGISTER,
149  ASSET_REGISTER,
150  CREDIT_REGISTER,
151  LIABILITY_REGISTER,
152  INCOME_REGISTER,
153  EXPENSE_REGISTER,
154  EQUITY_REGISTER,
155  STOCK_REGISTER,
156  CURRENCY_REGISTER,
157  RECEIVABLE_REGISTER,
158  PAYABLE_REGISTER,
159  TRADING_REGISTER,
160  NUM_SINGLE_REGISTER_TYPES,
161 
162  GENERAL_JOURNAL = NUM_SINGLE_REGISTER_TYPES,
163  INCOME_LEDGER,
164  PORTFOLIO_LEDGER,
165  SEARCH_LEDGER,
166 
167  NUM_REGISTER_TYPES
SplitRegisterType
Register types.

◆ SplitRegisterTypeGroup

Register group types.

used for grouping registers that have the same layout

Definition at line 173 of file split-register.h.

174 {
175  REG_TYPE_GROUP_UNKNOWN,
176  REG_TYPE_GROUP_CURRENCY,
177  REG_TYPE_GROUP_APAR,
178  REG_TYPE_GROUP_STOCK,
179  REG_TYPE_GROUP_JOURNAL,
180  REG_TYPE_GROUP_PORTFOLIO,
SplitRegisterTypeGroup
Register group types.

Function Documentation

◆ gnc_split_register_cancel_cursor_split_changes()

void gnc_split_register_cancel_cursor_split_changes ( SplitRegister *  reg)

Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.

The change flags are cleared.

Definition at line 1412 of file split-register.c.

1413 {
1414  VirtualLocation virt_loc;
1415 
1416  if (reg == NULL)
1417  return;
1418 
1419  virt_loc = reg->table->current_cursor_loc;
1420 
1421  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1422  return;
1423 
1424  /* We're just cancelling the current split here, not the transaction.
1425  * When cancelling edits, reload the cursor from the transaction. */
1426  gnc_table_clear_current_cursor_changes (reg->table);
1427 
1428  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1429  gnc_table_move_cursor_gui (reg->table, virt_loc);
1430 
1431  gnc_table_refresh_gui (reg->table, TRUE);
1432 }
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165

◆ gnc_split_register_cancel_cursor_trans_changes()

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, and updates the GUI.

The change flags are cleared.

Definition at line 1435 of file split-register.c.

1436 {
1437  SRInfo* info = gnc_split_register_get_info (reg);
1438  Transaction* pending_trans, *blank_trans;
1439  gboolean refresh_all = FALSE;
1440 
1441  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1442  gnc_get_current_book ());
1443 
1445 
1446  if (pending_trans == blank_trans)
1447  refresh_all = TRUE;
1448 
1449  /* Get the currently open transaction, rollback the edits on it, and
1450  * then repaint everything. To repaint everything, make a note of
1451  * all of the accounts that will be affected by this rollback. */
1452  if (!xaccTransIsOpen (pending_trans))
1453  {
1455  return;
1456  }
1457 
1458  if (!pending_trans)
1459  return;
1460 
1461  gnc_suspend_gui_refresh ();
1462 
1463  xaccTransRollbackEdit (pending_trans);
1464 
1465  info->pending_trans_guid = *guid_null ();
1466 
1467  gnc_resume_gui_refresh ();
1468 
1469  if (refresh_all)
1470  gnc_gui_refresh_all (); // force a refresh of all registers
1471  else
1473 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...
Definition: Transaction.c:1730

◆ gnc_split_register_change_blank_split_ref()

void gnc_split_register_change_blank_split_ref ( SplitRegister *  reg,
Split *  split 
)

Change the blank_split reference from pointing to split to another split of the transaction.

This is used when deleting a split after an autocomplete as the blank_split reference will be pointing to one of the splits so it does not cancel the whole transaction

Definition at line 1110 of file split-register.c.

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  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1118  Transaction* trans = xaccSplitGetParent (split);
1119 
1120  // loop through splitlist looking for splits other than the blank_split
1121  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1122  {
1123  Split *s = n->data;
1124  if (s != current_blank_split)
1125  {
1126  if (blank_split_account == xaccSplitGetAccount (s))
1127  pref_split = s; // prefer same account
1128  else
1129  other_split = s; // any other split
1130  }
1131  }
1132  // now change the saved blank split reference
1133  if (pref_split != NULL)
1134  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1135  else if (other_split != NULL)
1136  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1137 }
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
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.
Definition: Split.c:1072
#define xaccSplitGetGUID(X)
Definition: Split.h:554
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.

◆ gnc_split_register_changed()

gboolean gnc_split_register_changed ( SplitRegister *  reg)

Returns TRUE if the register has changed cells.

Definition at line 2470 of file split-register.c.

2471 {
2472  SRInfo* info = gnc_split_register_get_info (reg);
2473  Transaction* pending_trans;
2474 
2475  ENTER ("reg=%p", reg);
2476 
2477  if (reg == NULL)
2478  {
2479  LEAVE ("no register");
2480  return FALSE;
2481  }
2482 
2483  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2484  {
2485  LEAVE ("cursor changed");
2486  return TRUE;
2487  }
2488 
2489  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2490  gnc_get_current_book ());
2491  if (xaccTransIsOpen (pending_trans))
2492  {
2493  LEAVE ("open and pending txn");
2494  return TRUE;
2495  }
2496 
2497  LEAVE ("register unchanged");
2498  return FALSE;
2499 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282

◆ gnc_split_register_collapse_current_trans()

void gnc_split_register_collapse_current_trans ( SplitRegister *  reg)

Mark the current transaction as collapsed, and do callbacks.

◆ gnc_split_register_config()

void gnc_split_register_config ( SplitRegister *  reg,
SplitRegisterType  type,
SplitRegisterStyle  style,
gboolean  use_double_line 
)

Sets a split register's type, style or line use.

Parameters
rega ::SplitRegister
typea SplitRegisterType to use for the register
stylea SplitRegisterStyle to use for the register
use_double_lineTRUE to show two lines for transactions, FALSE for one

Definition at line 2903 of file split-register.c.

2907 {
2908  if (!reg) return;
2909 
2910  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2911  if (reg->use_double_line && !use_double_line)
2912  {
2913  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2914  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
2915  {
2916  if (virt_loc.phys_row_offset)
2917  {
2918  gnc_table_move_vertical_position (reg->table, &virt_loc,
2919  -virt_loc.phys_row_offset);
2920  gnc_table_move_cursor_gui (reg->table, virt_loc);
2921  }
2922  }
2923  else
2924  {
2925  /* WTF? Go to a known safe location. */
2926  virt_loc.vcell_loc.virt_row = 1;
2927  virt_loc.vcell_loc.virt_col = 0;
2928  virt_loc.phys_row_offset = 0;
2929  virt_loc.phys_col_offset = 0;
2930  gnc_table_move_cursor_gui (reg->table, virt_loc);
2931  }
2932  }
2933 
2934  reg->type = newtype;
2935 
2936  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
2937  newstyle = REG_STYLE_JOURNAL;
2938 
2939  reg->style = newstyle;
2940  reg->use_double_line = use_double_line;
2941 
2942  gnc_table_realize_gui (reg->table);
2943 }
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
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.

◆ gnc_split_register_control_new()

TableControl* gnc_split_register_control_new ( void  )

Create a new TableControl specialized for the SplitRegister.

Definition at line 1809 of file split-register-control.c.

1810 {
1811  TableControl *control = gnc_table_control_new();
1812 
1813  control->move_cursor = gnc_split_register_move_cursor;
1814  control->traverse = gnc_split_register_traverse;
1815 
1816  return control;
1817 }

◆ gnc_split_register_copy_current()

void gnc_split_register_copy_current ( SplitRegister *  reg)

Makes a copy of the current entity, either a split or a transaction, so that it can be pasted later.

Definition at line 846 of file split-register.c.

847 {
848  gnc_split_register_copy_current_internal (reg, FALSE);
849 }

◆ gnc_split_register_current_trans_expanded()

gboolean gnc_split_register_current_trans_expanded ( SplitRegister *  reg)

Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.

Definition at line 264 of file split-register.c.

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 }

◆ gnc_split_register_cut_current()

void gnc_split_register_cut_current ( SplitRegister *  reg)

Equivalent to copying the current entity and the deleting it with the appropriate delete method.

Definition at line 852 of file split-register.c.

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 ());
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)
890  else
892 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL. ...
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.
Definition: Split.c:1072
CursorClass
Types of cursors.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_delete_current_split()

void gnc_split_register_delete_current_split ( SplitRegister *  reg)

Deletes the split associated with the current cursor, if both are non-NULL.

Deleting the blank split just clears cursor values.

Definition at line 1140 of file split-register.c.

1141 {
1142  SRInfo* info = gnc_split_register_get_info (reg);
1143  Transaction* pending_trans;
1144  Transaction* trans;
1145  Split* blank_split;
1146  Split* split;
1147 
1148  if (!reg) return;
1149 
1150  blank_split = xaccSplitLookup (&info->blank_split_guid,
1151  gnc_get_current_book ());
1152 
1153  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1154  gnc_get_current_book ());
1155 
1156  /* get the current split based on cursor position */
1158  if (split == NULL)
1159  return;
1160 
1161  /* If we are deleting the blank split, just cancel. The user is
1162  * allowed to delete the blank split as a method for discarding
1163  * any edits they may have made to it. */
1164  if (split == blank_split)
1165  {
1167  return;
1168  }
1169 
1170  gnc_suspend_gui_refresh ();
1171 
1172  trans = xaccSplitGetParent (split);
1173 
1174  /* Check pending transaction */
1175  if (trans == pending_trans)
1176  {
1177  g_assert (xaccTransIsOpen (trans));
1178  }
1179  else
1180  {
1181  g_assert (!pending_trans);
1182  if (gnc_split_register_begin_edit_or_warn (info, trans))
1183  {
1184  gnc_resume_gui_refresh ();
1185  return;
1186  }
1187  }
1188  xaccSplitDestroy (split);
1189 
1190  gnc_resume_gui_refresh ();
1192 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1466
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
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.
Definition: Split.c:1072
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_delete_current_trans()

void gnc_split_register_delete_current_trans ( SplitRegister *  reg)

Deletes the transaction associated with the current cursor, if both are non-NULL.

Definition at line 1195 of file split-register.c.

1196 {
1197  SRInfo* info = gnc_split_register_get_info (reg);
1198  Transaction* pending_trans;
1199  Transaction* trans;
1200  Split* blank_split;
1201  Split* split;
1202  gboolean was_open;
1203 
1204  ENTER ("reg=%p", reg);
1205  if (!reg)
1206  {
1207  LEAVE ("no register");
1208  return;
1209  }
1210 
1211  blank_split = xaccSplitLookup (&info->blank_split_guid,
1212  gnc_get_current_book ());
1213  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1214  gnc_get_current_book ());
1215 
1216  /* get the current split based on cursor position */
1218  if (split == NULL)
1219  {
1220  LEAVE ("no split");
1221  return;
1222  }
1223 
1224  gnc_suspend_gui_refresh ();
1225  trans = xaccSplitGetParent (split);
1226 
1227  /* If we just deleted the blank split, clean up. The user is
1228  * allowed to delete the blank split as a method for discarding
1229  * any edits they may have made to it. */
1230  if (split == blank_split)
1231  {
1232  DEBUG ("deleting blank split");
1233  info->blank_split_guid = *guid_null ();
1234  info->auto_complete = FALSE;
1235  }
1236  else
1237  {
1238  info->trans_expanded = FALSE;
1239  }
1240 
1241  /* Check pending transaction */
1242  if (trans == pending_trans)
1243  {
1244  DEBUG ("clearing pending trans");
1245  info->pending_trans_guid = *guid_null ();
1246  pending_trans = NULL;
1247  }
1248 
1249  was_open = xaccTransIsOpen (trans);
1250  xaccTransDestroy (trans);
1251  if (was_open)
1252  {
1253  DEBUG ("committing");
1254  xaccTransCommitEdit (trans);
1255  }
1256  gnc_resume_gui_refresh ();
1258  LEAVE (" ");
1259 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
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.
Definition: Split.c:1072
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_destroy()

void gnc_split_register_destroy ( SplitRegister *  reg)

Destroys a split register.

Parameters
rega ::SplitRegister

Definition at line 3068 of file split-register.c.

3069 {
3070  g_return_if_fail (reg);
3071 
3072  ENTER ("reg=%p", reg);
3073 
3074  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3075  GNC_PREF_ACCOUNTING_LABELS,
3076  split_register_pref_changed,
3077  reg);
3078  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3079  GNC_PREF_ACCOUNT_SEPARATOR,
3080  split_register_pref_changed,
3081  reg);
3082  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3083  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3084  split_register_pref_changed,
3085  reg);
3086  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3087  GNC_PREF_ALT_COLOR_BY_TRANS,
3088  split_register_pref_changed,
3089  reg);
3090  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3091  split_register_book_option_changed,
3092  reg);
3093 
3094  gnc_split_register_cleanup (reg);
3095 
3096  gnc_table_destroy (reg->table);
3097  reg->table = NULL;
3098 
3099  /* free the memory itself */
3100  g_free (reg);
3101  LEAVE (" ");
3102 }
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143

◆ gnc_split_register_duplicate_current()

Split* gnc_split_register_duplicate_current ( SplitRegister *  reg)

Duplicates either the current transaction or the current split depending on the register mode and cursor position.

Returns the split just created, or the 'main' split of the transaction just created, or NULL if nothing happened.

Definition at line 401 of file split-register.c.

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 ());
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 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;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...
void gnc_copy_trans_onto_trans(Transaction *from, Transaction *to, gboolean use_cut_semantics, gboolean do_commit)
Private function – outsiders must not use this.
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:511
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4933
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean gnc_split_register_save(SplitRegister *reg, gboolean do_commit)
Copy the contents of the current cursor to a split.
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...
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition: qofutil.cpp:187
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition: Account.cpp:4945
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
Definition: Transaction.c:2425
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:1112
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.
Definition: Split.c:1072
CursorClass
Types of cursors.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gboolean xaccAccountEqual(const Account *aa, const Account *ab, gboolean check_guids)
Compare two accounts for equality - this is a deep compare.
Definition: Account.cpp:1644
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2311
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
The NumCell object implements a number handling cell.
Definition: numcell.h:39
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1247
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Definition: Transaction.c:2211
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2054
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:1086
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_empty_current_trans_except_split()

void gnc_split_register_empty_current_trans_except_split ( SplitRegister *  reg,
Split *  split 
)

Deletes the non-transaction splits associated with the current cursor, if both are non-NULL.

Definition at line 1359 of file split-register.c.

1361 {
1362  SRInfo* info;
1363  Transaction* trans;
1364  Transaction* pending;
1365  int i = 0;
1366  Split* s;
1367 
1368  if ((reg == NULL) || (split == NULL))
1369  return;
1370 
1371  gnc_suspend_gui_refresh ();
1372  info = gnc_split_register_get_info (reg);
1373  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1374 
1375  trans = xaccSplitGetParent (split);
1376  if (!pending)
1377  {
1378  if (gnc_split_register_begin_edit_or_warn (info, trans))
1379  {
1380  gnc_resume_gui_refresh ();
1381  return;
1382  }
1383  }
1384  else if (pending == trans)
1385  {
1386  g_assert (xaccTransIsOpen (trans));
1387  }
1388  else g_assert_not_reached ();
1389 
1390  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1391  {
1392  if (s != split)
1393  xaccSplitDestroy (s);
1394  else i++;
1395  }
1396 
1397  gnc_resume_gui_refresh ();
1399 }
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.c:1466
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.

◆ gnc_split_register_expand_current_trans()

void gnc_split_register_expand_current_trans ( SplitRegister *  reg,
gboolean  expand 
)

Expand the current transaction if it is collapsed.

Definition at line 204 of file split-register.c.

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 
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 }
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_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
Definition: table-allgui.c:737

◆ gnc_split_register_get_blank_split()

Split* gnc_split_register_get_blank_split ( SplitRegister *  reg)

Gets the blank split for a register.

Parameters
rega ::SplitRegister
Returns
the ::Split used as the blank split, or NULL if there currently isn't one

Definition at line 313 of file split-register.c.

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 }
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.
Definition: Split.c:1072

◆ gnc_split_register_get_credit_string()

const char* gnc_split_register_get_credit_string ( SplitRegister *  reg)

Return the credit string used in the register.

Definition at line 2447 of file split-register.c.

2448 {
2449  SRInfo* info = gnc_split_register_get_info (reg);
2450 
2451  if (!reg)
2452  return NULL;
2453 
2454  if (info->credit_str)
2455  return info->credit_str;
2456 
2457  info->credit_str =
2459  (gnc_split_register_type_to_account_type (reg->type));
2460 
2461  if (info->credit_str)
2462  return info->credit_str;
2463 
2464  info->credit_str = g_strdup (_ ("Credit"));
2465 
2466  return info->credit_str;
2467 }
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4246

◆ gnc_split_register_get_current_cursor_class()

CursorClass gnc_split_register_get_current_cursor_class ( SplitRegister *  reg)

Returns the class of a register's current cursor.

Parameters
rega ::SplitRegister
Returns
the CursorClass of the current cursor

Definition at line 545 of file split-register-util.c.

546 {
547  Table *table;
548 
549  if (reg == NULL)
550  return CURSOR_CLASS_NONE;
551 
552  table = reg->table;
553  if (table == NULL)
554  return CURSOR_CLASS_NONE;
555 
556  return gnc_split_register_cursor_class (reg, table->current_cursor);
557 }

◆ gnc_split_register_get_current_split()

Split* gnc_split_register_get_current_split ( SplitRegister *  reg)

Returns the split at which the cursor is currently located.

Parameters
rega ::SplitRegister
Returns
the ::Split at the cursor location, or the anchoring split if the cursor is currently on a transaction

Definition at line 303 of file split-register.c.

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 }

◆ gnc_split_register_get_current_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 of its splits.

Parameters
rega ::SplitRegister
Returns
the ::Transaction at the cursor location, or NULL

Definition at line 279 of file split-register.c.

280 {
281  Split* split;
282  VirtualCellLocation vcell_loc;
283 
284  if (reg == NULL)
285  return NULL;
286 
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 }
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_get_current_trans_split()

Split* gnc_split_register_get_current_trans_split ( SplitRegister *  reg,
VirtualCellLocation *  vcell_loc 
)

Gets the anchoring split of the transaction at the current cursor location, which may be on the transaction itself or on any of its splits.

Parameters
rega ::SplitRegister
vcell_loca pointer to be filled with the location of the transaction's virtual cell
Returns
the anchoring ::Split of the transaction

Definition at line 186 of file split-register-util.c.

188 {
189  VirtualCellLocation vcell_loc;
190 
191  if (reg == NULL)
192  return NULL;
193 
194  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
195 
196  return gnc_split_register_get_trans_split (reg, vcell_loc, trans_split_loc);
197 }

◆ gnc_split_register_get_cursor_class()

CursorClass gnc_split_register_get_cursor_class ( SplitRegister *  reg,
VirtualCellLocation  vcell_loc 
)

Returns the class of the cursor at the given virtual cell location.

Parameters
rega ::SplitRegister
vcell_locthe location of a virtual cell
Returns
the CursorClass of the cursor at vcell_loc

Definition at line 524 of file split-register-util.c.

526 {
527  VirtualCell *vcell;
528  Table *table;
529 
530  if (reg == NULL)
531  return CURSOR_CLASS_NONE;
532 
533  table = reg->table;
534  if (table == NULL)
535  return CURSOR_CLASS_NONE;
536 
537  vcell = gnc_table_get_virtual_cell (table, vcell_loc);
538  if (vcell == NULL)
539  return CURSOR_CLASS_NONE;
540 
541  return gnc_split_register_cursor_class (reg, vcell->cellblock);
542 }
holds information about each virtual cell.
Definition: table-allgui.h:132
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227

◆ gnc_split_register_get_debit_string()

const char* gnc_split_register_get_debit_string ( SplitRegister *  reg)

Return the debit string used in the register.

Definition at line 2424 of file split-register.c.

2425 {
2426  SRInfo* info = gnc_split_register_get_info (reg);
2427 
2428  if (!reg)
2429  return NULL;
2430 
2431  if (info->debit_str)
2432  return info->debit_str;
2433 
2434  info->debit_str =
2436  (gnc_split_register_type_to_account_type (reg->type));
2437 
2438  if (info->debit_str)
2439  return info->debit_str;
2440 
2441  info->debit_str = g_strdup (_ ("Debit"));
2442 
2443  return info->debit_str;
2444 }
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4234

◆ gnc_split_register_get_register_group()

SplitRegisterTypeGroup gnc_split_register_get_register_group ( SplitRegister *  reg)

Group registers for common layouts.

Parameters
rega ::SplitRegister
Returns
the SplitRegisterTypeGroup that groups registers together

Definition at line 3111 of file split-register.c.

3112 {
3113  switch (reg->type)
3114  {
3115  case BANK_REGISTER:
3116  case CASH_REGISTER:
3117  case ASSET_REGISTER:
3118  case CREDIT_REGISTER:
3119  case LIABILITY_REGISTER:
3120  case INCOME_REGISTER:
3121  case EXPENSE_REGISTER:
3122  case EQUITY_REGISTER:
3123  case TRADING_REGISTER:
3124  {
3125  return REG_TYPE_GROUP_CURRENCY;
3126  break;
3127  }
3128  case PAYABLE_REGISTER:
3129  case RECEIVABLE_REGISTER:
3130  {
3131  return REG_TYPE_GROUP_APAR;
3132  break;
3133  }
3134  case INCOME_LEDGER:
3135  case GENERAL_JOURNAL:
3136  case SEARCH_LEDGER:
3137  {
3138  return REG_TYPE_GROUP_JOURNAL;
3139  break;
3140  }
3141  case STOCK_REGISTER:
3142  case CURRENCY_REGISTER:
3143  {
3144  return REG_TYPE_GROUP_STOCK;
3145  break;
3146  }
3147  case PORTFOLIO_LEDGER:
3148  {
3149  return REG_TYPE_GROUP_PORTFOLIO;
3150  break;
3151  }
3152  default:
3153  return REG_TYPE_GROUP_UNKNOWN;
3154  PERR ("unknown register type %d\n", reg->type);
3155  break;
3156  }
3157 }
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244

◆ gnc_split_register_get_split_amount_virt_loc()

gboolean gnc_split_register_get_split_amount_virt_loc ( SplitRegister *  reg,
Split *  split,
VirtualLocation *  virt_loc 
)

Searches the split register for the given split and determines the location of either its credit (if non-zero) or debit cell.

Parameters
rega ::SplitRegister
splitthe ::Split to find
virt_loca pointer to be filled with the amount cell's location
Returns
TRUE if the split was found and the location has been stored at virt_loc, FALSE otherwise

Definition at line 363 of file split-register.c.

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 }
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_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
CursorClass
Types of cursors.
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84

◆ gnc_split_register_get_split_virt_loc()

gboolean gnc_split_register_get_split_virt_loc ( SplitRegister *  reg,
Split *  split,
VirtualCellLocation *  vcell_loc 
)

Searches the split register for a given split.

The search begins from the bottom row and works backwards. The location of the first virtual cell that matches will be returned in vcell_loc.

Parameters
rega ::SplitRegister
splitthe ::Split to find
vcell_loca pointer to be filled with the location of the matching virtual cell
Returns
TRUE if the split was found and the location has been stored at vcell_loc, FALSE otherwise

Definition at line 323 of file split-register.c.

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 }
gpointer vcell_data
Array of physical cells.
Definition: table-allgui.h:135
holds information about each virtual cell.
Definition: table-allgui.h:132
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.
Definition: Split.c:1072
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
unsigned int visible
Used by higher-level code.
Definition: table-allgui.h:138

◆ gnc_split_register_handle_exchange()

gboolean gnc_split_register_handle_exchange ( SplitRegister *  reg,
gboolean  force_dialog 
)

Pop up the exchange-rate dialog, maybe, for the current split.

If force_dialog is TRUE, the forces the dialog to be called. If the dialog does not complete successfully, then return TRUE. Return FALSE in all other cases (meaning "move on")

Pop up the exchange-rate dialog, maybe, for the current split.

If the dialog does not complete successfully, then return TRUE. Return FALSE in all other cases (meaning "move on")

Parameters
regthe register to operate on
force_dialogpop a dialog even if we don't think we need it.
Returns
whether more handling is required.

Definition at line 1279 of file split-register-control.c.

1280 {
1281  SRInfo *info;
1282  Transaction *txn;
1283  Split *split, *osplit;
1284  Account *xfer_acc, *reg_acc;
1285  gnc_commodity *txn_cur, *xfer_com, *reg_com;
1286  gnc_numeric amount, exch_rate;
1287  XferDialog *xfer;
1288  gboolean expanded = FALSE;
1289  PriceCell *rate_cell;
1290  const char *message;
1291  CursorClass cursor_class;
1292 
1293  ENTER("reg=%p, force_dialog=%s", reg, force_dialog ? "TRUE" : "FALSE" );
1294 
1295  /* No point in setting a rate on a template transaction. */
1296  if (reg->is_template)
1297  {
1298  LEAVE("Template transaction, rate makes no sense.");
1299  return FALSE;
1300  }
1301 
1302  /* Make sure we NEED this for this type of register */
1303  if (!gnc_split_reg_has_rate_cell (reg->type))
1304  {
1305  if (force_dialog)
1306  {
1307  message = _("This register does not support editing exchange rates.");
1308  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1309  }
1310  LEAVE("no rate cell");
1311  return FALSE;
1312  }
1313 
1314  rate_cell = (PriceCell*) gnc_table_layout_get_cell(
1315  reg->table->layout, RATE_CELL);
1316  if (!rate_cell)
1317  {
1318  if (force_dialog)
1319  {
1320  message = _("This register does not support editing exchange rates.");
1321  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1322  }
1323  LEAVE("null rate cell");
1324  return FALSE;
1325  }
1326 
1327  /* See if we already have an exchange rate... */
1328  info = gnc_split_register_get_info (reg);
1329  exch_rate = gnc_price_cell_get_value (rate_cell);
1330  if (!gnc_numeric_zero_p(exch_rate) && !force_dialog &&
1331  info->rate_reset != RATE_RESET_REQD)
1332  {
1333  LEAVE("rate already non-zero");
1334  return FALSE;
1335  }
1336 
1337  /* Are we expanded? */
1339  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1340 
1341  /* If we're expanded AND a transaction cursor, there is nothing to do */
1342  if (expanded && cursor_class == CURSOR_CLASS_TRANS)
1343  {
1344  if (force_dialog)
1345  {
1346  message = _("You need to select a split in order to modify its exchange "
1347  "rate.");
1348  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1349  }
1350  LEAVE("expanded with transaction cursor; nothing to do");
1351  return FALSE;
1352  }
1353 
1354  /* Grab the xfer account */
1355  xfer_acc = gnc_split_register_get_account_always(
1356  reg, expanded ? XFRM_CELL : MXFRM_CELL);
1357 
1358  /* If this is an un-expanded, multi-split transaction, then warn the user */
1359  if (force_dialog && !expanded && !xfer_acc)
1360  {
1361  message = _("You need to expand the transaction in order to modify its "
1362  "exchange rates.");
1363  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1364  LEAVE("%s", message);
1365  return TRUE;
1366  }
1367 
1368  /* No account -- don't run the dialog */
1369  if (!xfer_acc)
1370  {
1371  if (force_dialog)
1372  {
1373  message = _("The entered account could not be found.");
1374  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1375  }
1376  LEAVE("no xfer account");
1377  return FALSE;
1378  }
1379 
1380  /* Grab the txn currency and xfer commodity */
1382  txn_cur = xaccTransGetCurrency (txn);
1383  xfer_com = xaccAccountGetCommodity (xfer_acc);
1384 
1385  /* Grab the register account and commodity (may be used later) */
1386  reg_acc = gnc_split_register_get_default_account (reg);
1387  reg_com = xaccAccountGetCommodity (reg_acc);
1388 
1389  /* Grab the split and perhaps the "other" split (if it is a two-split txn) */
1391  osplit = xaccSplitGetOtherSplit (split);
1392 
1393  /* Check if the txn- and xfer- commodities are the same */
1394  if (gnc_commodity_equal (txn_cur, xfer_com))
1395  {
1396  /* If we're not forcing the dialog, then there is no reason to
1397  * go on. We're using the correct accounts.
1398  */
1399  if (!force_dialog)
1400  {
1401  LEAVE("txn and account currencies match, and not forcing");
1402  return FALSE;
1403  }
1404 
1405  /* Only proceed with two-split, basic, non-expanded registers */
1406  if (expanded || osplit == NULL)
1407  {
1408  message = _("The two currencies involved equal each other.");
1409  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1410  LEAVE("register is expanded or osplit == NULL; not forcing dialog");
1411  return FALSE;
1412  }
1413 
1414  /* If we're forcing, then compare the current account
1415  * commodity to the transaction currency.
1416  */
1417  xfer_acc = reg_acc;
1418  xfer_com = reg_com;
1419  if (gnc_commodity_equal (txn_cur, xfer_com))
1420  {
1421  message = _("The two currencies involved equal each other.");
1422  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1423  LEAVE("reg commodity == txn commodity; not forcing");
1424  return FALSE;
1425  }
1426  }
1427 
1428  /* If this is a non-expanded, two-split txn where BOTH splits need
1429  * conversion rates, then require the user to actually expand the
1430  * transaction in order to edit it.
1431  */
1432  if (!expanded && osplit &&
1433  gnc_split_register_split_needs_amount (reg, split) &&
1434  gnc_split_register_split_needs_amount (reg, osplit))
1435  {
1436  message = _("You need to expand the transaction in order to modify its "
1437  "exchange rates.");
1438  if (force_dialog)
1439  {
1440  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1441  }
1442  LEAVE("%s", message);
1443  return TRUE;
1444  }
1445 
1446  /* Strangely, if we're in a two-split, non-expanded txn, we need
1447  * to do something really special with the exchange rate! In
1448  * particular, we have to pick it up from the _other_ split --
1449  * right?
1450  * XXX: perhaps I should pop up an error here? Or maybe require the
1451  * user to go into expanded-mode?
1452  */
1453  if (!expanded && osplit && !gnc_commodity_equal(reg_com, txn_cur) &&
1454  !gnc_commodity_equal(reg_com, xfer_com))
1455  {
1456  gnc_numeric amt = xaccSplitGetAmount (osplit);
1457  gnc_numeric val = xaccSplitGetValue (osplit);
1458  exch_rate = gnc_numeric_div (amt, val, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
1459  }
1460 
1461  /* Ok, we need to grab the exchange rate */
1462  amount = gnc_split_register_debcred_cell_value (reg);
1463 
1464  /*
1465  * If "amount" is zero then we don't need an exchange-rate.. Return
1466  * FALSE to let the user continue on.
1467  */
1468  if (gnc_numeric_zero_p (amount))
1469  {
1470  if (force_dialog)
1471  {
1472  message = _("The split's amount is zero, so no exchange rate is needed.");
1473  gnc_error_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", message);
1474  }
1475  LEAVE("amount is zero; no exchange rate needed");
1476  return FALSE;
1477  }
1478 
1479  /* If the exch_rate is zero, we're not forcing the dialog, and this is
1480  * _not_ the blank split, then return FALSE -- this is a "special"
1481  * gain/loss stock transaction.
1482  */
1483  if (gnc_numeric_zero_p(exch_rate) && !force_dialog && split &&
1484  info->rate_reset != RATE_RESET_REQD &&
1485  split != gnc_split_register_get_blank_split (reg))
1486  {
1487  LEAVE("gain/loss split; no exchange rate needed");
1488  return FALSE;
1489  }
1490 
1491  /* Show the exchange-rate dialog */
1492  xfer = gnc_split_register_xfer_dialog(reg, txn, split);
1493  gnc_xfer_dialog_is_exchange_dialog(xfer, &exch_rate);
1494  if (gnc_xfer_dialog_run_exchange_dialog(
1495  xfer, &exch_rate, amount, reg_acc, txn, xfer_com, expanded))
1496  {
1497  /* FIXME: How should the dialog be destroyed? */
1498  LEAVE("leaving rate unchanged");
1499  return TRUE;
1500  }
1501  /* FIXME: How should the dialog be destroyed? */
1502 
1503  /* Set the RATE_CELL on this cursor and mark it changed */
1504  gnc_price_cell_set_value (rate_cell, exch_rate);
1505  gnc_basic_cell_set_changed (&rate_cell->cell, TRUE);
1506  info->rate_account = xfer_acc;
1507  info->rate_reset = RATE_RESET_DONE;
1508  LEAVE("set rate=%s", gnc_num_dbg_to_string(exch_rate));
1509  return FALSE;
1510 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;s current cursor.
Reduce the result value by common factor elimination, using the smallest possible value for the denom...
Definition: gnc-numeric.h:196
gchar * gnc_num_dbg_to_string(gnc_numeric n)
Convert to string.
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 gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equal.
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.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean gnc_split_register_current_trans_expanded(SplitRegister *reg)
Return TRUE if current trans is expanded and style is REG_STYLE_LEDGER.
CursorClass
Types of cursors.
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:50
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
gnc_numeric gnc_numeric_div(gnc_numeric a, gnc_numeric b, gint64 denom, gint how)
Division.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1367
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.
Definition: qoflog.h:282
gboolean gnc_price_cell_set_value(PriceCell *cell, gnc_numeric amount)
updates amount, returns TRUE if string representation actually changed
Definition: pricecell.c:219
#define GNC_DENOM_AUTO
Values that can be passed as the &#39;denom&#39; argument.
Definition: gnc-numeric.h:246
gnc_numeric gnc_price_cell_get_value(PriceCell *cell)
return the value of a price cell
Definition: pricecell.c:208
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69

◆ gnc_split_register_is_blank_split()

gboolean gnc_split_register_is_blank_split ( SplitRegister *  reg,
Split *  split 
)

Return TRUE if split is the blank_split.

Definition at line 1097 of file split-register.c.

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 }
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.
Definition: Split.c:1072

◆ gnc_split_register_layout_new()

TableLayout* gnc_split_register_layout_new ( SplitRegister *  reg)

Generate the split register layout.

Definition at line 865 of file split-register-layout.c.

866 {
867  TableLayout* layout;
868 
869  layout = gnc_table_layout_new();
870 
871  gnc_split_register_layout_add_cells (reg, layout);
872  gnc_split_register_layout_add_cursors (reg, layout);
873  gnc_split_register_set_cells (reg, layout);
874 
875  return layout;
876 }
TableLayout * gnc_table_layout_new(void)
API Declarations.
Definition: table-layout.c:59

◆ gnc_split_register_load()

void gnc_split_register_load ( SplitRegister *  reg,
GList *  slist,
Account default_account 
)

Populates the rows of a register.

The rows are filled, based on the register style, with data associated with the given list of splits slist. In addition, an area for the user to begin entering new transactions is placed at the tail end of the register. This area is anchored by the "blank split".

The account default_account, if provided, is used to determine various default values for the blank split (such as currency, last check number, and transfer account) for the blank split.

Parameters
rega ::SplitRegister
slista list of splits
default_accountan account to provide defaults for the blank split

Definition at line 349 of file split-register-load.c.

351 {
352  SRInfo* info;
353  Transaction* pending_trans;
354  CursorBuffer* cursor_buffer;
355  GHashTable* trans_table = NULL;
356  CellBlock* cursor_header;
357  CellBlock* lead_cursor;
358  CellBlock* split_cursor;
359  Transaction* blank_trans;
360  Transaction* find_trans;
361  Transaction* trans;
362  CursorClass find_class;
363  Split* find_trans_split;
364  Split* blank_split;
365  Split* find_split;
366  Split* split;
367  Table* table;
368  GList* node;
369  gnc_commodity *account_comm = NULL;
370 
371  gboolean start_primary_color = TRUE;
372  gboolean found_pending = FALSE;
373  gboolean need_divider_upper = FALSE;
374  gboolean found_divider_upper = FALSE;
375  gboolean found_divider = FALSE;
376  gboolean has_last_num = FALSE;
377  gboolean multi_line;
378  gboolean dynamic;
379  gboolean we_own_slist = FALSE;
380  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
381  gnc_get_current_book());
382  gboolean future_after_blank = gnc_prefs_get_bool (
383  GNC_PREFS_GROUP_GENERAL_REGISTER,
384  GNC_PREF_FUTURE_AFTER_BLANK);
385  gboolean added_blank_trans = FALSE;
386 
387  VirtualCellLocation vcell_loc;
388  VirtualLocation save_loc;
389 
390  int new_trans_split_row = -1;
391  int new_trans_row = -1;
392  int new_split_row = -1;
393  time64 present, autoreadonly_time = 0;
394 
395  g_return_if_fail (reg);
396  table = reg->table;
397  g_return_if_fail (table);
398  info = gnc_split_register_get_info (reg);
399  g_return_if_fail (info);
400 
401  ENTER ("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
402 
403  blank_split = xaccSplitLookup (&info->blank_split_guid,
404  gnc_get_current_book());
405 
406  pending_trans = xaccTransLookup (&info->pending_trans_guid,
407  gnc_get_current_book());
408 
409  if (default_account)
410  account_comm = gnc_account_get_currency_or_parent (default_account);
411 
412  if (!account_comm)
413  account_comm = gnc_default_currency ();
414 
415  /* Bug 742089: Set the debit and credit cells' print_info to the account */
417  ((PriceCell*) gnc_table_layout_get_cell (table->layout, DEBT_CELL),
418  gnc_commodity_print_info (account_comm, FALSE));
419 
421  ((PriceCell*) gnc_table_layout_get_cell (table->layout, CRED_CELL),
422  gnc_commodity_print_info (account_comm, FALSE));
423 
425  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
426  gnc_commodity_print_info (account_comm, FALSE));
427 
428  gnc_doclink_cell_set_use_glyphs
429  ((Doclinkcell *) gnc_table_layout_get_cell (table->layout, DOCLINK_CELL));
430 
431  /* make sure we have a blank split */
432  if (blank_split == NULL)
433  {
434  /* Wouldn't it be a bug to open the new transaction if there was
435  * already a pending transaction?
436  */
437  g_assert (pending_trans == NULL);
438  blank_split = create_blank_split (default_account, info);
439  }
440  blank_trans = xaccSplitGetParent (blank_split);
441 
442  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
443  blank_split, blank_trans, pending_trans);
444 
445  info->default_account = *xaccAccountGetGUID (default_account);
446 
447  // gnc_table_leave_update (table, table->current_cursor_loc);
448 
449  multi_line = (reg->style == REG_STYLE_JOURNAL);
450  dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
451 
452  lead_cursor = gnc_split_register_get_passive_cursor (reg);
453  split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
454 
455  /* figure out where we are going to. */
456  if (info->traverse_to_new)
457  {
458  find_trans = blank_trans;
459  find_split = NULL;
460  find_trans_split = blank_split;
461  find_class = CURSOR_CLASS_SPLIT;
462  }
463  else
464  {
465  find_trans = info->cursor_hint_trans;
466  find_split = info->cursor_hint_split;
467  find_trans_split = info->cursor_hint_trans_split;
468  find_class = info->cursor_hint_cursor_class;
469  }
470 
471  save_loc = table->current_cursor_loc;
472 
473  /* If the current cursor has changed we save the values for later
474  * possible restoration. */
475  if (gnc_table_current_cursor_changed (table, TRUE) &&
476  (find_split == gnc_split_register_get_current_split (reg)))
477  {
478  cursor_buffer = gnc_cursor_buffer_new();
479  gnc_table_save_current_cursor (table, cursor_buffer);
480  }
481  else
482  cursor_buffer = NULL;
483 
484  /* disable move callback -- we don't want the cascade of
485  * callbacks while we are fiddling with loading the register */
486  gnc_table_control_allow_move (table->control, FALSE);
487 
488  /* invalidate the cursor */
489  {
490  VirtualLocation virt_loc;
491 
492  gnc_virtual_location_init (&virt_loc);
493  gnc_table_move_cursor_gui (table, virt_loc);
494  }
495 
496  /* make sure that the header is loaded */
497  vcell_loc.virt_row = 0;
498  vcell_loc.virt_col = 0;
499  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
500  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
501  vcell_loc.virt_row++;
502 
503  /* get the current time and reset the dividing row */
504  present = gnc_time64_get_today_end();
505  if (use_autoreadonly)
506  {
507  GDate* d = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
508  // "d" is NULL if use_autoreadonly is FALSE
509  autoreadonly_time = d ? gdate_to_time64 (*d) : 0;
510  g_date_free (d);
511  }
512 
513  if (info->first_pass)
514  {
515  if (default_account)
516  {
517  const char* last_num = xaccAccountGetLastNum (default_account);
518 
519  if (last_num)
520  {
521  NumCell* cell;
522 
523  cell = (NumCell*) gnc_table_layout_get_cell (table->layout, NUM_CELL);
524  gnc_num_cell_set_last_num (cell, last_num);
525  has_last_num = TRUE;
526  }
527  }
528 
529  /* load up account names into the transfer combobox menus */
530  gnc_split_register_load_xfer_cells (reg, default_account);
531  gnc_split_register_load_doclink_cells (reg);
532  gnc_split_register_load_recn_cells (reg);
533  gnc_split_register_load_type_cells (reg);
534  }
535 
536  if (info->separator_changed)
537  change_account_separator (info, table, reg);
538 
539  table->model->dividing_row_upper = -1;
540  table->model->dividing_row = -1;
541  table->model->dividing_row_lower = -1;
542 
543  // Ensure that the transaction and splits being edited are in the split
544  // list we're about to load.
545  if (pending_trans != NULL)
546  {
547  for (node = xaccTransGetSplitList (pending_trans); node; node = node->next)
548  {
549  Split* pending_split = (Split*)node->data;
550  if (!xaccTransStillHasSplit (pending_trans, pending_split)) continue;
551  if (g_list_find (slist, pending_split) != NULL)
552  continue;
553 
554  if (g_list_find_custom (slist, pending_trans,
555  _find_split_with_parent_txn) != NULL)
556  continue;
557 
558  if (!we_own_slist)
559  {
560  // lazy-copy
561  slist = g_list_copy (slist);
562  we_own_slist = TRUE;
563  }
564  slist = g_list_append (slist, pending_split);
565  }
566  }
567 
568  if (multi_line)
569  trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
570 
571  /* populate the table */
572  for (node = slist; node; node = node->next)
573  {
574  split = node->data;
575  trans = xaccSplitGetParent (split);
576 
577  if (!xaccTransStillHasSplit (trans, split))
578  continue;
579 
580  if (pending_trans == trans)
581  found_pending = TRUE;
582  /* If the transaction has only one split, and it's not our
583  * pending_trans, then it's another register's blank split and
584  * we don't want to see it.
585  */
586  else if (xaccTransCountSplits (trans) == 1 &&
587  xaccSplitGetAccount (split) == NULL)
588  continue;
589 
590 
591  /* Do not load splits from the blank transaction. */
592  if (trans == blank_trans)
593  continue;
594 
595  if (multi_line)
596  {
597  /* Skip this split if its transaction has already been loaded. */
598  if (g_hash_table_lookup (trans_table, trans))
599  continue;
600 
601  g_hash_table_insert (trans_table, trans, trans);
602  }
603 
604  if (info->show_present_divider &&
605  use_autoreadonly &&
606  !found_divider_upper)
607  {
608  if (xaccTransGetDate (trans) >= autoreadonly_time)
609  {
610  table->model->dividing_row_upper = vcell_loc.virt_row;
611  found_divider_upper = TRUE;
612  }
613  else
614  {
615  need_divider_upper = TRUE;
616  }
617  }
618 
619  if (info->show_present_divider &&
620  !found_divider &&
621  (xaccTransGetDate (trans) > present))
622  {
623  table->model->dividing_row = vcell_loc.virt_row;
624  found_divider = TRUE;
625 
626  if (future_after_blank)
627  {
628  if (blank_trans == find_trans)
629  new_trans_row = vcell_loc.virt_row;
630 
631  if (blank_split == find_trans_split)
632  new_trans_split_row = vcell_loc.virt_row;
633 
634  /* go to blank on first pass */
635  if (info->first_pass)
636  {
637  save_loc.vcell_loc = vcell_loc;
638  save_loc.phys_row_offset = 0;
639  save_loc.phys_col_offset = 0;
640  }
641 
642  gnc_split_register_add_transaction (reg,
643  blank_trans, blank_split,
644  lead_cursor, split_cursor,
645  multi_line, start_primary_color,
646  info->blank_split_edited,
647  find_trans, find_split,
648  find_class, &new_split_row,
649  &vcell_loc);
650 
651  table->model->dividing_row_lower = vcell_loc.virt_row;
652 
653  if (!multi_line)
654  start_primary_color = !start_primary_color;
655 
656  added_blank_trans = TRUE;
657  }
658  }
659 
660  /* If this is the first load of the register,
661  * fill up the quickfill cells. */
662  if (info->first_pass)
663  add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
664 
665  if (trans == find_trans)
666  new_trans_row = vcell_loc.virt_row;
667 
668  if (split == find_trans_split)
669  new_trans_split_row = vcell_loc.virt_row;
670 
671  gnc_split_register_add_transaction (reg, trans, split,
672  lead_cursor, split_cursor,
673  multi_line, start_primary_color,
674  TRUE,
675  find_trans, find_split, find_class,
676  &new_split_row, &vcell_loc);
677 
678  if (!multi_line)
679  start_primary_color = !start_primary_color;
680  }
681 
682  if (multi_line)
683  g_hash_table_destroy (trans_table);
684 
685  /* add the blank split at the end. */
686  if (pending_trans == blank_trans)
687  found_pending = TRUE;
688 
689  /* No upper divider yet? Store it now */
690  if (info->show_present_divider &&
691  use_autoreadonly &&
692  !found_divider_upper && need_divider_upper)
693  {
694  table->model->dividing_row_upper = vcell_loc.virt_row;
695  }
696 
697  /* If we didn't find the pending transaction, it was removed
698  * from the account. */
699  if (!found_pending)
700  {
701  info->pending_trans_guid = *guid_null();
702  if (xaccTransIsOpen (pending_trans))
703  xaccTransCommitEdit (pending_trans);
704  else if (pending_trans)
705  g_assert_not_reached();
706 
707  pending_trans = NULL;
708  }
709 
710  if (!added_blank_trans) {
711  if (blank_trans == find_trans)
712  new_trans_row = vcell_loc.virt_row;
713 
714  if (blank_split == find_trans_split)
715  new_trans_split_row = vcell_loc.virt_row;
716 
717  /* go to blank on first pass */
718  if (info->first_pass)
719  {
720  save_loc.vcell_loc = vcell_loc;
721  save_loc.phys_row_offset = 0;
722  save_loc.phys_col_offset = 0;
723  }
724 
725  gnc_split_register_add_transaction (reg, blank_trans, blank_split,
726  lead_cursor, split_cursor,
727  multi_line, start_primary_color,
728  info->blank_split_edited,
729  find_trans, find_split,
730  find_class, &new_split_row,
731  &vcell_loc);
732 
733  if (future_after_blank)
734  table->model->dividing_row_lower = vcell_loc.virt_row;
735  }
736 
737  /* go to blank on first pass */
738  if (info->first_pass)
739  {
740  new_split_row = -1;
741  new_trans_split_row = -1;
742  new_trans_row = -1;
743  }
744 
745  /* resize the table to the sizes we just counted above */
746  /* num_virt_cols is always one. */
747  gnc_table_set_size (table, vcell_loc.virt_row, 1);
748 
749  /* restore the cursor to its rightful position */
750  {
751  VirtualLocation trans_split_loc;
752 
753  if (new_split_row > 0)
754  save_loc.vcell_loc.virt_row = new_split_row;
755  else if (new_trans_split_row > 0)
756  save_loc.vcell_loc.virt_row = new_trans_split_row;
757  else if (new_trans_row > 0)
758  save_loc.vcell_loc.virt_row = new_trans_row;
759 
760  trans_split_loc = save_loc;
761 
762  gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
763  &trans_split_loc.vcell_loc);
764 
765  if (dynamic || multi_line || info->trans_expanded)
766  {
768  table, trans_split_loc.vcell_loc,
769  gnc_split_register_get_active_cursor (reg));
770  gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
771  TRUE, multi_line);
772 
773  info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
774  }
775  else
776  {
777  save_loc = trans_split_loc;
778  info->trans_expanded = FALSE;
779  }
780 
781  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
782  {
783  gnc_table_move_cursor_gui (table, save_loc);
784  new_split_row = save_loc.vcell_loc.virt_row;
785 
786  if (find_split == gnc_split_register_get_current_split (reg))
787  gnc_table_restore_current_cursor (table, cursor_buffer);
788  }
789  }
790  gnc_cursor_buffer_destroy (cursor_buffer);
791  cursor_buffer = NULL;
792 
793  update_info (info, reg);
794 
795  gnc_split_register_set_cell_fractions (
797 
799 
800  gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
801 
802  /* enable callback for cursor user-driven moves */
803  gnc_table_control_allow_move (table->control, TRUE);
804 
805  if (we_own_slist)
806  g_list_free (slist);
807 
808  LEAVE (" ");
809 }
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4933
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
def find_split(split_list, search_string)
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
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.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
void gnc_table_set_size(Table *table, int virt_rows, int virt_cols)
The gnc_table_set_size() method will resize the table to the indicated dimensions.
Definition: table-allgui.c:587
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
The Doclinkcell object implements a cell handler that will cycle through a series of single-character...
Definition: doclinkcell.h:52
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Definition: gnc-ui-util.c:1197
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
#define xaccAccountGetGUID(X)
Definition: Account.h:248
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:1112
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.
Definition: Split.c:1072
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
CursorClass
Types of cursors.
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:50
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1256
void gnc_table_set_vcell(Table *table, CellBlock *cursor, gconstpointer vcell_data, gboolean visible, gboolean start_primary_color, VirtualCellLocation vcell_loc)
Indicate what handler should be used for a given virtual block.
Definition: table-allgui.c:664
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: Account.cpp:3455
The NumCell object implements a number handling cell.
Definition: numcell.h:39
void gnc_price_cell_set_print_info(PriceCell *cell, GNCPrintAmountInfo print_info)
set the printing context of the price cell
Definition: pricecell.c:272
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
Definition: table-allgui.c:737
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1359
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:1086
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.

◆ gnc_split_register_new()

SplitRegister* gnc_split_register_new ( SplitRegisterType  type,
SplitRegisterStyle  style,
gboolean  use_double_line,
gboolean  is_template,
gboolean  mismatched_commodities 
)

Creates a new split register.

Parameters
typea SplitRegisterType to use for the new register
stylea SplitRegisterStyle to use for the new register
use_double_lineTRUE to show two lines for transactions, FALSE for one
is_templateTRUE for a new template, FALSE otherwise
Returns
a newly created ::SplitRegister

Definition at line 2877 of file split-register.c.

2882 {
2883  SplitRegister* reg;
2884  gboolean default_do_auto_complete = TRUE;
2885 
2886  reg = g_new0 (SplitRegister, 1);
2887 
2888  if (type >= NUM_SINGLE_REGISTER_TYPES)
2889  style = REG_STYLE_JOURNAL;
2890 
2891  gnc_split_register_init (reg,
2892  type,
2893  style,
2894  use_double_line,
2895  default_do_auto_complete,
2896  is_template,
2897  mismatched_commodities);
2898 
2899  return reg;
2900 }

◆ gnc_split_register_paste_current()

void gnc_split_register_paste_current ( SplitRegister *  reg)

Pastes a previous copied entity onto the current entity, but only if the copied and current entity have the same type.

Definition at line 895 of file split-register.c.

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);
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 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;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...
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
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...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
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.
Definition: Split.c:1072
CursorClass
Types of cursors.
#define xaccSplitGetGUID(X)
Definition: Split.h:554
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2311
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
The type used to store guids in C.
Definition: guid.h:75
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2050

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

Definition at line 1476 of file split-register.c.

1477 {
1478  gnc_ledger_display_refresh_by_split_register (reg);
1479 }

◆ gnc_split_register_save()

gboolean gnc_split_register_save ( SplitRegister *  reg,
gboolean  do_commit 
)

Copy the contents of the current cursor to a split.

The split and transaction that are updated are the ones associated with the current cursor (register entry) position. If the do_commit flag is set, the transaction will also be committed. If it is the blank transaction, and the do_commit flag is set, a refresh will result in a new blank transaction. The method returns TRUE if something was changed.

Definition at line 1702 of file split-register.c.

1703 {
1704  SRInfo* info = gnc_split_register_get_info (reg);
1705  Transaction* pending_trans;
1706  Transaction* blank_trans;
1707  Transaction* trans;
1708  Account* account;
1709  Split* blank_split;
1710  const char* memo;
1711  const char* desc;
1712  Split* split;
1713 
1714  ENTER ("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
1715 
1716  if (!reg)
1717  {
1718  LEAVE ("no register");
1719  return FALSE;
1720  }
1721 
1722  blank_split = xaccSplitLookup (&info->blank_split_guid,
1723  gnc_get_current_book ());
1724 
1725  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1726  gnc_get_current_book ());
1727 
1728  blank_trans = xaccSplitGetParent (blank_split);
1729 
1730  /* get the handle to the current split and transaction */
1733  if (trans == NULL)
1734  {
1735  LEAVE ("no transaction");
1736  return FALSE;
1737  }
1738 
1739  /* use the changed flag to avoid heavy-weight updates
1740  * of the split & transaction fields. This will help
1741  * cut down on unnecessary register redraws. */
1742  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1743  {
1744  if (!do_commit)
1745  {
1746  LEAVE ("commit unnecessary");
1747  return FALSE;
1748  }
1749 
1750  if (!xaccTransIsOpen (trans))
1751  {
1752  LEAVE ("transaction not open");
1753  return FALSE;
1754  }
1755 
1756  if (trans == pending_trans ||
1757  (trans == blank_trans && info->blank_split_edited))
1758  {
1759  /* We are going to commit. */
1760 
1761  gnc_suspend_gui_refresh ();
1762 
1763  if (trans == blank_trans)
1764  {
1765  /* We have to clear the blank split before the
1766  * refresh or a new one won't be created. */
1767  info->last_date_entered = xaccTransGetDate (trans);
1768  info->blank_split_guid = *guid_null ();
1769  info->blank_split_edited = FALSE;
1770  info->auto_complete = FALSE;
1771  }
1772 
1773  /* We have to clear the pending guid *before* committing the
1774  * trans, because the event handler will find it otherwise. */
1775  if (trans == pending_trans)
1776  info->pending_trans_guid = *guid_null ();
1777 
1778  PINFO ("committing trans (%p)", trans);
1779  unreconcile_splits (reg);
1780  xaccTransCommitEdit (trans);
1781  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1782 
1783  gnc_resume_gui_refresh ();
1784  }
1785  else
1786  DEBUG ("leaving trans (%p) open", trans);
1787 
1788  LEAVE ("unchanged cursor");
1789  return TRUE;
1790  }
1791 
1792  DEBUG ("save split=%p", split);
1793  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
1794  blank_split, blank_trans, pending_trans, trans);
1795 
1796  /* Act on any changes to the current cell before the save. */
1797  if (!gnc_split_register_check_cell (reg,
1798  gnc_table_get_current_cell_name (reg->table)))
1799  {
1800  LEAVE ("need another go at changing cell");
1801  return FALSE;
1802  }
1803 
1804  if (!gnc_split_register_auto_calc (reg, split))
1805  {
1806  LEAVE ("auto calc failed");
1807  return FALSE;
1808  }
1809 
1810  /* Validate the transfer account names */
1811  (void)gnc_split_register_get_account (reg, MXFRM_CELL);
1812  (void)gnc_split_register_get_account (reg, XFRM_CELL);
1813 
1814  /* Maybe deal with exchange-rate transfers */
1815  if (gnc_split_register_handle_exchange (reg, FALSE))
1816  {
1817  LEAVE ("no exchange rate");
1818  return TRUE;
1819  }
1820 
1821  gnc_suspend_gui_refresh ();
1822 
1823  /* determine whether we should commit the pending transaction */
1824  if (pending_trans != trans)
1825  {
1826  // FIXME: How could the pending transaction not be open?
1827  // FIXME: For that matter, how could an open pending
1828  // transaction ever not be the current trans?
1829  if (xaccTransIsOpen (pending_trans))
1830  {
1831  g_warning ("Impossible? committing pending %p", pending_trans);
1832  unreconcile_splits (reg);
1833  xaccTransCommitEdit (pending_trans);
1834  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1835  }
1836  else if (pending_trans)
1837  {
1838  g_critical ("BUG DETECTED! pending transaction (%p) not open",
1839  pending_trans);
1840  g_assert_not_reached ();
1841  }
1842 
1843  if (trans == blank_trans)
1844  {
1845  /* Don't begin editing the blank trans, because it's
1846  already open, but mark it pending now. */
1847  g_assert (xaccTransIsOpen (blank_trans));
1848  /* This is now the pending transaction */
1849  info->pending_trans_guid = *xaccTransGetGUID (blank_trans);
1850  }
1851  else
1852  {
1853  PINFO ("beginning edit of trans %p", trans);
1854  if (gnc_split_register_begin_edit_or_warn (info, trans))
1855  {
1856  gnc_resume_gui_refresh ();
1857  LEAVE ("transaction opened elsewhere");
1858  return FALSE;
1859  }
1860  }
1861  pending_trans = trans;
1862  }
1863  g_assert (xaccTransIsOpen (trans));
1864 
1865  /* If we are saving a brand new transaction and the blank split hasn't
1866  * been edited, then we need to give it a default account. */
1867  /* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
1868  * even better? What if there were some way that we could be on
1869  * a row other than the transaction row or blank split row, but
1870  * the blank split still hasn't been edited? It seems to be assumed
1871  * that it isn't possible, but... -Charles, Jan 2009 */
1872  if (split == blank_split && !info->blank_split_edited)
1873  {
1874  /* If we've reached this point, it means that the blank split is
1875  * anchoring the transaction - see gnc_split_register_add_transaction ()
1876  * for an explanation - and the transaction has been edited (as evidenced
1877  * by the earlier check for a changed cursor.) Since the blank split
1878  * itself has not been edited, we'll have to assign a default account. */
1879  account = gnc_split_register_get_default_account (reg);
1880  if (account)
1881  xaccSplitSetAccount (blank_split, account);
1882  xaccTransSetDateEnteredSecs (trans, gnc_time (NULL));
1883  }
1884 
1885  if (split == NULL)
1886  {
1887  /* If we were asked to save data for a row for which there is no
1888  * associated split, then assume that this was an "empty" row - see
1889  * gnc_split_register_add_transaction () for an explanation. This row
1890  * is used to add splits to an existing transaction, or to add the
1891  * 2nd through nth split rows to a brand new transaction.
1892  * xaccSRGetCurrent will handle this case, too. We will create
1893  * a new split, copy the row contents to that split, and append
1894  * the split to the pre-existing transaction. */
1895  Split* trans_split;
1896 
1897  split = xaccMallocSplit (gnc_get_current_book ());
1898  xaccTransAppendSplit (trans, split);
1899 
1900  gnc_table_set_virt_cell_data (reg->table,
1901  reg->table->current_cursor_loc.vcell_loc,
1902  xaccSplitGetGUID (split));
1903  DEBUG ("assigned cell to new split=%p", split);
1904 
1905  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
1906  if ((info->cursor_hint_trans == trans) &&
1907  (info->cursor_hint_trans_split == trans_split) &&
1908  (info->cursor_hint_split == NULL))
1909  {
1910  info->cursor_hint_split = split;
1911  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
1912  }
1913  }
1914 
1915  DEBUG ("updating trans=%p", trans);
1916 
1917  {
1918  SRSaveData* sd;
1919 
1920  sd = gnc_split_register_save_data_new (
1921  trans, split, (info->trans_expanded ||
1922  reg->style == REG_STYLE_AUTO_LEDGER ||
1923  reg->style == REG_STYLE_JOURNAL));
1924  gnc_table_save_cells (reg->table, sd);
1925  gnc_split_register_save_data_destroy (sd);
1926  }
1927 
1928  memo = xaccSplitGetMemo (split);
1929  memo = memo ? memo : "(null)";
1930  desc = xaccTransGetDescription (trans);
1931  desc = desc ? desc : "(null)";
1932  PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
1933 
1934  /* If the modified split is the "blank split", then it is now an
1935  * official part of the account. Set the blank split to NULL, so we
1936  * can be sure of getting a new blank split. Also, save the date
1937  * for the new blank split. */
1938  if (trans == blank_trans)
1939  {
1940  if (do_commit)
1941  {
1942  info->blank_split_guid = *guid_null ();
1943  info->auto_complete = FALSE;
1944  blank_split = NULL;
1945  info->last_date_entered = xaccTransGetDate (trans);
1946  }
1947  else
1948  info->blank_split_edited = TRUE;
1949  }
1950 
1951  /* If requested, commit the current transaction and set the pending
1952  * transaction to NULL. */
1953  if (do_commit)
1954  {
1955  g_assert (trans == blank_trans || trans == pending_trans);
1956  if (pending_trans == trans)
1957  {
1958  pending_trans = NULL;
1959  info->pending_trans_guid = *guid_null ();
1960  }
1961  unreconcile_splits (reg);
1962  xaccTransCommitEdit (trans);
1963  xaccTransRecordPrice (trans, PRICE_SOURCE_SPLIT_REG);
1964  }
1965 
1966  gnc_table_clear_current_cursor_changes (reg->table);
1967 
1968  gnc_resume_gui_refresh ();
1969 
1970  LEAVE (" ");
1971  return TRUE;
1972 }
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...
#define xaccTransAppendSplit(t, s)
Add a split to the transaction.
Definition: Transaction.h:370
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
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.
Definition: qoflog.h:256
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...
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void xaccTransRecordPrice(Transaction *trans, PriceSource source)
The xaccTransRecordPrice() method iterates through the splits and and record the non-currency equival...
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gnc_table_set_virt_cell_data(Table *table, VirtualCellLocation vcell_loc, gconstpointer vcell_data)
Set the virtual cell data for a particular location.
Definition: table-allgui.c:700
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
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.
Definition: Split.c:1072
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
#define xaccSplitGetGUID(X)
Definition: Split.h:554
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#define xaccTransGetGUID(X)
Definition: Transaction.h:793
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
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...
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2054
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_set_auto_complete()

void gnc_split_register_set_auto_complete ( SplitRegister *  reg,
gboolean  do_auto_complete 
)

Sets whether a register uses auto-completion.

Parameters
rega ::SplitRegister
do_auto_completeTRUE to use auto-completion, FALSE otherwise

Definition at line 2946 of file split-register.c.

2948 {
2949  g_return_if_fail (reg);
2950  reg->do_auto_complete = do_auto_complete;
2951 }

◆ gnc_split_register_set_data()

void gnc_split_register_set_data ( SplitRegister *  reg,
gpointer  user_data,
SRGetParentCallback  get_parent 
)

Sets the user data and callback hooks for the register.

◆ gnc_split_register_set_read_only()

void gnc_split_register_set_read_only ( SplitRegister *  reg,
gboolean  read_only 
)

Sets whether a register window is "read only".

Parameters
rega ::SplitRegister
read_onlyTRUE to use "read only" mode, FALSE otherwise

Definition at line 3105 of file split-register.c.

3106 {
3107  gnc_table_model_set_read_only (reg->table->model, read_only);
3108 }

◆ gnc_split_register_set_template_account()

void gnc_split_register_set_template_account ( SplitRegister *  reg,
Account template_account 
)

Set the template account for use in a template register.

Parameters
rega ::SplitRegister
template_accountthe account to use for the template

Definition at line 116 of file split-register-util.c.

118 {
119  SRInfo *info = gnc_split_register_get_info (reg);
120 
121  g_return_if_fail (reg != NULL);
122 
123  info->template_account = *xaccAccountGetGUID (template_account);
124 }
#define xaccAccountGetGUID(X)
Definition: Account.h:248

◆ gnc_split_register_set_trans_visible()

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.

If only_blank_split is TRUE, only the row used for entering an additional split is affected. Despite the name, this should not be confused with the "blank split" row used for entering the first split of a brand-new transaction. Instead, here it only refers to rows not tied to any split at all, such as those created for entering new splits on old transactions or the 2nd through nth split on brand-new transactions.

Definition at line 316 of file split-register-util.c.

320 {
321  CursorClass cursor_class;
322 
323  while (TRUE)
324  {
325  vcell_loc.virt_row++;
326 
327  cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
328  if (cursor_class != CURSOR_CLASS_SPLIT)
329  return;
330 
331  if (only_blank_split && gnc_split_register_get_split (reg, vcell_loc))
332  continue;
333 
334  gnc_table_set_virt_cell_visible (reg->table, vcell_loc, visible);
335  }
336 }
void gnc_table_set_virt_cell_visible(Table *table, VirtualCellLocation vcell_loc, gboolean visible)
Set the visibility flag for a particular location.
Definition: table-allgui.c:720
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
CursorClass
Types of cursors.

◆ gnc_split_register_show_present_divider()

void gnc_split_register_show_present_divider ( SplitRegister *  reg,
gboolean  show_present 
)

If TRUE, visually indicate the demarcation between splits with post dates prior to the present, and after.

This will only make sense if the splits are ordered primarily by post date.

Definition at line 2502 of file split-register.c.

2504 {
2505  SRInfo* info = gnc_split_register_get_info (reg);
2506 
2507  if (reg == NULL)
2508  return;
2509 
2510  info->show_present_divider = show_present;
2511 }

◆ gnc_split_register_unvoid_current_trans()

void gnc_split_register_unvoid_current_trans ( SplitRegister *  reg)

Unvoids the transaction associated with the current cursor, if non-NULL.

Definition at line 1312 of file split-register.c.

1313 {
1314  SRInfo* info = gnc_split_register_get_info (reg);
1315  Transaction* pending_trans;
1316  Transaction* trans;
1317  Split* blank_split;
1318  Split* split;
1319 
1320  if (!reg) return;
1321 
1322  blank_split = xaccSplitLookup (&info->blank_split_guid,
1323  gnc_get_current_book ());
1324  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1325  gnc_get_current_book ());
1326 
1327  /* get the current split based on cursor position */
1329  if (split == NULL)
1330  return;
1331 
1332  /* Bail if trying to unvoid the blank split. */
1333  if (split == blank_split)
1334  return;
1335 
1336  /* not voided. */
1337  if (xaccSplitGetReconcile (split) != VREC)
1338  return;
1339 
1340  info->trans_expanded = FALSE;
1341 
1342  gnc_suspend_gui_refresh ();
1343 
1344  trans = xaccSplitGetParent (split);
1345 
1346  xaccTransUnvoid (trans);
1347 
1348  /* Check pending transaction */
1349  if (trans == pending_trans)
1350  {
1351  info->pending_trans_guid = *guid_null ();
1352  pending_trans = NULL;
1353  }
1354 
1355  gnc_resume_gui_refresh ();
1356 }
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define VREC
split is void
Definition: Split.h:75
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
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.
Definition: Split.c:1072
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
Definition: Transaction.c:2869
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_void_current_trans()

void gnc_split_register_void_current_trans ( SplitRegister *  reg,
const char *  reason 
)

Voids the transaction associated with the current cursor, if non-NULL.

Definition at line 1262 of file split-register.c.

1263 {
1264  SRInfo* info = gnc_split_register_get_info (reg);
1265  Transaction* pending_trans;
1266  Transaction* trans;
1267  Split* blank_split;
1268  Split* split;
1269 
1270  if (!reg) return;
1271 
1272  blank_split = xaccSplitLookup (&info->blank_split_guid,
1273  gnc_get_current_book ());
1274  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1275  gnc_get_current_book ());
1276 
1277  /* get the current split based on cursor position */
1279  if (split == NULL)
1280  return;
1281 
1282  /* Bail if trying to void the blank split. */
1283  if (split == blank_split)
1284  return;
1285 
1286  /* already voided. */
1287  if (xaccSplitGetReconcile (split) == VREC)
1288  return;
1289 
1290  info->trans_expanded = FALSE;
1291 
1292  gnc_suspend_gui_refresh ();
1293 
1294  trans = xaccSplitGetParent (split);
1295  xaccTransVoid (trans, reason);
1296 
1297  /* Check pending transaction */
1298  if (trans == pending_trans)
1299  {
1300  info->pending_trans_guid = *guid_null ();
1301  pending_trans = NULL;
1302  }
1303  if (xaccTransIsOpen (trans))
1304  {
1305  PERR ("We should not be voiding an open transaction.");
1306  xaccTransCommitEdit (trans);
1307  }
1308  gnc_resume_gui_refresh ();
1309 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define VREC
split is void
Definition: Split.h:75
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Definition: Transaction.c:1043
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.
Definition: Split.c:1072
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
Definition: Transaction.c:2785
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:131
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.