GnuCash  5.6-150-g038405b370+
Files | Data Structures | Macros | Typedefs | Enumerations | Functions

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

Files

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

Data Structures

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

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Cell Names

T* cells are transaction summary cells

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

Cursor Names

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

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

Detailed Description

GnuCash-specific ledger and journal displays based on RegisterCore.

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

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

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

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

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

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

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

Enumeration Type Documentation

◆ SplitRegisterType

Register types.

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

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

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

◆ SplitRegisterTypeGroup

Register group types.

used for grouping registers that have the same layout

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

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

Function Documentation

◆ gnc_split_register_cancel_cursor_split_changes()

void gnc_split_register_cancel_cursor_split_changes ( SplitRegister *  reg)

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

The change flags are cleared.

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

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

1455 {
1456  SRInfo* info = gnc_split_register_get_info (reg);
1457  Transaction* pending_trans, *blank_trans;
1458  gboolean refresh_all = FALSE;
1459 
1460  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1461  gnc_get_current_book ());
1462 
1464 
1465  if (pending_trans == blank_trans)
1466  refresh_all = TRUE;
1467 
1468  /* Get the currently open transaction, rollback the edits on it, and
1469  * then repaint everything. To repaint everything, make a note of
1470  * all of the accounts that will be affected by this rollback. */
1471  if (!xaccTransIsOpen (pending_trans))
1472  {
1474  return;
1475  }
1476 
1477  if (!pending_trans)
1478  return;
1479 
1480  gnc_suspend_gui_refresh ();
1481 
1482  xaccTransRollbackEdit (pending_trans);
1483 
1484  info->pending_trans_guid = *guid_null ();
1485 
1486  gnc_resume_gui_refresh ();
1487 
1488  if (refresh_all)
1489  gnc_gui_refresh_all (); // force a refresh of all registers
1490  else
1492 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
Split * gnc_split_register_get_blank_split(SplitRegister *reg)
Gets the blank split for a register.
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
void xaccTransRollbackEdit(Transaction *trans)
The xaccTransRollbackEdit() routine rejects all edits made, and sets the transaction back to where it...

◆ gnc_split_register_change_blank_split_ref()

void gnc_split_register_change_blank_split_ref ( SplitRegister *  reg,
Split *  split 
)

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

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

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

1130 {
1131  SRInfo* info = gnc_split_register_get_info (reg);
1132  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1133  gnc_get_current_book ());
1134  Split* pref_split = NULL; // has the same account as incoming split
1135  Split* other_split = NULL; // other split
1136  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1137  Transaction* trans = xaccSplitGetParent (split);
1138 
1139  // loop through splitlist looking for splits other than the blank_split
1140  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1141  {
1142  Split *s = n->data;
1143  if (s != current_blank_split)
1144  {
1145  if (blank_split_account == xaccSplitGetAccount (s))
1146  pref_split = s; // prefer same account
1147  else
1148  other_split = s; // any other split
1149  }
1150  }
1151  // now change the saved blank split reference
1152  if (pref_split != NULL)
1153  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1154  else if (other_split != NULL)
1155  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1156 }
STRUCTS.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
#define xaccSplitGetGUID(X)
Definition: Split.h:552
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
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 2489 of file split-register.c.

2490 {
2491  SRInfo* info = gnc_split_register_get_info (reg);
2492  Transaction* pending_trans;
2493 
2494  ENTER ("reg=%p", reg);
2495 
2496  if (reg == NULL)
2497  {
2498  LEAVE ("no register");
2499  return FALSE;
2500  }
2501 
2502  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2503  {
2504  LEAVE ("cursor changed");
2505  return TRUE;
2506  }
2507 
2508  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2509  gnc_get_current_book ());
2510  if (xaccTransIsOpen (pending_trans))
2511  {
2512  LEAVE ("open and pending txn");
2513  return TRUE;
2514  }
2515 
2516  LEAVE ("register unchanged");
2517  return FALSE;
2518 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282

◆ gnc_split_register_collapse_current_trans()

void gnc_split_register_collapse_current_trans ( SplitRegister *  reg)

Mark the current transaction as collapsed, and do callbacks.

◆ gnc_split_register_config()

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

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

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

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

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

1852 {
1853  TableControl *control = gnc_table_control_new ();
1854 
1855  control->move_cursor = gnc_split_register_move_cursor;
1856  control->traverse = gnc_split_register_traverse;
1857 
1858  return control;
1859 }

◆ gnc_split_register_copy_current()

void gnc_split_register_copy_current ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_current_trans_expanded()

gboolean gnc_split_register_current_trans_expanded ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_cut_current()

void gnc_split_register_cut_current ( SplitRegister *  reg)

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

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

869 {
870  SRInfo* info = gnc_split_register_get_info (reg);
871  CursorClass cursor_class;
872  Transaction* trans;
873  Split* blank_split;
874  gboolean changed;
875  Split* split;
876 
877  blank_split = xaccSplitLookup (&info->blank_split_guid,
878  gnc_get_current_book ());
881 
882  /* This shouldn't happen, but be paranoid. */
883  if (trans == NULL)
884  return;
885 
886  cursor_class = gnc_split_register_get_current_cursor_class (reg);
887 
888  /* Can't do anything with this. */
889  if (cursor_class == CURSOR_CLASS_NONE)
890  return;
891 
892  /* This shouldn't happen, but be paranoid. */
893  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
894  return;
895 
896  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
897 
898  /* See if we were asked to cut an unchanged blank split. Don't. */
899  if (!changed && ((split == NULL) || (split == blank_split)))
900  return;
901 
902  gnc_split_register_copy_current_internal (reg, TRUE);
903 
904  if (cursor_class == CURSOR_CLASS_SPLIT)
906  else
908 }
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register's current cursor.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
void gnc_split_register_delete_current_split(SplitRegister *reg)
Deletes the split associated with the current cursor, if both are non-NULL.
void gnc_split_register_delete_current_trans(SplitRegister *reg)
Deletes the transaction associated with the current cursor, if both are non-NULL. ...
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
CursorClass
Types of cursors.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_delete_current_split()

void gnc_split_register_delete_current_split ( SplitRegister *  reg)

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

Deleting the blank split just clears cursor values.

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

1160 {
1161  SRInfo* info = gnc_split_register_get_info (reg);
1162  Transaction* pending_trans;
1163  Transaction* trans;
1164  Split* blank_split;
1165  Split* split;
1166 
1167  if (!reg) return;
1168 
1169  blank_split = xaccSplitLookup (&info->blank_split_guid,
1170  gnc_get_current_book ());
1171 
1172  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1173  gnc_get_current_book ());
1174 
1175  /* get the current split based on cursor position */
1177  if (split == NULL)
1178  return;
1179 
1180  /* If we are deleting the blank split, just cancel. The user is
1181  * allowed to delete the blank split as a method for discarding
1182  * any edits they may have made to it. */
1183  if (split == blank_split)
1184  {
1186  return;
1187  }
1188 
1189  gnc_suspend_gui_refresh ();
1190 
1191  trans = xaccSplitGetParent (split);
1192 
1193  /* Check pending transaction */
1194  if (trans == pending_trans)
1195  {
1196  g_assert (xaccTransIsOpen (trans));
1197  }
1198  else
1199  {
1200  g_assert (!pending_trans);
1201  if (gnc_split_register_begin_edit_or_warn (info, trans))
1202  {
1203  gnc_resume_gui_refresh ();
1204  return;
1205  }
1206  }
1207  xaccSplitDestroy (split);
1208 
1209  gnc_resume_gui_refresh ();
1211 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1472
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.
void gnc_split_register_cancel_cursor_split_changes(SplitRegister *reg)
Cancels any changes made to the current cursor, reloads the cursor from the engine, reloads the table from the cursor, and updates the GUI.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_delete_current_trans()

void gnc_split_register_delete_current_trans ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_destroy()

void gnc_split_register_destroy ( SplitRegister *  reg)

Destroys a split register.

Parameters
rega ::SplitRegister

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

3105 {
3106  g_return_if_fail (reg);
3107 
3108  ENTER ("reg=%p", reg);
3109 
3110  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3111  GNC_PREF_ACCOUNTING_LABELS,
3112  split_register_pref_changed,
3113  reg);
3114  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3115  GNC_PREF_ACCOUNT_SEPARATOR,
3116  split_register_pref_changed,
3117  reg);
3118  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3119  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3120  split_register_pref_changed,
3121  reg);
3122  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3123  GNC_PREF_ALT_COLOR_BY_TRANS,
3124  split_register_pref_changed,
3125  reg);
3126  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3127  split_register_book_option_changed,
3128  reg);
3129 
3130  gnc_split_register_cleanup (reg);
3131 
3132  gnc_table_destroy (reg->table);
3133  reg->table = NULL;
3134 
3135  /* free the memory itself */
3136  g_free (reg);
3137  LEAVE (" ");
3138 }
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
Definition: gnc-prefs.c:143

◆ gnc_split_register_duplicate_current()

Split* gnc_split_register_duplicate_current ( SplitRegister *  reg)

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

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

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

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

◆ gnc_split_register_empty_current_trans_except_split()

void gnc_split_register_empty_current_trans_except_split ( SplitRegister *  reg,
Split *  split 
)

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

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

1380 {
1381  SRInfo* info;
1382  Transaction* trans;
1383  Transaction* pending;
1384  int i = 0;
1385  Split* s;
1386 
1387  if ((reg == NULL) || (split == NULL))
1388  return;
1389 
1390  gnc_suspend_gui_refresh ();
1391  info = gnc_split_register_get_info (reg);
1392  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1393 
1394  trans = xaccSplitGetParent (split);
1395  if (!pending)
1396  {
1397  if (gnc_split_register_begin_edit_or_warn (info, trans))
1398  {
1399  gnc_resume_gui_refresh ();
1400  return;
1401  }
1402  }
1403  else if (pending == trans)
1404  {
1405  g_assert (xaccTransIsOpen (trans));
1406  }
1407  else g_assert_not_reached ();
1408 
1409  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1410  {
1411  if (s != split)
1412  xaccSplitDestroy (s);
1413  else i++;
1414  }
1415 
1416  gnc_resume_gui_refresh ();
1418 }
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
gboolean xaccSplitDestroy(Split *split)
Destructor.
Definition: Split.cpp:1472
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
void gnc_split_register_redraw(SplitRegister *reg)
Causes a redraw of the register window associated with reg.

◆ gnc_split_register_expand_current_trans()

void gnc_split_register_expand_current_trans ( SplitRegister *  reg,
gboolean  expand 
)

Expand the current transaction if it is collapsed.

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

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

◆ gnc_split_register_get_blank_split()

Split* gnc_split_register_get_blank_split ( SplitRegister *  reg)

Gets the blank split for a register.

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

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

332 {
333  SRInfo* info = gnc_split_register_get_info (reg);
334 
335  if (!reg) return NULL;
336 
337  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
338 }
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071

◆ gnc_split_register_get_credit_string()

const char* gnc_split_register_get_credit_string ( SplitRegister *  reg)

Return the credit string used in the register.

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

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

◆ gnc_split_register_get_current_cursor_class()

CursorClass gnc_split_register_get_current_cursor_class ( SplitRegister *  reg)

Returns the class of a register's current cursor.

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

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

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

◆ gnc_split_register_get_current_split()

Split* gnc_split_register_get_current_split ( SplitRegister *  reg)

Returns the split at which the cursor is currently located.

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

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

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

◆ gnc_split_register_get_current_trans()

Transaction* gnc_split_register_get_current_trans ( SplitRegister *  reg)

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

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

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

298 {
299  Split* split;
300  VirtualCellLocation vcell_loc;
301 
302  if (reg == NULL)
303  return NULL;
304 
306  if (split != NULL)
307  return xaccSplitGetParent (split);
308 
309  /* Split is blank. Assume it is the blank split of a multi-line
310  * transaction. Go back one row to find a split in the transaction. */
311  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
312 
313  vcell_loc.virt_row--;
314 
315  split = gnc_split_register_get_split (reg, vcell_loc);
316 
317  return xaccSplitGetParent (split);
318 }
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_get_current_trans_split()

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

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

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

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

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

◆ gnc_split_register_get_cursor_class()

CursorClass gnc_split_register_get_cursor_class ( SplitRegister *  reg,
VirtualCellLocation  vcell_loc 
)

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

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

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

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

◆ gnc_split_register_get_debit_string()

const char* gnc_split_register_get_debit_string ( SplitRegister *  reg)

Return the debit string used in the register.

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

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

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

3148 {
3149  switch (reg->type)
3150  {
3151  case BANK_REGISTER:
3152  case CASH_REGISTER:
3153  case ASSET_REGISTER:
3154  case CREDIT_REGISTER:
3155  case LIABILITY_REGISTER:
3156  case INCOME_REGISTER:
3157  case EXPENSE_REGISTER:
3158  case EQUITY_REGISTER:
3159  case TRADING_REGISTER:
3160  {
3161  return REG_TYPE_GROUP_CURRENCY;
3162  break;
3163  }
3164  case PAYABLE_REGISTER:
3165  case RECEIVABLE_REGISTER:
3166  {
3167  return REG_TYPE_GROUP_APAR;
3168  break;
3169  }
3170  case INCOME_LEDGER:
3171  case GENERAL_JOURNAL:
3172  case SEARCH_LEDGER:
3173  {
3174  return REG_TYPE_GROUP_JOURNAL;
3175  break;
3176  }
3177  case STOCK_REGISTER:
3178  case CURRENCY_REGISTER:
3179  {
3180  return REG_TYPE_GROUP_STOCK;
3181  break;
3182  }
3183  case PORTFOLIO_LEDGER:
3184  {
3185  return REG_TYPE_GROUP_PORTFOLIO;
3186  break;
3187  }
3188  default:
3189  return REG_TYPE_GROUP_UNKNOWN;
3190  PERR ("unknown register type %d\n", reg->type);
3191  break;
3192  }
3193 }
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244

◆ gnc_split_register_get_split_amount_virt_loc()

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

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

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

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

383 {
384  VirtualLocation v_loc;
385  CursorClass cursor_class;
386  const char* cell_name;
387  gnc_numeric value;
388 
389  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
390  return FALSE;
391 
392  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
393 
394  value = xaccSplitGetValue (split);
395 
396  switch (cursor_class)
397  {
398  case CURSOR_CLASS_SPLIT:
399  case CURSOR_CLASS_TRANS:
400  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
401  break;
402  default:
403  return FALSE;
404  }
405 
406  if (!gnc_table_get_cell_location (reg->table, cell_name,
407  v_loc.vcell_loc, &v_loc))
408  return FALSE;
409 
410  if (virt_loc == NULL)
411  return TRUE;
412 
413  *virt_loc = v_loc;
414 
415  return TRUE;
416 }
CursorClass gnc_split_register_get_cursor_class(SplitRegister *reg, VirtualCellLocation vcell_loc)
Returns the class of the cursor at the given virtual cell location.
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
CursorClass
Types of cursors.
gboolean gnc_split_register_get_split_virt_loc(SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc)
Searches the split register for a given split.
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84

◆ gnc_split_register_get_split_virt_loc()

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

Searches the split register for a given split.

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

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

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

343 {
344  Table* table;
345  int v_row;
346  int v_col;
347 
348  if (!reg || !split) return FALSE;
349 
350  table = reg->table;
351 
352  /* go backwards because typically you search for splits at the end
353  * and because we find split rows before transaction rows. */
354 
355  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
356  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
357  {
358  VirtualCellLocation vc_loc = { v_row, v_col };
359  VirtualCell* vcell;
360  Split* s;
361 
362  vcell = gnc_table_get_virtual_cell (table, vc_loc);
363  if (!vcell || !vcell->visible)
364  continue;
365 
366  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
367 
368  if (s == split)
369  {
370  if (vcell_loc)
371  *vcell_loc = vc_loc;
372 
373  return TRUE;
374  }
375  }
376 
377  return FALSE;
378 }
gpointer vcell_data
Array of physical cells.
Definition: table-allgui.h:135
holds information about each virtual cell.
Definition: table-allgui.h:132
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
VirtualCell * gnc_table_get_virtual_cell(Table *table, VirtualCellLocation vcell_loc)
returns the virtual cell associated with a particular virtual location.
Definition: table-allgui.c:227
unsigned int visible
Used by higher-level code.
Definition: table-allgui.h:138

◆ gnc_split_register_handle_exchange()

gboolean gnc_split_register_handle_exchange ( SplitRegister *  reg,
gboolean  force_dialog 
)

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

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

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

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

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

Definition at line 1319 of file split-register-control.cpp.

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

◆ gnc_split_register_is_blank_split()

gboolean gnc_split_register_is_blank_split ( SplitRegister *  reg,
Split *  split 
)

Return TRUE if split is the blank_split.

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

1117 {
1118  SRInfo* info = gnc_split_register_get_info (reg);
1119  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1120  gnc_get_current_book ());
1121 
1122  if (split == current_blank_split)
1123  return TRUE;
1124 
1125  return FALSE;
1126 }
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071

◆ gnc_split_register_layout_new()

TableLayout* gnc_split_register_layout_new ( SplitRegister *  reg)

Generate the split register layout.

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

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

◆ gnc_split_register_load()

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

Populates the rows of a register.

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

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

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

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

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

◆ gnc_split_register_new()

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

Creates a new split register.

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

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

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

◆ gnc_split_register_paste_current()

void gnc_split_register_paste_current ( SplitRegister *  reg)

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

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

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

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

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

1496 {
1497  gnc_ledger_display_refresh_by_split_register (reg);
1498 }

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

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

◆ gnc_split_register_set_auto_complete()

void gnc_split_register_set_auto_complete ( SplitRegister *  reg,
gboolean  do_auto_complete 
)

Sets whether a register uses auto-completion.

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

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

2984 {
2985  g_return_if_fail (reg);
2986  reg->do_auto_complete = do_auto_complete;
2987 }

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

3142 {
3143  gnc_table_model_set_read_only (reg->table->model, read_only);
3144 }

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

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

◆ gnc_split_register_set_template_account()

void gnc_split_register_set_template_account ( SplitRegister *  reg,
Account template_account 
)

Set the template account for use in a template register.

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

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

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

◆ gnc_split_register_set_trans_visible()

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

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

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

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

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

◆ gnc_split_register_show_present_divider()

void gnc_split_register_show_present_divider ( SplitRegister *  reg,
gboolean  show_present 
)

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

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

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

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

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

1332 {
1333  SRInfo* info = gnc_split_register_get_info (reg);
1334  Transaction* pending_trans;
1335  Transaction* trans;
1336  Split* blank_split;
1337  Split* split;
1338 
1339  if (!reg) return;
1340 
1341  blank_split = xaccSplitLookup (&info->blank_split_guid,
1342  gnc_get_current_book ());
1343  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1344  gnc_get_current_book ());
1345 
1346  /* get the current split based on cursor position */
1348  if (split == NULL)
1349  return;
1350 
1351  /* Bail if trying to unvoid the blank split. */
1352  if (split == blank_split)
1353  return;
1354 
1355  /* not voided. */
1356  if (xaccSplitGetReconcile (split) != VREC)
1357  return;
1358 
1359  info->trans_expanded = FALSE;
1360 
1361  gnc_suspend_gui_refresh ();
1362 
1363  trans = xaccSplitGetParent (split);
1364 
1365  xaccTransUnvoid (trans);
1366 
1367  /* Check pending transaction */
1368  if (trans == pending_trans)
1369  {
1370  info->pending_trans_guid = *guid_null ();
1371  pending_trans = NULL;
1372  }
1373 
1374  gnc_resume_gui_refresh ();
1375 }
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define VREC
split is void
Definition: Split.h:77
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.

◆ gnc_split_register_void_current_trans()

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

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

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

1282 {
1283  SRInfo* info = gnc_split_register_get_info (reg);
1284  Transaction* pending_trans;
1285  Transaction* trans;
1286  Split* blank_split;
1287  Split* split;
1288 
1289  if (!reg) return;
1290 
1291  blank_split = xaccSplitLookup (&info->blank_split_guid,
1292  gnc_get_current_book ());
1293  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1294  gnc_get_current_book ());
1295 
1296  /* get the current split based on cursor position */
1298  if (split == NULL)
1299  return;
1300 
1301  /* Bail if trying to void the blank split. */
1302  if (split == blank_split)
1303  return;
1304 
1305  /* already voided. */
1306  if (xaccSplitGetReconcile (split) == VREC)
1307  return;
1308 
1309  info->trans_expanded = FALSE;
1310 
1311  gnc_suspend_gui_refresh ();
1312 
1313  trans = xaccSplitGetParent (split);
1314  xaccTransVoid (trans, reason);
1315 
1316  /* Check pending transaction */
1317  if (trans == pending_trans)
1318  {
1319  info->pending_trans_guid = *guid_null ();
1320  pending_trans = NULL;
1321  }
1322  if (xaccTransIsOpen (trans))
1323  {
1324  PERR ("We should not be voiding an open transaction.");
1325  xaccTransCommitEdit (trans);
1326  }
1327  gnc_resume_gui_refresh ();
1328 }
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define VREC
split is void
Definition: Split.h:77
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.