GnuCash  5.6-133-gc519490283+
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_reverse_sort (SplitRegister *reg, gboolean reverse_sort)
 Sets a split register's reverse sort order based on register. 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 1423 of file split-register.c.

1424 {
1425  VirtualLocation virt_loc;
1426 
1427  if (reg == NULL)
1428  return;
1429 
1430  virt_loc = reg->table->current_cursor_loc;
1431 
1432  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1433  return;
1434 
1435  /* We're just cancelling the current split here, not the transaction.
1436  * When cancelling edits, reload the cursor from the transaction. */
1437  gnc_table_clear_current_cursor_changes (reg->table);
1438 
1439  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1440  gnc_table_move_cursor_gui (reg->table, virt_loc);
1441 
1442  gnc_table_refresh_gui (reg->table, TRUE);
1443 }
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 1446 of file split-register.c.

1447 {
1448  SRInfo* info = gnc_split_register_get_info (reg);
1449  Transaction* pending_trans, *blank_trans;
1450  gboolean refresh_all = FALSE;
1451 
1452  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1453  gnc_get_current_book ());
1454 
1456 
1457  if (pending_trans == blank_trans)
1458  refresh_all = TRUE;
1459 
1460  /* Get the currently open transaction, rollback the edits on it, and
1461  * then repaint everything. To repaint everything, make a note of
1462  * all of the accounts that will be affected by this rollback. */
1463  if (!xaccTransIsOpen (pending_trans))
1464  {
1466  return;
1467  }
1468 
1469  if (!pending_trans)
1470  return;
1471 
1472  gnc_suspend_gui_refresh ();
1473 
1474  xaccTransRollbackEdit (pending_trans);
1475 
1476  info->pending_trans_guid = *guid_null ();
1477 
1478  gnc_resume_gui_refresh ();
1479 
1480  if (refresh_all)
1481  gnc_gui_refresh_all (); // force a refresh of all registers
1482  else
1484 }
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...
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:130
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...

◆ 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 1121 of file split-register.c.

1122 {
1123  SRInfo* info = gnc_split_register_get_info (reg);
1124  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1125  gnc_get_current_book ());
1126  Split* pref_split = NULL; // has the same account as incoming split
1127  Split* other_split = NULL; // other split
1128  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1129  Transaction* trans = xaccSplitGetParent (split);
1130 
1131  // loop through splitlist looking for splits other than the blank_split
1132  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1133  {
1134  Split *s = n->data;
1135  if (s != current_blank_split)
1136  {
1137  if (blank_split_account == xaccSplitGetAccount (s))
1138  pref_split = s; // prefer same account
1139  else
1140  other_split = s; // any other split
1141  }
1142  }
1143  // now change the saved blank split reference
1144  if (pref_split != NULL)
1145  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1146  else if (other_split != NULL)
1147  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1148 }
STRUCTS.
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.cpp:1103
#define xaccSplitGetGUID(X)
Definition: Split.h:555
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 2481 of file split-register.c.

2482 {
2483  SRInfo* info = gnc_split_register_get_info (reg);
2484  Transaction* pending_trans;
2485 
2486  ENTER ("reg=%p", reg);
2487 
2488  if (reg == NULL)
2489  {
2490  LEAVE ("no register");
2491  return FALSE;
2492  }
2493 
2494  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2495  {
2496  LEAVE ("cursor changed");
2497  return TRUE;
2498  }
2499 
2500  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2501  gnc_get_current_book ());
2502  if (xaccTransIsOpen (pending_trans))
2503  {
2504  LEAVE ("open and pending txn");
2505  return TRUE;
2506  }
2507 
2508  LEAVE ("register unchanged");
2509  return FALSE;
2510 }
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...
#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 2924 of file split-register.c.

2928 {
2929  if (!reg) return;
2930 
2931  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2932  if (reg->use_double_line && !use_double_line)
2933  {
2934  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2935  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
2936  {
2937  if (virt_loc.phys_row_offset)
2938  {
2939  gnc_table_move_vertical_position (reg->table, &virt_loc,
2940  -virt_loc.phys_row_offset);
2941  gnc_table_move_cursor_gui (reg->table, virt_loc);
2942  }
2943  }
2944  else
2945  {
2946  /* WTF? Go to a known safe location. */
2947  virt_loc.vcell_loc.virt_row = 1;
2948  virt_loc.vcell_loc.virt_col = 0;
2949  virt_loc.phys_row_offset = 0;
2950  virt_loc.phys_col_offset = 0;
2951  gnc_table_move_cursor_gui (reg->table, virt_loc);
2952  }
2953  }
2954 
2955  reg->type = newtype;
2956 
2957  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
2958  newstyle = REG_STYLE_JOURNAL;
2959 
2960  reg->style = newstyle;
2961  reg->use_double_line = use_double_line;
2962 
2963  gnc_table_realize_gui (reg->table);
2964 }
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 1815 of file split-register-control.cpp.

1816 {
1817  TableControl *control = gnc_table_control_new();
1818 
1819  control->move_cursor = gnc_split_register_move_cursor;
1820  control->traverse = gnc_split_register_traverse;
1821 
1822  return control;
1823 }

◆ 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 858 of file split-register.c.

859 {
860  gnc_split_register_copy_current_internal (reg, FALSE);
861 }

◆ 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 279 of file split-register.c.

280 {
281  SRInfo* info = gnc_split_register_get_info (reg);
282 
283  if (!reg)
284  return FALSE;
285 
286  if (reg->style == REG_STYLE_AUTO_LEDGER ||
287  reg->style == REG_STYLE_JOURNAL)
288  return TRUE;
289 
290  return info->trans_expanded;
291 }

◆ 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 864 of file split-register.c.

865 {
866  SRInfo* info = gnc_split_register_get_info (reg);
867  CursorClass cursor_class;
868  Transaction* trans;
869  Split* blank_split;
870  gboolean changed;
871  Split* split;
872 
873  blank_split = xaccSplitLookup (&info->blank_split_guid,
874  gnc_get_current_book ());
877 
878  /* This shouldn't happen, but be paranoid. */
879  if (trans == NULL)
880  return;
881 
882  cursor_class = gnc_split_register_get_current_cursor_class (reg);
883 
884  /* Can't do anything with this. */
885  if (cursor_class == CURSOR_CLASS_NONE)
886  return;
887 
888  /* This shouldn't happen, but be paranoid. */
889  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
890  return;
891 
892  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
893 
894  /* See if we were asked to cut an unchanged blank split. Don't. */
895  if (!changed && ((split == NULL) || (split == blank_split)))
896  return;
897 
898  gnc_split_register_copy_current_internal (reg, TRUE);
899 
900  if (cursor_class == CURSOR_CLASS_SPLIT)
902  else
904 }
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.cpp:1103
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 1151 of file split-register.c.

1152 {
1153  SRInfo* info = gnc_split_register_get_info (reg);
1154  Transaction* pending_trans;
1155  Transaction* trans;
1156  Split* blank_split;
1157  Split* split;
1158 
1159  if (!reg) return;
1160 
1161  blank_split = xaccSplitLookup (&info->blank_split_guid,
1162  gnc_get_current_book ());
1163 
1164  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1165  gnc_get_current_book ());
1166 
1167  /* get the current split based on cursor position */
1169  if (split == NULL)
1170  return;
1171 
1172  /* If we are deleting the blank split, just cancel. The user is
1173  * allowed to delete the blank split as a method for discarding
1174  * any edits they may have made to it. */
1175  if (split == blank_split)
1176  {
1178  return;
1179  }
1180 
1181  gnc_suspend_gui_refresh ();
1182 
1183  trans = xaccSplitGetParent (split);
1184 
1185  /* Check pending transaction */
1186  if (trans == pending_trans)
1187  {
1188  g_assert (xaccTransIsOpen (trans));
1189  }
1190  else
1191  {
1192  g_assert (!pending_trans);
1193  if (gnc_split_register_begin_edit_or_warn (info, trans))
1194  {
1195  gnc_resume_gui_refresh ();
1196  return;
1197  }
1198  }
1199  xaccSplitDestroy (split);
1200 
1201  gnc_resume_gui_refresh ();
1203 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1504
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...
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.cpp:1103
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 1206 of file split-register.c.

1207 {
1208  SRInfo* info = gnc_split_register_get_info (reg);
1209  Transaction* pending_trans;
1210  Transaction* trans;
1211  Split* blank_split;
1212  Split* split;
1213  gboolean was_open;
1214 
1215  ENTER ("reg=%p", reg);
1216  if (!reg)
1217  {
1218  LEAVE ("no register");
1219  return;
1220  }
1221 
1222  blank_split = xaccSplitLookup (&info->blank_split_guid,
1223  gnc_get_current_book ());
1224  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1225  gnc_get_current_book ());
1226 
1227  /* get the current split based on cursor position */
1229  if (split == NULL)
1230  {
1231  LEAVE ("no split");
1232  return;
1233  }
1234 
1235  gnc_suspend_gui_refresh ();
1236  trans = xaccSplitGetParent (split);
1237 
1238  /* If we just deleted the blank split, clean up. The user is
1239  * allowed to delete the blank split as a method for discarding
1240  * any edits they may have made to it. */
1241  if (split == blank_split)
1242  {
1243  DEBUG ("deleting blank split");
1244  info->blank_split_guid = *guid_null ();
1245  info->auto_complete = FALSE;
1246  }
1247  else
1248  {
1249  info->trans_expanded = FALSE;
1250  }
1251 
1252  /* Check pending transaction */
1253  if (trans == pending_trans)
1254  {
1255  DEBUG ("clearing pending trans");
1256  info->pending_trans_guid = *guid_null ();
1257  pending_trans = NULL;
1258  }
1259 
1260  was_open = xaccTransIsOpen (trans);
1261  xaccTransDestroy (trans);
1262  if (was_open)
1263  {
1264  DEBUG ("committing");
1265  xaccTransCommitEdit (trans);
1266  }
1267  gnc_resume_gui_refresh ();
1269  LEAVE (" ");
1270 }
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...
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.cpp:1103
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:130
#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 3096 of file split-register.c.

3097 {
3098  g_return_if_fail (reg);
3099 
3100  ENTER ("reg=%p", reg);
3101 
3102  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3103  GNC_PREF_ACCOUNTING_LABELS,
3104  split_register_pref_changed,
3105  reg);
3106  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3107  GNC_PREF_ACCOUNT_SEPARATOR,
3108  split_register_pref_changed,
3109  reg);
3110  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3111  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3112  split_register_pref_changed,
3113  reg);
3114  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3115  GNC_PREF_ALT_COLOR_BY_TRANS,
3116  split_register_pref_changed,
3117  reg);
3118  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3119  split_register_book_option_changed,
3120  reg);
3121 
3122  gnc_split_register_cleanup (reg);
3123 
3124  gnc_table_destroy (reg->table);
3125  reg->table = NULL;
3126 
3127  /* free the memory itself */
3128  g_free (reg);
3129  LEAVE (" ");
3130 }
#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 416 of file split-register.c.

417 {
418  SRInfo* info = gnc_split_register_get_info (reg);
419  CursorClass cursor_class;
420  Transaction* trans;
421  Split* return_split;
422  Split* trans_split;
423  Split* blank_split;
424  gboolean changed;
425  Split* split;
426 
427  ENTER ("reg=%p", reg);
428 
429  blank_split = xaccSplitLookup (&info->blank_split_guid,
430  gnc_get_current_book ());
433  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
434 
435  /* This shouldn't happen, but be paranoid. */
436  if (trans == NULL)
437  {
438  LEAVE ("no transaction");
439  return NULL;
440  }
441 
442  cursor_class = gnc_split_register_get_current_cursor_class (reg);
443 
444  /* Can't do anything with this. */
445  if (cursor_class == CURSOR_CLASS_NONE)
446  {
447  LEAVE ("no cursor class");
448  return NULL;
449  }
450 
451  /* This shouldn't happen, but be paranoid. */
452  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
453  {
454  LEAVE ("no split with transaction class");
455  return NULL;
456  }
457 
458  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
459 
460  /* See if we were asked to duplicate an unchanged blank split.
461  * There's no point in doing that! */
462  if (!changed && ((split == NULL) || (split == blank_split)))
463  {
464  LEAVE ("skip unchanged blank split");
465  return NULL;
466  }
467 
468  gnc_suspend_gui_refresh ();
469 
470  /* If the cursor has been edited, we are going to have to commit
471  * it before we can duplicate. Make sure the user wants to do that. */
472  if (changed)
473  {
474  GtkWidget* dialog, *window;
475  gint response;
476  const char* title = _ ("Save transaction before duplicating?");
477  const char* message =
478  _ ("The current transaction has been changed. Would you like to "
479  "record the changes before duplicating the transaction, or "
480  "cancel the duplication?");
481 
482  window = gnc_split_register_get_parent (reg);
483  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
484  GTK_DIALOG_DESTROY_WITH_PARENT,
485  GTK_MESSAGE_QUESTION,
486  GTK_BUTTONS_CANCEL,
487  "%s", title);
488  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
489  "%s", message);
490  gtk_dialog_add_button (GTK_DIALOG (dialog),
491  _ ("_Record"), GTK_RESPONSE_ACCEPT);
492  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_TRANS_DUP);
493  gtk_widget_destroy (dialog);
494 
495  if (response != GTK_RESPONSE_ACCEPT)
496  {
497  gnc_resume_gui_refresh ();
498  LEAVE ("save cancelled");
499  return NULL;
500  }
501 
502  gnc_split_register_save (reg, TRUE);
503 
504  /* If the split is NULL, then we were on a blank split row
505  * in an expanded transaction. The new split (created by
506  * gnc_split_register_save above) will be the last split in the
507  * current transaction, as it was just added. */
508  if (split == NULL)
509  split = xaccTransGetSplit (trans, xaccTransCountSplits (trans) - 1);
510  }
511 
512  /* Ok, we are now ready to make the copy. */
513 
514  if (cursor_class == CURSOR_CLASS_SPLIT)
515  {
516  Split* new_split;
517  char* out_num;
518  gboolean new_act_num = FALSE;
519 
520  /* We are on a split in an expanded transaction.
521  * Just copy the split and add it to the transaction.
522  * However, if the split-action field is being used as the register
523  * number, and the action field is a number, request a new value or
524  * cancel. Need to get next number and update account last num from
525  * split account not register account, which may be the same or not */
526 
527  if (!reg->use_tran_num_for_num_field
528  && gnc_strisnum (gnc_get_num_action (NULL, split)))
529  {
530  Account* account = xaccSplitGetAccount (split);
531  const char* in_num = NULL;
532  const char* title = _ ("New Split Information");
533  time64 date = info->last_date_entered;
534 
535  if (account)
536  in_num = xaccAccountGetLastNum (account);
537  else
538  in_num = gnc_get_num_action (NULL, split);
539 
540  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg),
541  title, FALSE, &date, in_num, &out_num,
542  NULL, NULL, NULL, NULL))
543  {
544  gnc_resume_gui_refresh ();
545  LEAVE ("dup cancelled");
546  return NULL;
547  }
548  new_act_num = TRUE;
549  }
550 
551  new_split = xaccMallocSplit (gnc_get_current_book ());
552 
553  xaccTransBeginEdit (trans);
554  xaccSplitSetParent (new_split, trans);
555  gnc_copy_split_onto_split (split, new_split, FALSE);
556  if (new_act_num) /* if new number supplied by user dialog */
557  gnc_set_num_action (NULL, new_split, out_num, NULL);
558 
559  xaccTransCommitEdit (trans);
560 
561  if (new_act_num && gnc_strisnum (out_num))
562  {
563  Account* account = xaccSplitGetAccount (new_split);
564 
565  /* If current register is for account, set last num */
566  if (xaccAccountEqual (account,
567  gnc_split_register_get_default_account (reg),
568  TRUE))
569  {
570  NumCell* num_cell;
571  num_cell = (NumCell*) gnc_table_layout_get_cell (reg->table->layout,
572  NUM_CELL);
573  if (gnc_num_cell_set_last_num (num_cell, out_num))
574  gnc_split_register_set_last_num (reg, out_num);
575  }
576  else
577  {
578  xaccAccountSetLastNum (account, out_num);
579  }
580  }
581 
582  return_split = new_split;
583 
584  info->cursor_hint_split = new_split;
585  info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
586  if (new_act_num)
587  g_free (out_num);
588  }
589  else
590  {
591  Account* account;
592  NumCell* num_cell;
593  Transaction* new_trans;
594  int trans_split_index;
595  int split_index;
596  const char* in_num = NULL;
597  const char* in_tnum = NULL;
598  char* out_num = NULL;
599  char* out_tnum = NULL;
600  char* out_tdoclink = NULL;
601  time64 date;
602  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
603  gnc_get_current_book ());
604 
605  /* We are on a transaction row. Copy the whole transaction. */
606 
607  date = info->last_date_entered;
608 
609  account = gnc_split_register_get_default_account (reg);
610 
611  if (account && gnc_strisnum (gnc_get_num_action (trans, trans_split)))
612  in_num = xaccAccountGetLastNum (account);
613  else
614  in_num = gnc_get_num_action (trans, trans_split);
615 
616  in_tnum = (reg->use_tran_num_for_num_field
617  ? NULL
618  : gnc_get_num_action (trans, NULL));
619 
620  if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg), NULL,
621  TRUE, &date, in_num, &out_num, in_tnum, &out_tnum,
622  xaccTransGetDocLink (trans), &out_tdoclink))
623  {
624  gnc_resume_gui_refresh ();
625  LEAVE ("dup cancelled");
626  return NULL;
627  }
628 
629  if (use_autoreadonly)
630  {
631  GDate d;
632  GDate* readonly_threshold = qof_book_get_autoreadonly_gdate (
633  gnc_get_current_book ());
634  gnc_gdate_set_time64 (&d, date);
635  if (g_date_compare (&d, readonly_threshold) < 0)
636  {
637  GtkWidget* dialog = gtk_message_dialog_new (NULL,
638  0,
639  GTK_MESSAGE_ERROR,
640  GTK_BUTTONS_OK,
641  "%s", _ ("Cannot store a transaction at this date"));
642  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
643  "%s", _ ("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book. "
644  "This setting can be changed in File->Properties->Accounts."));
645  gtk_dialog_run (GTK_DIALOG (dialog));
646  gtk_widget_destroy (dialog);
647 
648  g_date_free (readonly_threshold);
649  return NULL;
650  }
651  g_date_free (readonly_threshold);
652  }
653 
654  split_index = xaccTransGetSplitIndex (trans, split);
655  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
656 
657  /* we should *always* find the split, but be paranoid */
658  if (split_index < 0)
659  {
660  gnc_resume_gui_refresh ();
661  LEAVE ("no split");
662  return NULL;
663  }
664 
665  new_trans = xaccMallocTransaction (gnc_get_current_book ());
666 
667  xaccTransBeginEdit (new_trans);
668  gnc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
669  xaccTransSetDatePostedSecsNormalized (new_trans, date);
670  /* We also must set a new DateEntered on the new entry
671  * because otherwise the ordering is not deterministic */
672  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
673 
674  /* clear the document link entry if returned value NULL */
675  if (out_tdoclink == NULL)
676  xaccTransSetDocLink (new_trans, "");
677  else
678  g_free (out_tdoclink);
679 
680  /* set per book option */
681  gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
682  if (!reg->use_tran_num_for_num_field)
683  {
684  /* find split in new_trans that equals trans_split and set
685  * split_action to out_num */
686  gnc_set_num_action (NULL,
687  xaccTransGetSplit (new_trans, trans_split_index),
688  out_num, NULL);
689  /* note that if the transaction has multiple splits to the register
690  * account, only the anchor split will be set with user input. The
691  * user will have to adjust other splits manually. */
692  }
693  xaccTransCommitEdit (new_trans);
694 
695  num_cell = (NumCell*) gnc_table_layout_get_cell (reg->table->layout,
696  NUM_CELL);
697  if (gnc_num_cell_set_last_num (num_cell, out_num))
698  gnc_split_register_set_last_num (reg, out_num);
699 
700  g_free (out_num);
701  if (!reg->use_tran_num_for_num_field)
702  g_free (out_tnum);
703 
704  /* This shouldn't happen, but be paranoid. */
705  if (split_index >= xaccTransCountSplits (new_trans))
706  split_index = 0;
707 
708  return_split = xaccTransGetSplit (new_trans, split_index);
709  trans_split = xaccTransGetSplit (new_trans, trans_split_index);
710 
711  info->cursor_hint_trans = new_trans;
712  info->cursor_hint_split = return_split;
713  info->cursor_hint_trans_split = trans_split;
714  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
715 
716  info->trans_expanded = FALSE;
717  }
718 
719  /* Refresh the GUI. */
720  gnc_resume_gui_refresh ();
721 
722  LEAVE (" ");
723  return return_split;
724 }
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.
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4919
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...
STRUCTS.
#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:4931
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:988
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.cpp:1103
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:1674
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()
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:1243
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.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current time
Definition: gnc-date.cpp:261
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:962
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 1370 of file split-register.c.

1372 {
1373  SRInfo* info;
1374  Transaction* trans;
1375  Transaction* pending;
1376  int i = 0;
1377  Split* s;
1378 
1379  if ((reg == NULL) || (split == NULL))
1380  return;
1381 
1382  gnc_suspend_gui_refresh ();
1383  info = gnc_split_register_get_info (reg);
1384  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1385 
1386  trans = xaccSplitGetParent (split);
1387  if (!pending)
1388  {
1389  if (gnc_split_register_begin_edit_or_warn (info, trans))
1390  {
1391  gnc_resume_gui_refresh ();
1392  return;
1393  }
1394  }
1395  else if (pending == trans)
1396  {
1397  g_assert (xaccTransIsOpen (trans));
1398  }
1399  else g_assert_not_reached ();
1400 
1401  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1402  {
1403  if (s != split)
1404  xaccSplitDestroy (s);
1405  else i++;
1406  }
1407 
1408  gnc_resume_gui_refresh ();
1410 }
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.cpp:1504
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...
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 219 of file split-register.c.

220 {
221  SRInfo* info = gnc_split_register_get_info (reg);
222  VirtualLocation virt_loc;
223 
224  if (!reg)
225  return;
226 
227  if (reg->style == REG_STYLE_AUTO_LEDGER ||
228  reg->style == REG_STYLE_JOURNAL)
229  return;
230 
231  /* ok, so I just wanted an excuse to use exclusive-or */
232  if (! (expand ^ info->trans_expanded))
233  return;
234 
235  if (!expand)
236  {
237  virt_loc = reg->table->current_cursor_loc;
238  gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
239  &virt_loc.vcell_loc);
240 
241  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
242  gnc_table_move_cursor_gui (reg->table, virt_loc);
243  else
244  {
245  PERR ("Can't find place to go!");
246  return;
247  }
248  }
249 
250  info->trans_expanded = expand;
251 
252  gnc_table_set_virt_cell_cursor (reg->table,
253  reg->table->current_cursor_loc.vcell_loc,
254  gnc_split_register_get_active_cursor (reg));
255 
257  reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
258 
259  virt_loc = reg->table->current_cursor_loc;
260  if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
261  {
262  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
263  gnc_table_move_cursor_gui (reg->table, virt_loc);
264  else
265  {
266  PERR ("Can't find place to go!");
267  return;
268  }
269  }
270 
271  gnc_table_refresh_gui (reg->table, TRUE);
272 
273  if (expand)
274  gnc_split_register_show_trans (reg,
275  reg->table->current_cursor_loc.vcell_loc);
276 }
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 328 of file split-register.c.

329 {
330  SRInfo* info = gnc_split_register_get_info (reg);
331 
332  if (!reg) return NULL;
333 
334  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
335 }
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.cpp:1103

◆ 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 2458 of file split-register.c.

2459 {
2460  SRInfo* info = gnc_split_register_get_info (reg);
2461 
2462  if (!reg)
2463  return NULL;
2464 
2465  if (info->credit_str)
2466  return info->credit_str;
2467 
2468  info->credit_str =
2470  (gnc_split_register_type_to_account_type (reg->type));
2471 
2472  if (info->credit_str)
2473  return info->credit_str;
2474 
2475  info->credit_str = g_strdup (_ ("Credit"));
2476 
2477  return info->credit_str;
2478 }
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4237

◆ 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 546 of file split-register-util.c.

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

◆ 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 318 of file split-register.c.

319 {
320  if (reg == NULL)
321  return NULL;
322 
323  return gnc_split_register_get_split (
324  reg, reg->table->current_cursor_loc.vcell_loc);
325 }

◆ 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 294 of file split-register.c.

295 {
296  Split* split;
297  VirtualCellLocation vcell_loc;
298 
299  if (reg == NULL)
300  return NULL;
301 
303  if (split != NULL)
304  return xaccSplitGetParent (split);
305 
306  /* Split is blank. Assume it is the blank split of a multi-line
307  * transaction. Go back one row to find a split in the transaction. */
308  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
309 
310  vcell_loc.virt_row--;
311 
312  split = gnc_split_register_get_split (reg, vcell_loc);
313 
314  return xaccSplitGetParent (split);
315 }
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 187 of file split-register-util.c.

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

◆ 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 525 of file split-register-util.c.

527 {
528  VirtualCell *vcell;
529  Table *table;
530 
531  if (reg == NULL)
532  return CURSOR_CLASS_NONE;
533 
534  table = reg->table;
535  if (table == NULL)
536  return CURSOR_CLASS_NONE;
537 
538  vcell = gnc_table_get_virtual_cell (table, vcell_loc);
539  if (vcell == NULL)
540  return CURSOR_CLASS_NONE;
541 
542  return gnc_split_register_cursor_class (reg, vcell->cellblock);
543 }
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 2435 of file split-register.c.

2436 {
2437  SRInfo* info = gnc_split_register_get_info (reg);
2438 
2439  if (!reg)
2440  return NULL;
2441 
2442  if (info->debit_str)
2443  return info->debit_str;
2444 
2445  info->debit_str =
2447  (gnc_split_register_type_to_account_type (reg->type));
2448 
2449  if (info->debit_str)
2450  return info->debit_str;
2451 
2452  info->debit_str = g_strdup (_ ("Debit"));
2453 
2454  return info->debit_str;
2455 }
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4225

◆ 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 3139 of file split-register.c.

3140 {
3141  switch (reg->type)
3142  {
3143  case BANK_REGISTER:
3144  case CASH_REGISTER:
3145  case ASSET_REGISTER:
3146  case CREDIT_REGISTER:
3147  case LIABILITY_REGISTER:
3148  case INCOME_REGISTER:
3149  case EXPENSE_REGISTER:
3150  case EQUITY_REGISTER:
3151  case TRADING_REGISTER:
3152  {
3153  return REG_TYPE_GROUP_CURRENCY;
3154  break;
3155  }
3156  case PAYABLE_REGISTER:
3157  case RECEIVABLE_REGISTER:
3158  {
3159  return REG_TYPE_GROUP_APAR;
3160  break;
3161  }
3162  case INCOME_LEDGER:
3163  case GENERAL_JOURNAL:
3164  case SEARCH_LEDGER:
3165  {
3166  return REG_TYPE_GROUP_JOURNAL;
3167  break;
3168  }
3169  case STOCK_REGISTER:
3170  case CURRENCY_REGISTER:
3171  {
3172  return REG_TYPE_GROUP_STOCK;
3173  break;
3174  }
3175  case PORTFOLIO_LEDGER:
3176  {
3177  return REG_TYPE_GROUP_PORTFOLIO;
3178  break;
3179  }
3180  default:
3181  return REG_TYPE_GROUP_UNKNOWN;
3182  PERR ("unknown register type %d\n", reg->type);
3183  break;
3184  }
3185 }
#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 378 of file split-register.c.

380 {
381  VirtualLocation v_loc;
382  CursorClass cursor_class;
383  const char* cell_name;
384  gnc_numeric value;
385 
386  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
387  return FALSE;
388 
389  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
390 
391  value = xaccSplitGetValue (split);
392 
393  switch (cursor_class)
394  {
395  case CURSOR_CLASS_SPLIT:
396  case CURSOR_CLASS_TRANS:
397  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
398  break;
399  default:
400  return FALSE;
401  }
402 
403  if (!gnc_table_get_cell_location (reg->table, cell_name,
404  v_loc.vcell_loc, &v_loc))
405  return FALSE;
406 
407  if (virt_loc == NULL)
408  return TRUE;
409 
410  *virt_loc = v_loc;
411 
412  return TRUE;
413 }
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 338 of file split-register.c.

340 {
341  Table* table;
342  int v_row;
343  int v_col;
344 
345  if (!reg || !split) return FALSE;
346 
347  table = reg->table;
348 
349  /* go backwards because typically you search for splits at the end
350  * and because we find split rows before transaction rows. */
351 
352  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
353  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
354  {
355  VirtualCellLocation vc_loc = { v_row, v_col };
356  VirtualCell* vcell;
357  Split* s;
358 
359  vcell = gnc_table_get_virtual_cell (table, vc_loc);
360  if (!vcell || !vcell->visible)
361  continue;
362 
363  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
364 
365  if (s == split)
366  {
367  if (vcell_loc)
368  *vcell_loc = vc_loc;
369 
370  return TRUE;
371  }
372  }
373 
374  return FALSE;
375 }
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.cpp:1103
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 1285 of file split-register-control.cpp.

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

1109 {
1110  SRInfo* info = gnc_split_register_get_info (reg);
1111  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1112  gnc_get_current_book ());
1113 
1114  if (split == current_blank_split)
1115  return TRUE;
1116 
1117  return FALSE;
1118 }
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.cpp:1103

◆ gnc_split_register_layout_new()

TableLayout* gnc_split_register_layout_new ( SplitRegister *  reg)

Generate the split register layout.

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

868 {
869  TableLayout* layout;
870 
871  layout = gnc_table_layout_new();
872 
873  gnc_split_register_layout_add_cells (reg, layout);
874  gnc_split_register_layout_add_cursors (reg, layout);
875  gnc_split_register_set_cells (reg, layout);
876 
877  return layout;
878 }
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 369 of file split-register-load.c.

371 {
372  SRInfo* info;
373  Transaction* pending_trans;
374  CursorBuffer* cursor_buffer;
375  GHashTable* trans_table = NULL;
376  CellBlock* cursor_header;
377  CellBlock* lead_cursor;
378  CellBlock* split_cursor;
379  Transaction* blank_trans;
380  Transaction* find_trans;
381  Transaction* trans;
382  CursorClass find_class;
383  Split* find_trans_split;
384  Split* blank_split;
385  Split* find_split;
386  Split* split;
387  Table* table;
388  GList* node;
389  gnc_commodity *account_comm = NULL;
390 
391  gboolean start_primary_color = TRUE;
392  gboolean found_pending = FALSE;
393  gboolean need_divider_upper = FALSE;
394  gboolean found_divider_upper = FALSE;
395  gboolean found_divider = FALSE;
396  gboolean has_last_num = FALSE;
397  gboolean multi_line;
398  gboolean dynamic;
399  gboolean we_own_slist = FALSE;
400  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
401  gnc_get_current_book());
402  gboolean future_after_blank = gnc_prefs_get_bool (
403  GNC_PREFS_GROUP_GENERAL_REGISTER,
404  GNC_PREF_FUTURE_AFTER_BLANK);
405  gboolean added_blank_trans = FALSE;
406 
407  VirtualCellLocation vcell_loc;
408  VirtualLocation save_loc;
409 
410  int new_trans_split_row = -1;
411  int new_trans_row = -1;
412  int new_split_row = -1;
413  time64 present, autoreadonly_time = 0;
414 
415  g_return_if_fail (reg);
416  table = reg->table;
417  g_return_if_fail (table);
418  info = gnc_split_register_get_info (reg);
419  g_return_if_fail (info);
420 
421  ENTER ("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
422 
423  blank_split = xaccSplitLookup (&info->blank_split_guid,
424  gnc_get_current_book());
425 
426  pending_trans = xaccTransLookup (&info->pending_trans_guid,
427  gnc_get_current_book());
428 
429  if (default_account)
430  account_comm = gnc_account_get_currency_or_parent (default_account);
431 
432  if (!account_comm)
433  account_comm = gnc_default_currency ();
434 
435  /* Bug 742089: Set the debit and credit cells' print_info to the account */
437  ((PriceCell*) gnc_table_layout_get_cell (table->layout, DEBT_CELL),
438  gnc_commodity_print_info (account_comm, FALSE));
439 
441  ((PriceCell*) gnc_table_layout_get_cell (table->layout, CRED_CELL),
442  gnc_commodity_print_info (account_comm, FALSE));
443 
445  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
446  gnc_commodity_print_info (account_comm, FALSE));
447 
448  /* Only test for linked document glyths once */
449  if (info->first_pass)
450  {
451  gnc_doclink_cell_set_use_glyphs
452  ((Doclinkcell *) gnc_table_layout_get_cell (table->layout, DOCLINK_CELL));
453  }
454 
455  /* make sure we have a blank split */
456  if (blank_split == NULL)
457  {
458  /* Wouldn't it be a bug to open the new transaction if there was
459  * already a pending transaction?
460  */
461  g_assert (pending_trans == NULL);
462  blank_split = create_blank_split (default_account, info);
463  }
464  blank_trans = xaccSplitGetParent (blank_split);
465 
466  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
467  blank_split, blank_trans, pending_trans);
468 
469  info->default_account = *xaccAccountGetGUID (default_account);
470 
471  // gnc_table_leave_update (table, table->current_cursor_loc);
472 
473  multi_line = (reg->style == REG_STYLE_JOURNAL);
474  dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
475 
476  lead_cursor = gnc_split_register_get_passive_cursor (reg);
477  split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
478 
479  /* figure out where we are going to. */
480  if (info->traverse_to_new)
481  {
482  find_trans = blank_trans;
483  find_split = NULL;
484  find_trans_split = blank_split;
485  find_class = CURSOR_CLASS_SPLIT;
486  }
487  else
488  {
489  find_trans = info->cursor_hint_trans;
490  find_split = info->cursor_hint_split;
491  find_trans_split = info->cursor_hint_trans_split;
492  find_class = info->cursor_hint_cursor_class;
493  }
494 
495  save_loc = table->current_cursor_loc;
496 
497  /* If the current cursor has changed we save the values for later
498  * possible restoration. */
499  if (gnc_table_current_cursor_changed (table, TRUE) &&
500  (find_split == gnc_split_register_get_current_split (reg)))
501  {
502  cursor_buffer = gnc_cursor_buffer_new();
503  gnc_table_save_current_cursor (table, cursor_buffer);
504  }
505  else
506  cursor_buffer = NULL;
507 
508  /* disable move callback -- we don't want the cascade of
509  * callbacks while we are fiddling with loading the register */
510  gnc_table_control_allow_move (table->control, FALSE);
511 
512  /* invalidate the cursor */
513  {
514  VirtualLocation virt_loc;
515 
516  gnc_virtual_location_init (&virt_loc);
517  gnc_table_move_cursor_gui (table, virt_loc);
518  }
519 
520  /* make sure that the header is loaded */
521  vcell_loc.virt_row = 0;
522  vcell_loc.virt_col = 0;
523  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
524  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
525  vcell_loc.virt_row++;
526 
527  /* get the current time and reset the dividing row */
528  present = gnc_time64_get_today_end();
529  if (use_autoreadonly)
530  {
531  GDate* d = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
532  // "d" is NULL if use_autoreadonly is FALSE
533  autoreadonly_time = d ? gdate_to_time64 (*d) : 0;
534  g_date_free (d);
535  }
536 
537  if (info->first_pass)
538  {
539  if (default_account)
540  {
541  const char* last_num = xaccAccountGetLastNum (default_account);
542 
543  if (last_num)
544  {
545  NumCell* cell;
546 
547  cell = (NumCell*) gnc_table_layout_get_cell (table->layout, NUM_CELL);
548  gnc_num_cell_set_last_num (cell, last_num);
549  has_last_num = TRUE;
550  }
551  }
552 
553  /* load up account names into the transfer combobox menus */
554  gnc_split_register_load_xfer_cells (reg, default_account);
555  gnc_split_register_load_desc_cells (reg);
556  gnc_split_register_load_doclink_cells (reg);
557  gnc_split_register_load_recn_cells (reg);
558  gnc_split_register_load_type_cells (reg);
559  }
560 
561  if (info->separator_changed)
562  change_account_separator (info, table, reg);
563 
564  table->model->dividing_row_upper = -1;
565  table->model->dividing_row = -1;
566  table->model->dividing_row_lower = -1;
567 
568  // Ensure that the transaction and splits being edited are in the split
569  // list we're about to load.
570  if (pending_trans != NULL)
571  {
572  for (node = xaccTransGetSplitList (pending_trans); node; node = node->next)
573  {
574  Split* pending_split = (Split*)node->data;
575  if (!xaccTransStillHasSplit (pending_trans, pending_split)) continue;
576  if (g_list_find (slist, pending_split) != NULL)
577  continue;
578 
579  if (g_list_find_custom (slist, pending_trans,
580  _find_split_with_parent_txn) != NULL)
581  continue;
582 
583  if (!we_own_slist)
584  {
585  // lazy-copy
586  slist = g_list_copy (slist);
587  we_own_slist = TRUE;
588  }
589  slist = g_list_append (slist, pending_split);
590  }
591  }
592 
593  if (multi_line)
594  trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
595 
596  // View reversed add blank transaction at the top
597  if (table->model->reverse_sort && !future_after_blank)
598  {
599  if (blank_trans == find_trans)
600  new_trans_row = vcell_loc.virt_row;
601 
602  if (blank_split == find_trans_split)
603  new_trans_split_row = vcell_loc.virt_row;
604 
605  /* go to blank on first pass */
606  if (info->first_pass)
607  {
608  save_loc.vcell_loc = vcell_loc;
609  save_loc.phys_row_offset = 0;
610  save_loc.phys_col_offset = 0;
611  }
612 
613  // used in the setting the rows insensitive
614  table->model->blank_trans_row = vcell_loc.virt_row;
615 
616  gnc_split_register_add_transaction (reg,
617  blank_trans, blank_split,
618  lead_cursor, split_cursor,
619  multi_line, start_primary_color,
620  info->blank_split_edited,
621  find_trans, find_split,
622  find_class, &new_split_row,
623  &vcell_loc);
624 
625  if (!multi_line)
626  start_primary_color = !start_primary_color;
627 
628  added_blank_trans = TRUE;
629  }
630 
631  gnc_completion_cell_clear_menu (
632  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL));
633 
635  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
636  table->model->reverse_sort);
637 
638  /* populate the table */
639  for (node = slist; node; node = node->next)
640  {
641  split = node->data;
642  trans = xaccSplitGetParent (split);
643 
644  if (!xaccTransStillHasSplit (trans, split))
645  continue;
646 
647  if (pending_trans == trans)
648  found_pending = TRUE;
649  /* If the transaction has only one split, and it's not our
650  * pending_trans, then it's another register's blank split and
651  * we don't want to see it.
652  */
653  else if (xaccTransCountSplits (trans) == 1 &&
654  xaccSplitGetAccount (split) == NULL)
655  continue;
656 
657  /* Do not load splits from the blank transaction. */
658  if (trans == blank_trans)
659  continue;
660 
661  if (multi_line)
662  {
663  /* Skip this split if its transaction has already been loaded. */
664  if (g_hash_table_lookup (trans_table, trans))
665  continue;
666 
667  g_hash_table_insert (trans_table, trans, trans);
668  }
669 
670  if (info->show_present_divider &&
671  use_autoreadonly &&
672  !found_divider_upper)
673  {
674  if (((table->model->reverse_sort && xaccTransGetDate(trans) < autoreadonly_time) ||
675  (!table->model->reverse_sort && xaccTransGetDate (trans) >= autoreadonly_time)))
676  {
677  table->model->dividing_row_upper = vcell_loc.virt_row;
678  found_divider_upper = TRUE;
679  }
680  else
681  {
682  need_divider_upper = TRUE;
683  }
684  }
685 
686  if (info->show_present_divider && !found_divider &&
687  ((table->model->reverse_sort && xaccTransGetDate (trans) < present) ||
688  (!table->model->reverse_sort && xaccTransGetDate (trans) > present)))
689  {
690  gint count_blank_splits = 1;
691  gint virt_row_offset = 2;
692  gboolean show_lower_divider = FALSE;
693 
694  if (table->model->reverse_sort)
695  {
696  count_blank_splits = xaccTransCountSplits (blank_trans);
697 
698  if (count_blank_splits > 1)
699  count_blank_splits ++;
700 
701  if (table->model->reverse_sort && future_after_blank)
702  virt_row_offset = 0;
703  }
704 
705  if ((table->model->reverse_sort && vcell_loc.virt_row != count_blank_splits + virt_row_offset) ||
706  !table->model->reverse_sort)
707  {
708  table->model->dividing_row = vcell_loc.virt_row; // blue top
709  show_lower_divider = TRUE;
710  }
711 
712  found_divider = TRUE;
713 
714  if (future_after_blank)
715  {
716  if (blank_trans == find_trans)
717  new_trans_row = vcell_loc.virt_row;
718 
719  if (blank_split == find_trans_split)
720  new_trans_split_row = vcell_loc.virt_row;
721 
722  /* go to blank on first pass */
723  if (info->first_pass)
724  {
725  save_loc.vcell_loc = vcell_loc;
726  save_loc.phys_row_offset = 0;
727  save_loc.phys_col_offset = 0;
728  }
729 
730  // used in the setting the rows insensitive
731  table->model->blank_trans_row = vcell_loc.virt_row;
732 
733  gnc_split_register_add_transaction (reg,
734  blank_trans, blank_split,
735  lead_cursor, split_cursor,
736  multi_line, start_primary_color,
737  info->blank_split_edited,
738  find_trans, find_split,
739  find_class, &new_split_row,
740  &vcell_loc);
741 
742 
743  if (show_lower_divider)
744  table->model->dividing_row_lower = vcell_loc.virt_row; // blue bottom
745 
746  if (!multi_line)
747  start_primary_color = !start_primary_color;
748 
749  added_blank_trans = TRUE;
750  }
751  }
752 
753  /* On first load the split list is empty so fill up the quickfill cells
754  * only on the next load. */
755  if (!info->first_pass && !info->quickfill_setup)
756  add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
757 
759  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
760  xaccTransGetDescription (trans));
761 
762  if (trans == find_trans)
763  new_trans_row = vcell_loc.virt_row;
764 
765  if (split == find_trans_split)
766  new_trans_split_row = vcell_loc.virt_row;
767 
768  gnc_split_register_add_transaction (reg, trans, split,
769  lead_cursor, split_cursor,
770  multi_line, start_primary_color,
771  TRUE,
772  find_trans, find_split, find_class,
773  &new_split_row, &vcell_loc);
774 
775  if (!multi_line)
776  start_primary_color = !start_primary_color;
777  }
778 
779  if (multi_line)
780  g_hash_table_destroy (trans_table);
781 
782  /* add the blank split at the end. */
783  if (pending_trans == blank_trans)
784  found_pending = TRUE;
785 
786  /* No upper divider yet? Store it now */
787  if (info->show_present_divider &&
788  use_autoreadonly &&
789  !found_divider_upper && need_divider_upper)
790  {
791  table->model->dividing_row_upper = vcell_loc.virt_row;
792  }
793 
794  /* If we didn't find the pending transaction, it was removed
795  * from the account. */
796  if (!found_pending)
797  {
798  info->pending_trans_guid = *guid_null();
799  if (xaccTransIsOpen (pending_trans))
800  xaccTransCommitEdit (pending_trans);
801  else if (pending_trans)
802  g_assert_not_reached();
803 
804  pending_trans = NULL;
805  }
806 
807  if (!added_blank_trans)
808  {
809  if (blank_trans == find_trans)
810  new_trans_row = vcell_loc.virt_row;
811 
812  if (blank_split == find_trans_split)
813  new_trans_split_row = vcell_loc.virt_row;
814 
815  /* go to blank on first pass */
816  if (info->first_pass)
817  {
818  save_loc.vcell_loc = vcell_loc;
819  save_loc.phys_row_offset = 0;
820  save_loc.phys_col_offset = 0;
821  }
822 
823  // used in the setting the rows insensitive
824  table->model->blank_trans_row = vcell_loc.virt_row;
825 
826  gnc_split_register_add_transaction (reg, blank_trans, blank_split,
827  lead_cursor, split_cursor,
828  multi_line, start_primary_color,
829  info->blank_split_edited,
830  find_trans, find_split,
831  find_class, &new_split_row,
832  &vcell_loc);
833 
834  if (future_after_blank)
835  {
836  table->model->dividing_row_lower = vcell_loc.virt_row;
837  }
838  }
839 
840  /* go to blank on first pass */
841  if (info->first_pass)
842  {
843  new_split_row = -1;
844  new_trans_split_row = -1;
845  new_trans_row = -1;
846  }
847 
848  /* resize the table to the sizes we just counted above */
849  /* num_virt_cols is always one. */
850  gnc_table_set_size (table, vcell_loc.virt_row, 1);
851 
852  /* restore the cursor to its rightful position */
853  {
854  VirtualLocation trans_split_loc;
855 
856  if (new_split_row > 0)
857  save_loc.vcell_loc.virt_row = new_split_row;
858  else if (new_trans_split_row > 0)
859  save_loc.vcell_loc.virt_row = new_trans_split_row;
860  else if (new_trans_row > 0)
861  save_loc.vcell_loc.virt_row = new_trans_row;
862 
863  trans_split_loc = save_loc;
864 
865  gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
866  &trans_split_loc.vcell_loc);
867 
868  if (dynamic || multi_line || info->trans_expanded)
869  {
871  table, trans_split_loc.vcell_loc,
872  gnc_split_register_get_active_cursor (reg));
873  gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
874  TRUE, multi_line);
875 
876  info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
877  }
878  else
879  {
880  save_loc = trans_split_loc;
881  info->trans_expanded = FALSE;
882  }
883 
884  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
885  {
886  gnc_table_move_cursor_gui (table, save_loc);
887  new_split_row = save_loc.vcell_loc.virt_row;
888 
889  if (find_split == gnc_split_register_get_current_split (reg))
890  gnc_table_restore_current_cursor (table, cursor_buffer);
891  }
892  }
893  gnc_cursor_buffer_destroy (cursor_buffer);
894  cursor_buffer = NULL;
895 
896  update_info (info, reg);
897 
898  gnc_split_register_set_cell_fractions (
900 
902 
903  // if in reverse order, always show the first transaction
904  if (table->model->reverse_sort)
905  {
906  VirtualCellLocation vc_loc;
907  vc_loc.virt_row = 0;
908  vc_loc.virt_col = 0;
909  gnc_split_register_show_trans (reg, vc_loc);
910  }
911  else
912  gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
913 
914  /* enable callback for cursor user-driven moves */
915  gnc_table_control_allow_move (table->control, TRUE);
916 
917  if (we_own_slist)
918  g_list_free (slist);
919 
920  LEAVE (" ");
921 }
The CompletionCell object implements a cell handler with a "combination-box" pull-down menu in it...
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4919
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
def find_split(split_list, search_string)
void gnc_completion_cell_reverse_sort(CompletionCell *cell, gboolean is_reversed)
Register the sort direction.
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.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
#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:988
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.cpp:1103
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:54
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1252
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:3474
void gnc_completion_cell_add_menu_item(CompletionCell *cell, const char *menustr)
Add a menu item to the hash table list.
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:130
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:1355
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
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:962
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 2898 of file split-register.c.

2903 {
2904  SplitRegister* reg;
2905  gboolean default_do_auto_complete = TRUE;
2906 
2907  reg = g_new0 (SplitRegister, 1);
2908 
2909  if (type >= NUM_SINGLE_REGISTER_TYPES)
2910  style = REG_STYLE_JOURNAL;
2911 
2912  gnc_split_register_init (reg,
2913  type,
2914  style,
2915  use_double_line,
2916  default_do_auto_complete,
2917  is_template,
2918  mismatched_commodities);
2919 
2920  return reg;
2921 }

◆ 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 907 of file split-register.c.

908 {
909  SRInfo* info = gnc_split_register_get_info (reg);
910  CursorClass cursor_class;
911  Transaction* trans;
912  Transaction* blank_trans;
913  Split* blank_split;
914  Split* trans_split;
915  Split* split;
916 
917  ENTER ("reg=%p", reg);
918 
919  if (copied_class == CURSOR_CLASS_NONE)
920  {
921  LEAVE ("no copied cursor class");
922  return;
923  }
924 
925  blank_split = xaccSplitLookup (&info->blank_split_guid,
926  gnc_get_current_book ());
927  blank_trans = xaccSplitGetParent (blank_split);
930 
931  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
932 
933  /* This shouldn't happen, but be paranoid. */
934  if (trans == NULL)
935  {
936  LEAVE ("no transaction");
937  return;
938  }
939 
940  cursor_class = gnc_split_register_get_current_cursor_class (reg);
941 
942  /* Can't do anything with this. */
943  if (cursor_class == CURSOR_CLASS_NONE)
944  {
945  LEAVE ("no current cursor class");
946  return;
947  }
948 
949  /* This shouldn't happen, but be paranoid. */
950  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
951  {
952  g_warning ("BUG DETECTED: transaction cursor with no anchoring split!");
953  LEAVE ("transaction cursor with no anchoring split");
954  return;
955  }
956 
957  if (cursor_class == CURSOR_CLASS_SPLIT)
958  {
959  const char* message = _ ("You are about to overwrite an existing split. "
960  "Are you sure you want to do that?");
961  const char* anchor_message = _ ("This is the split anchoring this transaction "
962  "to the register. You may not overwrite it from "
963  "this register window. You may overwrite it if "
964  "you navigate to a register that shows another "
965  "side of this same transaction.");
966 
967  if (copied_class == CURSOR_CLASS_TRANS)
968  {
969  /* An entire transaction was copied, but we're just on a split. */
970  LEAVE ("can't copy trans to split");
971  return;
972  }
973 
974  if (split != NULL)
975  {
976  /* the General Journal does not have any anchoring splits */
977  if ((reg->type != GENERAL_JOURNAL) &&
978  split == gnc_split_register_get_current_trans_split (reg, NULL))
979  {
980  gnc_warning_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
981  "%s", anchor_message);
982  LEAVE ("anchore split");
983  return;
984  }
985  else if (!gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
986  FALSE, "%s", message))
987  {
988  LEAVE ("user cancelled");
989  return;
990  }
991  }
992 
993  /* Open the transaction for editing. */
994  if (gnc_split_register_begin_edit_or_warn (info, trans))
995  {
996  LEAVE ("can't begin editing");
997  return;
998  }
999 
1000  gnc_suspend_gui_refresh ();
1001 
1002  if (split == NULL)
1003  {
1004  /* We are on a null split in an expanded transaction. */
1005  split = xaccMallocSplit (gnc_get_current_book ());
1006  xaccSplitSetParent (split, trans);
1007  }
1008 
1009  if (copied_item.ftype != GNC_TYPE_SPLIT)
1010  {
1011  LEAVE ("copy buffer doesn't represent a split");
1012  return;
1013  }
1014 
1015  gnc_float_split_to_split (copied_item.fs, split);
1016  }
1017  else
1018  {
1019  const char *message = _("You are about to overwrite an existing "
1020  "transaction. "
1021  "Are you sure you want to do that?");
1022  Account * copied_leader;
1023  Account * default_account;
1024  int trans_split_index;
1025  int split_index;
1026  int num_splits;
1027 
1028  if (copied_class == CURSOR_CLASS_SPLIT)
1029  {
1030  LEAVE ("can't copy split to transaction");
1031  return;
1032  }
1033 
1034 
1035  if (copied_item.ftype != GNC_TYPE_TRANSACTION)
1036  {
1037  LEAVE ("copy buffer doesn't represent a transaction");
1038  return;
1039  }
1040 
1041  /* Ask before overwriting an existing transaction. */
1042  if (split != blank_split &&
1043  !gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
1044  FALSE, "%s", message))
1045  {
1046  LEAVE ("user cancelled");
1047  return;
1048  }
1049 
1050  /* Open the transaction for editing. */
1051  if (gnc_split_register_begin_edit_or_warn (info, trans))
1052  {
1053  LEAVE ("can't begin editing");
1054  return;
1055  }
1056 
1057  gnc_suspend_gui_refresh ();
1058 
1059  DEBUG ("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
1060  trans, split, blank_trans, blank_split);
1061 
1062  split_index = xaccTransGetSplitIndex (trans, split);
1063  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
1064 
1065  copied_leader = xaccAccountLookup (&copied_leader_guid,
1066  gnc_get_current_book ());
1067  default_account = gnc_split_register_get_default_account (reg);
1068  if (copied_leader && default_account)
1069  {
1070  gnc_float_txn_to_txn_swap_accounts (copied_item.ft, trans,
1071  copied_leader,
1072  default_account, FALSE);
1073  }
1074  else
1075  gnc_float_txn_to_txn (copied_item.ft, trans, FALSE);
1076 
1077  num_splits = xaccTransCountSplits (trans);
1078  if (split_index >= num_splits)
1079  split_index = 0;
1080 
1081  if (trans == blank_trans)
1082  {
1083  /* In pasting, the blank split is deleted. Pick a new one. */
1084  blank_split = xaccTransGetSplit (trans, 0);
1085  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
1086  info->blank_split_edited = TRUE;
1087  info->auto_complete = FALSE;
1088  DEBUG ("replacement blank_split=%p", blank_split);
1089 
1090  /* NOTE: At this point, the blank transaction virtual cell is still
1091  * anchored by the old, deleted blank split. The register will
1092  * have to be reloaded (redrawn) to correct this. */
1093  }
1094 
1095  info->cursor_hint_trans = trans;
1096  info->cursor_hint_split = xaccTransGetSplit (trans, split_index);
1097  info->cursor_hint_trans_split = xaccTransGetSplit (trans,
1098  trans_split_index);
1099  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
1100  }
1101 
1102  /* Refresh the GUI. */
1103  gnc_resume_gui_refresh ();
1104  LEAVE (" ");
1105 }
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...
STRUCTS.
#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.
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.cpp:1103
CursorClass
Types of cursors.
#define xaccSplitGetGUID(X)
Definition: Split.h:555
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#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.
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id...
Definition: Account.cpp:2064

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

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

1488 {
1489  gnc_ledger_display_refresh_by_split_register (reg);
1490 }

◆ 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 1713 of file split-register.c.

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

2976 {
2977  g_return_if_fail (reg);
2978  reg->do_auto_complete = do_auto_complete;
2979 }

◆ 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 3133 of file split-register.c.

3134 {
3135  gnc_table_model_set_read_only (reg->table->model, read_only);
3136 }

◆ gnc_split_register_set_reverse_sort()

void gnc_split_register_set_reverse_sort ( SplitRegister *  reg,
gboolean  reverse_sort 
)

Sets a split register's reverse sort order based on register.

Parameters
rega ::SplitRegister
reverse_sortTRUE reverse sort order, FALSE default

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

2968 {
2969  g_return_if_fail (reg);
2970  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
2971 }

◆ 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 117 of file split-register-util.c.

119 {
120  SRInfo *info = gnc_split_register_get_info (reg);
121 
122  g_return_if_fail (reg != NULL);
123 
124  info->template_account = *xaccAccountGetGUID (template_account);
125 }
#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 317 of file split-register-util.c.

321 {
322  CursorClass cursor_class;
323 
324  while (TRUE)
325  {
326  vcell_loc.virt_row++;
327 
328  cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
329  if (cursor_class != CURSOR_CLASS_SPLIT)
330  return;
331 
332  if (only_blank_split && gnc_split_register_get_split (reg, vcell_loc))
333  continue;
334 
335  gnc_table_set_virt_cell_visible (reg->table, vcell_loc, visible);
336  }
337 }
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 2513 of file split-register.c.

2515 {
2516  SRInfo* info = gnc_split_register_get_info (reg);
2517 
2518  if (reg == NULL)
2519  return;
2520 
2521  info->show_present_divider = show_present;
2522 }

◆ 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 1323 of file split-register.c.

1324 {
1325  SRInfo* info = gnc_split_register_get_info (reg);
1326  Transaction* pending_trans;
1327  Transaction* trans;
1328  Split* blank_split;
1329  Split* split;
1330 
1331  if (!reg) return;
1332 
1333  blank_split = xaccSplitLookup (&info->blank_split_guid,
1334  gnc_get_current_book ());
1335  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1336  gnc_get_current_book ());
1337 
1338  /* get the current split based on cursor position */
1340  if (split == NULL)
1341  return;
1342 
1343  /* Bail if trying to unvoid the blank split. */
1344  if (split == blank_split)
1345  return;
1346 
1347  /* not voided. */
1348  if (xaccSplitGetReconcile (split) != VREC)
1349  return;
1350 
1351  info->trans_expanded = FALSE;
1352 
1353  gnc_suspend_gui_refresh ();
1354 
1355  trans = xaccSplitGetParent (split);
1356 
1357  xaccTransUnvoid (trans);
1358 
1359  /* Check pending transaction */
1360  if (trans == pending_trans)
1361  {
1362  info->pending_trans_guid = *guid_null ();
1363  pending_trans = NULL;
1364  }
1365 
1366  gnc_resume_gui_refresh ();
1367 }
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...
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.cpp:1103
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
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 1273 of file split-register.c.

1274 {
1275  SRInfo* info = gnc_split_register_get_info (reg);
1276  Transaction* pending_trans;
1277  Transaction* trans;
1278  Split* blank_split;
1279  Split* split;
1280 
1281  if (!reg) return;
1282 
1283  blank_split = xaccSplitLookup (&info->blank_split_guid,
1284  gnc_get_current_book ());
1285  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1286  gnc_get_current_book ());
1287 
1288  /* get the current split based on cursor position */
1290  if (split == NULL)
1291  return;
1292 
1293  /* Bail if trying to void the blank split. */
1294  if (split == blank_split)
1295  return;
1296 
1297  /* already voided. */
1298  if (xaccSplitGetReconcile (split) == VREC)
1299  return;
1300 
1301  info->trans_expanded = FALSE;
1302 
1303  gnc_suspend_gui_refresh ();
1304 
1305  trans = xaccSplitGetParent (split);
1306  xaccTransVoid (trans, reason);
1307 
1308  /* Check pending transaction */
1309  if (trans == pending_trans)
1310  {
1311  info->pending_trans_guid = *guid_null ();
1312  pending_trans = NULL;
1313  }
1314  if (xaccTransIsOpen (trans))
1315  {
1316  PERR ("We should not be voiding an open transaction.");
1317  xaccTransCommitEdit (trans);
1318  }
1319  gnc_resume_gui_refresh ();
1320 }
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...
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.cpp:1103
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
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:130
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.