GnuCash  5.6-150-g038405b370+
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, GList *pre_filter_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 1433 of file split-register.c.

1434 {
1435  VirtualLocation virt_loc;
1436 
1437  if (reg == NULL)
1438  return;
1439 
1440  virt_loc = reg->table->current_cursor_loc;
1441 
1442  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1443  return;
1444 
1445  /* We're just cancelling the current split here, not the transaction.
1446  * When cancelling edits, reload the cursor from the transaction. */
1447  gnc_table_clear_current_cursor_changes (reg->table);
1448 
1449  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1450  gnc_table_move_cursor_gui (reg->table, virt_loc);
1451 
1452  gnc_table_refresh_gui (reg->table, TRUE);
1453 }
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 1456 of file split-register.c.

1457 {
1458  SRInfo* info = gnc_split_register_get_info (reg);
1459  Transaction* pending_trans, *blank_trans;
1460  gboolean refresh_all = FALSE;
1461 
1462  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1463  gnc_get_current_book ());
1464 
1466 
1467  if (pending_trans == blank_trans)
1468  refresh_all = TRUE;
1469 
1470  /* Get the currently open transaction, rollback the edits on it, and
1471  * then repaint everything. To repaint everything, make a note of
1472  * all of the accounts that will be affected by this rollback. */
1473  if (!xaccTransIsOpen (pending_trans))
1474  {
1476  return;
1477  }
1478 
1479  if (!pending_trans)
1480  return;
1481 
1482  gnc_suspend_gui_refresh ();
1483 
1484  xaccTransRollbackEdit (pending_trans);
1485 
1486  info->pending_trans_guid = *guid_null ();
1487 
1488  gnc_resume_gui_refresh ();
1489 
1490  if (refresh_all)
1491  gnc_gui_refresh_all (); // force a refresh of all registers
1492  else
1494 }
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 1129 of file split-register.c.

1130 {
1131  SRInfo* info = gnc_split_register_get_info (reg);
1132  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1133  gnc_get_current_book ());
1134  Split* pref_split = NULL; // has the same account as incoming split
1135  Split* other_split = NULL; // other split
1136  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1137  Transaction* trans = xaccSplitGetParent (split);
1138 
1139  // loop through splitlist looking for splits other than the blank_split
1140  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1141  {
1142  Split *s = n->data;
1143  if (s != current_blank_split && xaccTransStillHasSplit (trans, s))
1144  {
1145  if (blank_split_account == xaccSplitGetAccount (s))
1146  pref_split = s; // prefer same account
1147  else
1148  other_split = s; // any other split
1149  }
1150  }
1151  // now change the saved blank split reference
1152  if (pref_split != NULL)
1153  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1154  else if (other_split != NULL)
1155  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1156  else
1157  info->blank_split_guid = *guid_null();
1158 }
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:1071
#define xaccSplitGetGUID(X)
Definition: Split.h:552
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
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 2491 of file split-register.c.

2492 {
2493  SRInfo* info = gnc_split_register_get_info (reg);
2494  Transaction* pending_trans;
2495 
2496  ENTER ("reg=%p", reg);
2497 
2498  if (reg == NULL)
2499  {
2500  LEAVE ("no register");
2501  return FALSE;
2502  }
2503 
2504  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2505  {
2506  LEAVE ("cursor changed");
2507  return TRUE;
2508  }
2509 
2510  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2511  gnc_get_current_book ());
2512  if (xaccTransIsOpen (pending_trans))
2513  {
2514  LEAVE ("open and pending txn");
2515  return TRUE;
2516  }
2517 
2518  LEAVE ("register unchanged");
2519  return FALSE;
2520 }
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 2934 of file split-register.c.

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

1862 {
1863  TableControl *control = gnc_table_control_new ();
1864 
1865  control->move_cursor = gnc_split_register_move_cursor;
1866  control->traverse = gnc_split_register_traverse;
1867 
1868  return control;
1869 }

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

863 {
864  gnc_split_register_copy_current_internal (reg, FALSE);
865 }

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

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

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

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

1162 {
1163  SRInfo* info = gnc_split_register_get_info (reg);
1164  Transaction* pending_trans;
1165  Transaction* trans;
1166  Split* blank_split;
1167  Split* split;
1168 
1169  if (!reg) return;
1170 
1171  blank_split = xaccSplitLookup (&info->blank_split_guid,
1172  gnc_get_current_book ());
1173 
1174  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1175  gnc_get_current_book ());
1176 
1177  /* get the current split based on cursor position */
1179  if (split == NULL)
1180  return;
1181 
1182  /* If we are deleting the blank split, just cancel. The user is
1183  * allowed to delete the blank split as a method for discarding
1184  * any edits they may have made to it. */
1185  if (split == blank_split)
1186  {
1188  return;
1189  }
1190 
1191  gnc_suspend_gui_refresh ();
1192 
1193  trans = xaccSplitGetParent (split);
1194 
1195  /* Check pending transaction */
1196  if (trans == pending_trans)
1197  {
1198  g_assert (xaccTransIsOpen (trans));
1199  }
1200  else
1201  {
1202  g_assert (!pending_trans);
1203  if (gnc_split_register_begin_edit_or_warn (info, trans))
1204  {
1205  gnc_resume_gui_refresh ();
1206  return;
1207  }
1208  }
1209  xaccSplitDestroy (split);
1210 
1211  gnc_resume_gui_refresh ();
1213 }
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:1472
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:1071
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 1216 of file split-register.c.

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

3107 {
3108  g_return_if_fail (reg);
3109 
3110  ENTER ("reg=%p", reg);
3111 
3112  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3113  GNC_PREF_ACCOUNTING_LABELS,
3114  split_register_pref_changed,
3115  reg);
3116  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3117  GNC_PREF_ACCOUNT_SEPARATOR,
3118  split_register_pref_changed,
3119  reg);
3120  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3121  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3122  split_register_pref_changed,
3123  reg);
3124  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3125  GNC_PREF_ALT_COLOR_BY_TRANS,
3126  split_register_pref_changed,
3127  reg);
3128  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3129  split_register_book_option_changed,
3130  reg);
3131 
3132  gnc_split_register_cleanup (reg);
3133 
3134  gnc_table_destroy (reg->table);
3135  reg->table = NULL;
3136 
3137  /* free the memory itself */
3138  g_free (reg);
3139  LEAVE (" ");
3140 }
#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 419 of file split-register.c.

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

1382 {
1383  SRInfo* info;
1384  Transaction* trans;
1385  Transaction* pending;
1386  int i = 0;
1387  Split* s;
1388 
1389  if ((reg == NULL) || (split == NULL))
1390  return;
1391 
1392  gnc_suspend_gui_refresh ();
1393  info = gnc_split_register_get_info (reg);
1394  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1395 
1396  trans = xaccSplitGetParent (split);
1397  if (!pending)
1398  {
1399  if (gnc_split_register_begin_edit_or_warn (info, trans))
1400  {
1401  gnc_resume_gui_refresh ();
1402  return;
1403  }
1404  }
1405  else if (pending == trans)
1406  {
1407  g_assert (xaccTransIsOpen (trans));
1408  }
1409  else g_assert_not_reached ();
1410 
1411  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1412  {
1413  if (s != split)
1414  xaccSplitDestroy (s);
1415  else i++;
1416  }
1417 
1418  gnc_resume_gui_refresh ();
1420 }
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:1472
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 222 of file split-register.c.

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

332 {
333  SRInfo* info = gnc_split_register_get_info (reg);
334 
335  if (!reg) return NULL;
336 
337  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
338 }
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:1071

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

2469 {
2470  SRInfo* info = gnc_split_register_get_info (reg);
2471 
2472  if (!reg)
2473  return NULL;
2474 
2475  if (info->credit_str)
2476  return info->credit_str;
2477 
2478  info->credit_str =
2480  (gnc_split_register_type_to_account_type (reg->type));
2481 
2482  if (info->credit_str)
2483  return info->credit_str;
2484 
2485  info->credit_str = g_strdup (_ ("Credit"));
2486 
2487  return info->credit_str;
2488 }
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4058

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

322 {
323  if (reg == NULL)
324  return NULL;
325 
326  return gnc_split_register_get_split (
327  reg, reg->table->current_cursor_loc.vcell_loc);
328 }

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

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

2446 {
2447  SRInfo* info = gnc_split_register_get_info (reg);
2448 
2449  if (!reg)
2450  return NULL;
2451 
2452  if (info->debit_str)
2453  return info->debit_str;
2454 
2455  info->debit_str =
2457  (gnc_split_register_type_to_account_type (reg->type));
2458 
2459  if (info->debit_str)
2460  return info->debit_str;
2461 
2462  info->debit_str = g_strdup (_ ("Debit"));
2463 
2464  return info->debit_str;
2465 }
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4046

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

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

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

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

1330 {
1331  SRInfo *info;
1332  Transaction *txn;
1333  Split *split, *osplit;
1334  Account *xfer_acc, *reg_acc;
1335  gnc_commodity *txn_cur, *xfer_com, *reg_com;
1336  gnc_numeric amount, exch_rate;
1337  XferDialog *xfer;
1338  gboolean expanded = FALSE;
1339  PriceCell *rate_cell;
1340  const char *message;
1341  CursorClass cursor_class;
1342 
1343  ENTER("reg=%p, force_dialog=%s", reg, force_dialog ? "TRUE" : "FALSE" );
1344 
1345  /* No point in setting a rate on a template transaction. */
1346  if (reg->is_template)
1347  {
1348  LEAVE("Template transaction, rate makes no sense.");
1349  return FALSE;
1350  }
1351 
1352  /* Make sure we NEED this for this type of register */
1353  if (!gnc_split_reg_has_rate_cell (reg->type))
1354  {
1355  if (force_dialog)
1356  {
1357  message = _("This register does not support editing exchange rates.");
1358  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1359  }
1360  LEAVE("no rate cell");
1361  return FALSE;
1362  }
1363 
1364  rate_cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout, RATE_CELL);
1365 
1366  if (!rate_cell)
1367  {
1368  if (force_dialog)
1369  {
1370  message = _("This register does not support editing exchange rates.");
1371  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1372  }
1373  LEAVE("null rate cell");
1374  return FALSE;
1375  }
1376 
1377  /* See if we already have an exchange rate... */
1378  info = gnc_split_register_get_info (reg);
1379  exch_rate = gnc_price_cell_get_value (rate_cell);
1380  if (!gnc_numeric_zero_p (exch_rate) && !force_dialog &&
1381  info->rate_reset != RATE_RESET_REQD)
1382  {
1383  LEAVE("rate already non-zero");
1384  return FALSE;
1385  }
1386 
1387  /* Are we expanded? */
1389  cursor_class = gnc_split_register_get_current_cursor_class (reg);
1390 
1391  /* If we're expanded AND a transaction cursor, there is nothing to do */
1392  if (expanded && cursor_class == CURSOR_CLASS_TRANS)
1393  {
1394  if (force_dialog)
1395  {
1396  message = _("You need to select a split in order to modify its exchange "
1397  "rate.");
1398  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1399  }
1400  LEAVE("expanded with transaction cursor; nothing to do");
1401  return FALSE;
1402  }
1403 
1404  /* Grab the xfer account */
1405  xfer_acc = gnc_split_register_get_account_always (reg,
1406  expanded ? XFRM_CELL : MXFRM_CELL);
1407 
1408  /* If this is an un-expanded, multi-split transaction, then warn the user */
1409  if (force_dialog && !expanded && !xfer_acc)
1410  {
1411  message = _("You need to expand the transaction in order to modify its "
1412  "exchange rates.");
1413  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1414  LEAVE("%s", message);
1415  return TRUE;
1416  }
1417 
1418  /* No account -- don't run the dialog */
1419  if (!xfer_acc)
1420  {
1421  if (force_dialog)
1422  {
1423  message = _("The entered account could not be found.");
1424  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1425  }
1426  LEAVE("no xfer account");
1427  return FALSE;
1428  }
1429 
1430  /* Grab the txn currency and xfer commodity */
1432  txn_cur = xaccTransGetCurrency (txn);
1433  xfer_com = xaccAccountGetCommodity (xfer_acc);
1434 
1435  /* Grab the register account and commodity (may be used later) */
1436  reg_acc = gnc_split_register_get_default_account (reg);
1437  reg_com = xaccAccountGetCommodity (reg_acc);
1438 
1439  /* Grab the split and perhaps the "other" split (if it is a two-split txn) */
1441  osplit = xaccSplitGetOtherSplit (split);
1442 
1443  /* Check if the txn- and xfer- commodities are the same */
1444  if (gnc_commodity_equal (txn_cur, xfer_com))
1445  {
1446  /* If we're not forcing the dialog, then there is no reason to
1447  * go on. We're using the correct accounts.
1448  */
1449  if (!force_dialog)
1450  {
1451  LEAVE("txn and account currencies match, and not forcing");
1452  return FALSE;
1453  }
1454 
1455  /* Only proceed with two-split, basic, non-expanded registers */
1456  if (expanded || osplit == NULL)
1457  {
1458  message = _("The two currencies involved equal each other.");
1459  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1460  LEAVE("register is expanded or osplit == NULL; not forcing dialog");
1461  return FALSE;
1462  }
1463 
1464  /* If we're forcing, then compare the current account
1465  * commodity to the transaction currency.
1466  */
1467  xfer_acc = reg_acc;
1468  xfer_com = reg_com;
1469  if (gnc_commodity_equal (txn_cur, xfer_com))
1470  {
1471  message = _("The two currencies involved equal each other.");
1472  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1473  LEAVE("reg commodity == txn commodity; not forcing");
1474  return FALSE;
1475  }
1476  }
1477 
1478  /* If this is a non-expanded, two-split txn where BOTH splits need
1479  * conversion rates, then require the user to actually expand the
1480  * transaction in order to edit it.
1481  */
1482  if (!expanded && osplit &&
1483  gnc_split_register_split_needs_amount (reg, split) &&
1484  gnc_split_register_split_needs_amount (reg, osplit))
1485  {
1486  message = _("You need to expand the transaction in order to modify its "
1487  "exchange rates.");
1488  if (force_dialog)
1489  {
1490  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1491  }
1492  LEAVE("%s", message);
1493  return TRUE;
1494  }
1495 
1496  /* Strangely, if we're in a two-split, non-expanded txn, we need
1497  * to do something really special with the exchange rate! In
1498  * particular, we have to pick it up from the _other_ split --
1499  * right?
1500  * XXX: perhaps I should pop up an error here? Or maybe require the
1501  * user to go into expanded-mode?
1502  */
1503  if (!expanded && osplit &&
1504  !gnc_commodity_equal (reg_com, txn_cur) &&
1505  !gnc_commodity_equal (reg_com, xfer_com))
1506  {
1507  gnc_numeric amt = xaccSplitGetAmount (osplit);
1508  gnc_numeric val = xaccSplitGetValue (osplit);
1509  exch_rate = gnc_numeric_div (amt, val, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
1510  }
1511 
1512  /* Ok, we need to grab the exchange rate */
1513  amount = gnc_split_register_debcred_cell_value (reg);
1514 
1515  /*
1516  * If "amount" is zero then we don't need an exchange-rate.. Return
1517  * FALSE to let the user continue on.
1518  */
1519  if (gnc_numeric_zero_p (amount))
1520  {
1521  if (force_dialog)
1522  {
1523  message = _("The split's amount is zero, so no exchange rate is needed.");
1524  gnc_error_dialog (GTK_WINDOW(gnc_split_register_get_parent (reg)), "%s", message);
1525  }
1526  LEAVE("amount is zero; no exchange rate needed");
1527  return FALSE;
1528  }
1529 
1530  /* If the exch_rate is zero, we're not forcing the dialog, and this is
1531  * _not_ the blank split, then return FALSE -- this is a "special"
1532  * gain/loss stock transaction.
1533  */
1534  if (gnc_numeric_zero_p (exch_rate) && !force_dialog && split &&
1535  info->rate_reset != RATE_RESET_REQD &&
1536  split != gnc_split_register_get_blank_split (reg))
1537  {
1538  LEAVE("gain/loss split; no exchange rate needed");
1539  return FALSE;
1540  }
1541 
1542  /* Show the exchange-rate dialog */
1543  xfer = gnc_split_register_xfer_dialog (reg, txn, split);
1544  gnc_xfer_dialog_is_exchange_dialog (xfer, &exch_rate);
1545  if (gnc_xfer_dialog_run_exchange_dialog (xfer, &exch_rate, amount,
1546  reg_acc, txn, xfer_com, expanded))
1547  {
1548  /* FIXME: How should the dialog be destroyed? */
1549  LEAVE("leaving rate unchanged");
1550  return TRUE;
1551  }
1552  /* FIXME: How should the dialog be destroyed? */
1553 
1554  /* Set the RATE_CELL on this cursor and mark it changed */
1555  gnc_price_cell_set_value (rate_cell, exch_rate);
1556  gnc_basic_cell_set_changed (&rate_cell->cell, TRUE);
1557  info->rate_account = xfer_acc;
1558  info->rate_reset = RATE_RESET_DONE;
1559  LEAVE("set rate=%s", gnc_num_dbg_to_string (exch_rate));
1560  return FALSE;
1561 }
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:195
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 x, gnc_numeric y, 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:3371
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:245
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 1116 of file split-register.c.

1117 {
1118  SRInfo* info = gnc_split_register_get_info (reg);
1119  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1120  gnc_get_current_book ());
1121 
1122  if (split == current_blank_split)
1123  return TRUE;
1124 
1125  return FALSE;
1126 }
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:1071

◆ 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,
GList *  pre_filter_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
pre_filter_slistthe list of splits before applying filter
default_accountan account to provide defaults for the blank split

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

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

2913 {
2914  SplitRegister* reg;
2915  gboolean default_do_auto_complete = TRUE;
2916 
2917  reg = g_new0 (SplitRegister, 1);
2918 
2919  if (type >= NUM_SINGLE_REGISTER_TYPES)
2920  style = REG_STYLE_JOURNAL;
2921 
2922  gnc_split_register_init (reg,
2923  type,
2924  style,
2925  use_double_line,
2926  default_do_auto_complete,
2927  is_template,
2928  mismatched_commodities);
2929 
2930  return reg;
2931 }

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

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

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

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

1498 {
1499  gnc_ledger_display_refresh_by_split_register (reg);
1500 }

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

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

2986 {
2987  g_return_if_fail (reg);
2988  reg->do_auto_complete = do_auto_complete;
2989 }

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

3144 {
3145  gnc_table_model_set_read_only (reg->table->model, read_only);
3146 }

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

2978 {
2979  g_return_if_fail (reg);
2980  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
2981 }

◆ 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:252

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

2525 {
2526  SRInfo* info = gnc_split_register_get_info (reg);
2527 
2528  if (reg == NULL)
2529  return;
2530 
2531  info->show_present_divider = show_present;
2532 }

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

1334 {
1335  SRInfo* info = gnc_split_register_get_info (reg);
1336  Transaction* pending_trans;
1337  Transaction* trans;
1338  Split* blank_split;
1339  Split* split;
1340 
1341  if (!reg) return;
1342 
1343  blank_split = xaccSplitLookup (&info->blank_split_guid,
1344  gnc_get_current_book ());
1345  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1346  gnc_get_current_book ());
1347 
1348  /* get the current split based on cursor position */
1350  if (split == NULL)
1351  return;
1352 
1353  /* Bail if trying to unvoid the blank split. */
1354  if (split == blank_split)
1355  return;
1356 
1357  /* not voided. */
1358  if (xaccSplitGetReconcile (split) != VREC)
1359  return;
1360 
1361  info->trans_expanded = FALSE;
1362 
1363  gnc_suspend_gui_refresh ();
1364 
1365  trans = xaccSplitGetParent (split);
1366 
1367  xaccTransUnvoid (trans);
1368 
1369  /* Check pending transaction */
1370  if (trans == pending_trans)
1371  {
1372  info->pending_trans_guid = *guid_null ();
1373  pending_trans = NULL;
1374  }
1375 
1376  gnc_resume_gui_refresh ();
1377 }
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:77
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:1071
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 1283 of file split-register.c.

1284 {
1285  SRInfo* info = gnc_split_register_get_info (reg);
1286  Transaction* pending_trans;
1287  Transaction* trans;
1288  Split* blank_split;
1289  Split* split;
1290 
1291  if (!reg) return;
1292 
1293  blank_split = xaccSplitLookup (&info->blank_split_guid,
1294  gnc_get_current_book ());
1295  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1296  gnc_get_current_book ());
1297 
1298  /* get the current split based on cursor position */
1300  if (split == NULL)
1301  return;
1302 
1303  /* Bail if trying to void the blank split. */
1304  if (split == blank_split)
1305  return;
1306 
1307  /* already voided. */
1308  if (xaccSplitGetReconcile (split) == VREC)
1309  return;
1310 
1311  info->trans_expanded = FALSE;
1312 
1313  gnc_suspend_gui_refresh ();
1314 
1315  trans = xaccSplitGetParent (split);
1316  xaccTransVoid (trans, reason);
1317 
1318  /* Check pending transaction */
1319  if (trans == pending_trans)
1320  {
1321  info->pending_trans_guid = *guid_null ();
1322  pending_trans = NULL;
1323  }
1324  if (xaccTransIsOpen (trans))
1325  {
1326  PERR ("We should not be voiding an open transaction.");
1327  xaccTransCommitEdit (trans);
1328  }
1329  gnc_resume_gui_refresh ();
1330 }
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:77
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:1071
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.