GnuCash  4.13-177-g21dd8aa057+
Files | Data Structures | Macros | Typedefs | Enumerations | Functions

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

Files

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

Data Structures

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

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Cell Names

T* cells are transaction summary cells

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

Cursor Names

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

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

Detailed Description

GnuCash-specific ledger and journal displays based on RegisterCore.

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

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

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

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

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

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

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

Enumeration Type Documentation

◆ SplitRegisterType

Register types.

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

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

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

◆ SplitRegisterTypeGroup

Register group types.

used for grouping registers that have the same layout

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

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

Function Documentation

◆ gnc_split_register_cancel_cursor_split_changes()

void gnc_split_register_cancel_cursor_split_changes ( SplitRegister *  reg)

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

The change flags are cleared.

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

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

◆ gnc_split_register_cancel_cursor_trans_changes()

void gnc_split_register_cancel_cursor_trans_changes ( SplitRegister *  reg)

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

The change flags are cleared.

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

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

◆ gnc_split_register_change_blank_split_ref()

void gnc_split_register_change_blank_split_ref ( SplitRegister *  reg,
Split *  split 
)

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

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

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

1111 {
1112  SRInfo* info = gnc_split_register_get_info (reg);
1113  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1114  gnc_get_current_book ());
1115  Split* pref_split = NULL; // has the same account as incoming split
1116  Split* other_split = NULL; // other split
1117  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1118  Transaction* trans = xaccSplitGetParent (split);
1119 
1120  // loop through splitlist looking for splits other than the blank_split
1121  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1122  {
1123  Split *s = n->data;
1124  if (s != current_blank_split)
1125  {
1126  if (blank_split_account == xaccSplitGetAccount (s))
1127  pref_split = s; // prefer same account
1128  else
1129  other_split = s; // any other split
1130  }
1131  }
1132  // now change the saved blank split reference
1133  if (pref_split != NULL)
1134  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1135  else if (other_split != NULL)
1136  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1137 }
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1074
#define xaccSplitGetGUID(X)
Definition: Split.h:554
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.

◆ gnc_split_register_changed()

gboolean gnc_split_register_changed ( SplitRegister *  reg)

Returns TRUE if the register has changed cells.

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

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

◆ gnc_split_register_collapse_current_trans()

void gnc_split_register_collapse_current_trans ( SplitRegister *  reg)

Mark the current transaction as collapsed, and do callbacks.

◆ gnc_split_register_config()

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

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

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

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

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

◆ gnc_split_register_control_new()

TableControl* gnc_split_register_control_new ( void  )

Create a new TableControl specialized for the SplitRegister.

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

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

◆ gnc_split_register_copy_current()

void gnc_split_register_copy_current ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_current_trans_expanded()

gboolean gnc_split_register_current_trans_expanded ( SplitRegister *  reg)

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

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

265 {
266  SRInfo* info = gnc_split_register_get_info (reg);
267 
268  if (!reg)
269  return FALSE;
270 
271  if (reg->style == REG_STYLE_AUTO_LEDGER ||
272  reg->style == REG_STYLE_JOURNAL)
273  return TRUE;
274 
275  return info->trans_expanded;
276 }

◆ gnc_split_register_cut_current()

void gnc_split_register_cut_current ( SplitRegister *  reg)

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

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

853 {
854  SRInfo* info = gnc_split_register_get_info (reg);
855  CursorClass cursor_class;
856  Transaction* trans;
857  Split* blank_split;
858  gboolean changed;
859  Split* split;
860 
861  blank_split = xaccSplitLookup (&info->blank_split_guid,
862  gnc_get_current_book ());
865 
866  /* This shouldn't happen, but be paranoid. */
867  if (trans == NULL)
868  return;
869 
870  cursor_class = gnc_split_register_get_current_cursor_class (reg);
871 
872  /* Can't do anything with this. */
873  if (cursor_class == CURSOR_CLASS_NONE)
874  return;
875 
876  /* This shouldn't happen, but be paranoid. */
877  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
878  return;
879 
880  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
881 
882  /* See if we were asked to cut an unchanged blank split. Don't. */
883  if (!changed && ((split == NULL) || (split == blank_split)))
884  return;
885 
886  gnc_split_register_copy_current_internal (reg, TRUE);
887 
888  if (cursor_class == CURSOR_CLASS_SPLIT)
890  else
892 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL. ...
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1074
CursorClass
Types of cursors.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_delete_current_split()

void gnc_split_register_delete_current_split ( SplitRegister *  reg)

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

Deleting the blank split just clears cursor values.

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

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

◆ gnc_split_register_delete_current_trans()

void gnc_split_register_delete_current_trans ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_destroy()

void gnc_split_register_destroy ( SplitRegister *  reg)

Destroys a split register.

Parameters
rega ::SplitRegister

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

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

◆ gnc_split_register_duplicate_current()

Split* gnc_split_register_duplicate_current ( SplitRegister *  reg)

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

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

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

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

◆ gnc_split_register_empty_current_trans_except_split()

void gnc_split_register_empty_current_trans_except_split ( SplitRegister *  reg,
Split *  split 
)

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

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

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

◆ gnc_split_register_expand_current_trans()

void gnc_split_register_expand_current_trans ( SplitRegister *  reg,
gboolean  expand 
)

Expand the current transaction if it is collapsed.

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

205 {
206  SRInfo* info = gnc_split_register_get_info (reg);
207  VirtualLocation virt_loc;
208 
209  if (!reg)
210  return;
211 
212  if (reg->style == REG_STYLE_AUTO_LEDGER ||
213  reg->style == REG_STYLE_JOURNAL)
214  return;
215 
216  /* ok, so I just wanted an excuse to use exclusive-or */
217  if (! (expand ^ info->trans_expanded))
218  return;
219 
220  if (!expand)
221  {
222  virt_loc = reg->table->current_cursor_loc;
223  gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
224  &virt_loc.vcell_loc);
225 
226  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
227  gnc_table_move_cursor_gui (reg->table, virt_loc);
228  else
229  {
230  PERR ("Can't find place to go!");
231  return;
232  }
233  }
234 
235  info->trans_expanded = expand;
236 
237  gnc_table_set_virt_cell_cursor (reg->table,
238  reg->table->current_cursor_loc.vcell_loc,
239  gnc_split_register_get_active_cursor (reg));
240 
242  reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
243 
244  virt_loc = reg->table->current_cursor_loc;
245  if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
246  {
247  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
248  gnc_table_move_cursor_gui (reg->table, virt_loc);
249  else
250  {
251  PERR ("Can't find place to go!");
252  return;
253  }
254  }
255 
256  gnc_table_refresh_gui (reg->table, TRUE);
257 
258  if (expand)
259  gnc_split_register_show_trans (reg,
260  reg->table->current_cursor_loc.vcell_loc);
261 }
void gnc_split_register_set_trans_visible(SplitRegister *reg, VirtualCellLocation vcell_loc, gboolean visible, gboolean only_blank_split)
Set the visibility of the split rows belonging to a transaction located at vcell_loc.
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
Definition: table-allgui.c:737

◆ gnc_split_register_get_blank_split()

Split* gnc_split_register_get_blank_split ( SplitRegister *  reg)

Gets the blank split for a register.

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

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

314 {
315  SRInfo* info = gnc_split_register_get_info (reg);
316 
317  if (!reg) return NULL;
318 
319  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
320 }
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1074

◆ gnc_split_register_get_credit_string()

const char* gnc_split_register_get_credit_string ( SplitRegister *  reg)

Return the credit string used in the register.

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

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

◆ gnc_split_register_get_current_cursor_class()

CursorClass gnc_split_register_get_current_cursor_class ( SplitRegister *  reg)

Returns the class of a register's current cursor.

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

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

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

◆ gnc_split_register_get_current_split()

Split* gnc_split_register_get_current_split ( SplitRegister *  reg)

Returns the split at which the cursor is currently located.

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

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

304 {
305  if (reg == NULL)
306  return NULL;
307 
308  return gnc_split_register_get_split (
309  reg, reg->table->current_cursor_loc.vcell_loc);
310 }

◆ gnc_split_register_get_current_trans()

Transaction* gnc_split_register_get_current_trans ( SplitRegister *  reg)

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

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

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

280 {
281  Split* split;
282  VirtualCellLocation vcell_loc;
283 
284  if (reg == NULL)
285  return NULL;
286 
288  if (split != NULL)
289  return xaccSplitGetParent (split);
290 
291  /* Split is blank. Assume it is the blank split of a multi-line
292  * transaction. Go back one row to find a split in the transaction. */
293  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
294 
295  vcell_loc.virt_row--;
296 
297  split = gnc_split_register_get_split (reg, vcell_loc);
298 
299  return xaccSplitGetParent (split);
300 }
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_get_current_trans_split()

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

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

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

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

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

◆ gnc_split_register_get_cursor_class()

CursorClass gnc_split_register_get_cursor_class ( SplitRegister *  reg,
VirtualCellLocation  vcell_loc 
)

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

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

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

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

◆ gnc_split_register_get_debit_string()

const char* gnc_split_register_get_debit_string ( SplitRegister *  reg)

Return the debit string used in the register.

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

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

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

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

◆ gnc_split_register_get_split_amount_virt_loc()

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

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

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

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

365 {
366  VirtualLocation v_loc;
367  CursorClass cursor_class;
368  const char* cell_name;
369  gnc_numeric value;
370 
371  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
372  return FALSE;
373 
374  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
375 
376  value = xaccSplitGetValue (split);
377 
378  switch (cursor_class)
379  {
380  case CURSOR_CLASS_SPLIT:
381  case CURSOR_CLASS_TRANS:
382  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
383  break;
384  default:
385  return FALSE;
386  }
387 
388  if (!gnc_table_get_cell_location (reg->table, cell_name,
389  v_loc.vcell_loc, &v_loc))
390  return FALSE;
391 
392  if (virt_loc == NULL)
393  return TRUE;
394 
395  *virt_loc = v_loc;
396 
397  return TRUE;
398 }
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
CursorClass
Types of cursors.
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84

◆ gnc_split_register_get_split_virt_loc()

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

Searches the split register for a given split.

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

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

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

325 {
326  Table* table;
327  int v_row;
328  int v_col;
329 
330  if (!reg || !split) return FALSE;
331 
332  table = reg->table;
333 
334  /* go backwards because typically you search for splits at the end
335  * and because we find split rows before transaction rows. */
336 
337  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
338  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
339  {
340  VirtualCellLocation vc_loc = { v_row, v_col };
341  VirtualCell* vcell;
342  Split* s;
343 
344  vcell = gnc_table_get_virtual_cell (table, vc_loc);
345  if (!vcell || !vcell->visible)
346  continue;
347 
348  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
349 
350  if (s == split)
351  {
352  if (vcell_loc)
353  *vcell_loc = vc_loc;
354 
355  return TRUE;
356  }
357  }
358 
359  return FALSE;
360 }
gpointer vcell_data
Array of physical cells.
Definition: table-allgui.h:135
holds information about each virtual cell.
Definition: table-allgui.h:132
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1074
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
unsigned int visible
Used by higher-level code.
Definition: table-allgui.h:138

◆ gnc_split_register_handle_exchange()

gboolean gnc_split_register_handle_exchange ( SplitRegister *  reg,
gboolean  force_dialog 
)

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

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

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

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

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

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

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

◆ gnc_split_register_is_blank_split()

gboolean gnc_split_register_is_blank_split ( SplitRegister *  reg,
Split *  split 
)

Return TRUE if split is the blank_split.

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

1098 {
1099  SRInfo* info = gnc_split_register_get_info (reg);
1100  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1101  gnc_get_current_book ());
1102 
1103  if (split == current_blank_split)
1104  return TRUE;
1105 
1106  return FALSE;
1107 }
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.c:1074

◆ gnc_split_register_layout_new()

TableLayout* gnc_split_register_layout_new ( SplitRegister *  reg)

Generate the split register layout.

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

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

◆ gnc_split_register_load()

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

Populates the rows of a register.

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

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

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

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

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

◆ gnc_split_register_new()

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

Creates a new split register.

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

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

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

◆ gnc_split_register_paste_current()

void gnc_split_register_paste_current ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

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

1477 {
1478  gnc_ledger_display_refresh_by_split_register (reg);
1479 }

◆ gnc_split_register_save()

gboolean gnc_split_register_save ( SplitRegister *  reg,
gboolean  do_commit 
)

Copy the contents of the current cursor to a split.

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

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

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

2955 {
2956  g_return_if_fail (reg);
2957  reg->do_auto_complete = do_auto_complete;
2958 }

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

3113 {
3114  gnc_table_model_set_read_only (reg->table->model, read_only);
3115 }

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

2947 {
2948  g_return_if_fail (reg);
2949  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
2950 }

◆ gnc_split_register_set_template_account()

void gnc_split_register_set_template_account ( SplitRegister *  reg,
Account template_account 
)

Set the template account for use in a template register.

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

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

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

◆ gnc_split_register_set_trans_visible()

void gnc_split_register_set_trans_visible ( SplitRegister *  reg,
VirtualCellLocation  vcell_loc,
gboolean  visible,
gboolean  only_blank_split 
)

Set the visibility of the split rows belonging to a transaction located at vcell_loc.

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

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

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

◆ gnc_split_register_show_present_divider()

void gnc_split_register_show_present_divider ( SplitRegister *  reg,
gboolean  show_present 
)

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

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

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

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

◆ gnc_split_register_unvoid_current_trans()

void gnc_split_register_unvoid_current_trans ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_void_current_trans()

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

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

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

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