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...
 
gboolean gnc_split_register_has_copied_item (void)
 Return TRUE if copied_item holds a transaction or split.
 
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 1487 of file split-register.c.

1488 {
1489  VirtualLocation virt_loc;
1490 
1491  if (reg == NULL)
1492  return;
1493 
1494  virt_loc = reg->table->current_cursor_loc;
1495 
1496  if (!gnc_table_current_cursor_changed (reg->table, FALSE))
1497  return;
1498 
1499  /* We're just cancelling the current split here, not the transaction.
1500  * When cancelling edits, reload the cursor from the transaction. */
1501  gnc_table_clear_current_cursor_changes (reg->table);
1502 
1503  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
1504  gnc_table_move_cursor_gui (reg->table, virt_loc);
1505 
1506  gnc_table_refresh_gui (reg->table, TRUE);
1507 }
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 1510 of file split-register.c.

1511 {
1512  SRInfo* info = gnc_split_register_get_info (reg);
1513  Transaction* pending_trans, *blank_trans;
1514  gboolean refresh_all = FALSE;
1515 
1516  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1517  gnc_get_current_book ());
1518 
1520 
1521  if (pending_trans == blank_trans)
1522  refresh_all = TRUE;
1523 
1524  /* Get the currently open transaction, rollback the edits on it, and
1525  * then repaint everything. To repaint everything, make a note of
1526  * all of the accounts that will be affected by this rollback. */
1527  if (!xaccTransIsOpen (pending_trans))
1528  {
1530  return;
1531  }
1532 
1533  if (!pending_trans)
1534  return;
1535 
1536  gnc_suspend_gui_refresh ();
1537 
1538  xaccTransRollbackEdit (pending_trans);
1539 
1540  info->pending_trans_guid = *guid_null ();
1541 
1542  gnc_resume_gui_refresh ();
1543 
1544  if (refresh_all)
1545  gnc_gui_refresh_all (); // force a refresh of all registers
1546  else
1548 }
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:165
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 1183 of file split-register.c.

1184 {
1185  SRInfo* info = gnc_split_register_get_info (reg);
1186  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1187  gnc_get_current_book ());
1188  Split* pref_split = NULL; // has the same account as incoming split
1189  Split* other_split = NULL; // other split
1190  Account* blank_split_account = xaccSplitGetAccount (current_blank_split);
1191  Transaction* trans = xaccSplitGetParent (split);
1192 
1193  // loop through splitlist looking for splits other than the blank_split
1194  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
1195  {
1196  Split *s = n->data;
1197  if (s != current_blank_split && xaccTransStillHasSplit (trans, s))
1198  {
1199  if (blank_split_account == xaccSplitGetAccount (s))
1200  pref_split = s; // prefer same account
1201  else
1202  other_split = s; // any other split
1203  }
1204  }
1205  // now change the saved blank split reference
1206  if (pref_split != NULL)
1207  info->blank_split_guid = *xaccSplitGetGUID (pref_split);
1208  else if (other_split != NULL)
1209  info->blank_split_guid = *xaccSplitGetGUID (other_split);
1210  else
1211  info->blank_split_guid = *guid_null();
1212 }
STRUCTS.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
#define xaccSplitGetGUID(X)
Definition: Split.h:552
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:165
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 2545 of file split-register.c.

2546 {
2547  SRInfo* info = gnc_split_register_get_info (reg);
2548  Transaction* pending_trans;
2549 
2550  ENTER ("reg=%p", reg);
2551 
2552  if (reg == NULL)
2553  {
2554  LEAVE ("no register");
2555  return FALSE;
2556  }
2557 
2558  if (gnc_table_current_cursor_changed (reg->table, FALSE))
2559  {
2560  LEAVE ("cursor changed");
2561  return TRUE;
2562  }
2563 
2564  pending_trans = xaccTransLookup (&info->pending_trans_guid,
2565  gnc_get_current_book ());
2566  if (xaccTransIsOpen (pending_trans))
2567  {
2568  LEAVE ("open and pending txn");
2569  return TRUE;
2570  }
2571 
2572  LEAVE ("register unchanged");
2573  return FALSE;
2574 }
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 2988 of file split-register.c.

2992 {
2993  if (!reg) return;
2994 
2995  /* If shrinking the transaction split, put the cursor on the first row of the trans */
2996  if (reg->use_double_line && !use_double_line)
2997  {
2998  VirtualLocation virt_loc = reg->table->current_cursor_loc;
2999  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
3000  {
3001  if (virt_loc.phys_row_offset)
3002  {
3003  gnc_table_move_vertical_position (reg->table, &virt_loc,
3004  -virt_loc.phys_row_offset);
3005  gnc_table_move_cursor_gui (reg->table, virt_loc);
3006  }
3007  }
3008  else
3009  {
3010  /* WTF? Go to a known safe location. */
3011  virt_loc.vcell_loc.virt_row = 1;
3012  virt_loc.vcell_loc.virt_col = 0;
3013  virt_loc.phys_row_offset = 0;
3014  virt_loc.phys_col_offset = 0;
3015  gnc_table_move_cursor_gui (reg->table, virt_loc);
3016  }
3017  }
3018 
3019  reg->type = newtype;
3020 
3021  if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
3022  newstyle = REG_STYLE_JOURNAL;
3023 
3024  reg->style = newstyle;
3025  reg->use_double_line = use_double_line;
3026 
3027  gnc_table_realize_gui (reg->table);
3028 }
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 1864 of file split-register-control.cpp.

1865 {
1866  TableControl *control = gnc_table_control_new ();
1867 
1868  control->move_cursor = gnc_split_register_move_cursor;
1869  control->traverse = gnc_split_register_traverse;
1870 
1871  return control;
1872 }

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

893 {
894  gnc_split_register_copy_current_internal (reg, FALSE);
895 }

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

304 {
305  SRInfo* info = gnc_split_register_get_info (reg);
306 
307  if (!reg)
308  return FALSE;
309 
310  if (reg->style == REG_STYLE_AUTO_LEDGER ||
311  reg->style == REG_STYLE_JOURNAL)
312  return TRUE;
313 
314  return info->trans_expanded;
315 }

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

899 {
900  SRInfo* info = gnc_split_register_get_info (reg);
901  CursorClass cursor_class;
902  Transaction* trans;
903  Split* blank_split;
904  gboolean changed;
905  Split* split;
906 
907  blank_split = xaccSplitLookup (&info->blank_split_guid,
908  gnc_get_current_book ());
911 
912  /* This shouldn't happen, but be paranoid. */
913  if (trans == NULL)
914  return;
915 
916  cursor_class = gnc_split_register_get_current_cursor_class (reg);
917 
918  /* Can't do anything with this. */
919  if (cursor_class == CURSOR_CLASS_NONE)
920  return;
921 
922  /* This shouldn't happen, but be paranoid. */
923  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
924  return;
925 
926  changed = gnc_table_current_cursor_changed (reg->table, FALSE);
927 
928  /* See if we were asked to cut an unchanged blank split. Don't. */
929  if (!changed && ((split == NULL) || (split == blank_split)))
930  return;
931 
932  gnc_split_register_copy_current_internal (reg, TRUE);
933 
934  if (cursor_class == CURSOR_CLASS_SPLIT)
936  else
938 }
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 1215 of file split-register.c.

1216 {
1217  SRInfo* info = gnc_split_register_get_info (reg);
1218  Transaction* pending_trans;
1219  Transaction* trans;
1220  Split* blank_split;
1221  Split* split;
1222 
1223  if (!reg) return;
1224 
1225  blank_split = xaccSplitLookup (&info->blank_split_guid,
1226  gnc_get_current_book ());
1227 
1228  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1229  gnc_get_current_book ());
1230 
1231  /* get the current split based on cursor position */
1233  if (split == NULL)
1234  return;
1235 
1236  /* If we are deleting the blank split, just cancel. The user is
1237  * allowed to delete the blank split as a method for discarding
1238  * any edits they may have made to it. */
1239  if (split == blank_split)
1240  {
1242  return;
1243  }
1244 
1245  gnc_suspend_gui_refresh ();
1246 
1247  trans = xaccSplitGetParent (split);
1248 
1249  /* Check pending transaction */
1250  if (trans == pending_trans)
1251  {
1252  g_assert (xaccTransIsOpen (trans));
1253  }
1254  else
1255  {
1256  g_assert (!pending_trans);
1257  if (gnc_split_register_begin_edit_or_warn (info, trans))
1258  {
1259  gnc_resume_gui_refresh ();
1260  return;
1261  }
1262  }
1263  xaccSplitDestroy (split);
1264 
1265  gnc_resume_gui_refresh ();
1267 }
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:1470
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 1270 of file split-register.c.

1271 {
1272  SRInfo* info = gnc_split_register_get_info (reg);
1273  Transaction* pending_trans;
1274  Transaction* trans;
1275  Split* blank_split;
1276  Split* split;
1277  gboolean was_open;
1278 
1279  ENTER ("reg=%p", reg);
1280  if (!reg)
1281  {
1282  LEAVE ("no register");
1283  return;
1284  }
1285 
1286  blank_split = xaccSplitLookup (&info->blank_split_guid,
1287  gnc_get_current_book ());
1288  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1289  gnc_get_current_book ());
1290 
1291  /* get the current split based on cursor position */
1293  if (split == NULL)
1294  {
1295  LEAVE ("no split");
1296  return;
1297  }
1298 
1299  gnc_suspend_gui_refresh ();
1300  trans = xaccSplitGetParent (split);
1301 
1302  /* If we just deleted the blank split, clean up. The user is
1303  * allowed to delete the blank split as a method for discarding
1304  * any edits they may have made to it. */
1305  if (split == blank_split)
1306  {
1307  DEBUG ("deleting blank split");
1308  info->blank_split_guid = *guid_null ();
1309  info->auto_complete = FALSE;
1310  }
1311  else
1312  {
1313  info->trans_expanded = FALSE;
1314  }
1315 
1316  /* Check pending transaction */
1317  if (trans == pending_trans)
1318  {
1319  DEBUG ("clearing pending trans");
1320  info->pending_trans_guid = *guid_null ();
1321  pending_trans = NULL;
1322  }
1323 
1324  was_open = xaccTransIsOpen (trans);
1325  xaccTransDestroy (trans);
1326  if (was_open)
1327  {
1328  DEBUG ("committing");
1329  xaccTransCommitEdit (trans);
1330  }
1331  gnc_resume_gui_refresh ();
1333  LEAVE (" ");
1334 }
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:165
#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 3160 of file split-register.c.

3161 {
3162  g_return_if_fail (reg);
3163 
3164  ENTER ("reg=%p", reg);
3165 
3166  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3167  GNC_PREF_ACCOUNTING_LABELS,
3168  split_register_pref_changed,
3169  reg);
3170  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL,
3171  GNC_PREF_ACCOUNT_SEPARATOR,
3172  split_register_pref_changed,
3173  reg);
3174  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3175  GNC_PREF_SHOW_LEAF_ACCT_NAMES,
3176  split_register_pref_changed,
3177  reg);
3178  gnc_prefs_remove_cb_by_func (GNC_PREFS_GROUP_GENERAL_REGISTER,
3179  GNC_PREF_ALT_COLOR_BY_TRANS,
3180  split_register_pref_changed,
3181  reg);
3182  gnc_book_option_remove_cb (OPTION_NAME_NUM_FIELD_SOURCE,
3183  split_register_book_option_changed,
3184  reg);
3185 
3186  gnc_split_register_cleanup (reg);
3187 
3188  gnc_table_destroy (reg->table);
3189  reg->table = NULL;
3190 
3191  /* free the memory itself */
3192  g_free (reg);
3193  LEAVE (" ");
3194 }
#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.cpp:142

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

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

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

1436 {
1437  SRInfo* info;
1438  Transaction* trans;
1439  Transaction* pending;
1440  int i = 0;
1441  Split* s;
1442 
1443  if ((reg == NULL) || (split == NULL))
1444  return;
1445 
1446  gnc_suspend_gui_refresh ();
1447  info = gnc_split_register_get_info (reg);
1448  pending = xaccTransLookup (&info->pending_trans_guid, gnc_get_current_book ());
1449 
1450  trans = xaccSplitGetParent (split);
1451  if (!pending)
1452  {
1453  if (gnc_split_register_begin_edit_or_warn (info, trans))
1454  {
1455  gnc_resume_gui_refresh ();
1456  return;
1457  }
1458  }
1459  else if (pending == trans)
1460  {
1461  g_assert (xaccTransIsOpen (trans));
1462  }
1463  else g_assert_not_reached ();
1464 
1465  while ((s = xaccTransGetSplit (trans, i)) != NULL)
1466  {
1467  if (s != split)
1468  xaccSplitDestroy (s);
1469  else i++;
1470  }
1471 
1472  gnc_resume_gui_refresh ();
1474 }
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:1470
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 243 of file split-register.c.

244 {
245  SRInfo* info = gnc_split_register_get_info (reg);
246  VirtualLocation virt_loc;
247 
248  if (!reg)
249  return;
250 
251  if (reg->style == REG_STYLE_AUTO_LEDGER ||
252  reg->style == REG_STYLE_JOURNAL)
253  return;
254 
255  /* ok, so I just wanted an excuse to use exclusive-or */
256  if (! (expand ^ info->trans_expanded))
257  return;
258 
259  if (!expand)
260  {
261  virt_loc = reg->table->current_cursor_loc;
262  gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
263  &virt_loc.vcell_loc);
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  info->trans_expanded = expand;
275 
276  gnc_table_set_virt_cell_cursor (reg->table,
277  reg->table->current_cursor_loc.vcell_loc,
278  gnc_split_register_get_active_cursor (reg));
279 
281  reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
282 
283  virt_loc = reg->table->current_cursor_loc;
284  if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
285  {
286  if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
287  gnc_table_move_cursor_gui (reg->table, virt_loc);
288  else
289  {
290  PERR ("Can't find place to go!");
291  return;
292  }
293  }
294 
295  gnc_table_refresh_gui (reg->table, TRUE);
296 
297  if (expand)
298  gnc_split_register_show_trans (reg,
299  reg->table->current_cursor_loc.vcell_loc);
300 }
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 352 of file split-register.c.

353 {
354  SRInfo* info = gnc_split_register_get_info (reg);
355 
356  if (!reg) return NULL;
357 
358  return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
359 }
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 2522 of file split-register.c.

2523 {
2524  SRInfo* info = gnc_split_register_get_info (reg);
2525 
2526  if (!reg)
2527  return NULL;
2528 
2529  if (info->credit_str)
2530  return info->credit_str;
2531 
2532  info->credit_str =
2534  (gnc_split_register_type_to_account_type (reg->type));
2535 
2536  if (info->credit_str)
2537  return info->credit_str;
2538 
2539  info->credit_str = g_strdup (_ ("Credit"));
2540 
2541  return info->credit_str;
2542 }
const char * gnc_account_get_credit_string(GNCAccountType acct_type)
Get the credit string associated with this account type.
Definition: Account.cpp:4062

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

343 {
344  if (reg == NULL)
345  return NULL;
346 
347  return gnc_split_register_get_split (
348  reg, reg->table->current_cursor_loc.vcell_loc);
349 }

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

319 {
320  Split* split;
321  VirtualCellLocation vcell_loc;
322 
323  if (reg == NULL)
324  return NULL;
325 
327  if (split != NULL)
328  return xaccSplitGetParent (split);
329 
330  /* Split is blank. Assume it is the blank split of a multi-line
331  * transaction. Go back one row to find a split in the transaction. */
332  vcell_loc = reg->table->current_cursor_loc.vcell_loc;
333 
334  vcell_loc.virt_row--;
335 
336  split = gnc_split_register_get_split (reg, vcell_loc);
337 
338  return xaccSplitGetParent (split);
339 }
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 2499 of file split-register.c.

2500 {
2501  SRInfo* info = gnc_split_register_get_info (reg);
2502 
2503  if (!reg)
2504  return NULL;
2505 
2506  if (info->debit_str)
2507  return info->debit_str;
2508 
2509  info->debit_str =
2511  (gnc_split_register_type_to_account_type (reg->type));
2512 
2513  if (info->debit_str)
2514  return info->debit_str;
2515 
2516  info->debit_str = g_strdup (_ ("Debit"));
2517 
2518  return info->debit_str;
2519 }
const char * gnc_account_get_debit_string(GNCAccountType acct_type)
Get the debit string associated with this account type.
Definition: Account.cpp:4050

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

3204 {
3205  switch (reg->type)
3206  {
3207  case BANK_REGISTER:
3208  case CASH_REGISTER:
3209  case ASSET_REGISTER:
3210  case CREDIT_REGISTER:
3211  case LIABILITY_REGISTER:
3212  case INCOME_REGISTER:
3213  case EXPENSE_REGISTER:
3214  case EQUITY_REGISTER:
3215  case TRADING_REGISTER:
3216  {
3217  return REG_TYPE_GROUP_CURRENCY;
3218  break;
3219  }
3220  case PAYABLE_REGISTER:
3221  case RECEIVABLE_REGISTER:
3222  {
3223  return REG_TYPE_GROUP_APAR;
3224  break;
3225  }
3226  case INCOME_LEDGER:
3227  case GENERAL_JOURNAL:
3228  case SEARCH_LEDGER:
3229  {
3230  return REG_TYPE_GROUP_JOURNAL;
3231  break;
3232  }
3233  case STOCK_REGISTER:
3234  case CURRENCY_REGISTER:
3235  {
3236  return REG_TYPE_GROUP_STOCK;
3237  break;
3238  }
3239  case PORTFOLIO_LEDGER:
3240  {
3241  return REG_TYPE_GROUP_PORTFOLIO;
3242  break;
3243  }
3244  default:
3245  return REG_TYPE_GROUP_UNKNOWN;
3246  PERR ("unknown register type %d\n", reg->type);
3247  break;
3248  }
3249 }
#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 402 of file split-register.c.

404 {
405  VirtualLocation v_loc;
406  CursorClass cursor_class;
407  const char* cell_name;
408  gnc_numeric value;
409 
410  if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
411  return FALSE;
412 
413  cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
414 
415  value = xaccSplitGetValue (split);
416 
417  switch (cursor_class)
418  {
419  case CURSOR_CLASS_SPLIT:
420  case CURSOR_CLASS_TRANS:
421  cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
422  break;
423  default:
424  return FALSE;
425  }
426 
427  if (!gnc_table_get_cell_location (reg->table, cell_name,
428  v_loc.vcell_loc, &v_loc))
429  return FALSE;
430 
431  if (virt_loc == NULL)
432  return TRUE;
433 
434  *virt_loc = v_loc;
435 
436  return TRUE;
437 }
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 362 of file split-register.c.

364 {
365  Table* table;
366  int v_row;
367  int v_col;
368 
369  if (!reg || !split) return FALSE;
370 
371  table = reg->table;
372 
373  /* go backwards because typically you search for splits at the end
374  * and because we find split rows before transaction rows. */
375 
376  for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
377  for (v_col = 0; v_col < table->num_virt_cols; v_col++)
378  {
379  VirtualCellLocation vc_loc = { v_row, v_col };
380  VirtualCell* vcell;
381  Split* s;
382 
383  vcell = gnc_table_get_virtual_cell (table, vc_loc);
384  if (!vcell || !vcell->visible)
385  continue;
386 
387  s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
388 
389  if (s == split)
390  {
391  if (vcell_loc)
392  *vcell_loc = vc_loc;
393 
394  return TRUE;
395  }
396  }
397 
398  return FALSE;
399 }
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 1332 of file split-register-control.cpp.

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

1171 {
1172  SRInfo* info = gnc_split_register_get_info (reg);
1173  Split* current_blank_split = xaccSplitLookup (&info->blank_split_guid,
1174  gnc_get_current_book ());
1175 
1176  if (split == current_blank_split)
1177  return TRUE;
1178 
1179  return FALSE;
1180 }
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071

◆ gnc_split_register_layout_new()

TableLayout* gnc_split_register_layout_new ( SplitRegister *  reg)

Generate the split register layout.

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

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

◆ gnc_split_register_load()

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

Populates the rows of a register.

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

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

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

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

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

2967 {
2968  SplitRegister* reg;
2969  gboolean default_do_auto_complete = TRUE;
2970 
2971  reg = g_new0 (SplitRegister, 1);
2972 
2973  if (type >= NUM_SINGLE_REGISTER_TYPES)
2974  style = REG_STYLE_JOURNAL;
2975 
2976  gnc_split_register_init (reg,
2977  type,
2978  style,
2979  use_double_line,
2980  default_do_auto_complete,
2981  is_template,
2982  mismatched_commodities);
2983 
2984  return reg;
2985 }

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

942 {
943  SRInfo* info = gnc_split_register_get_info (reg);
944  CursorClass cursor_class;
945  Transaction* trans;
946  Transaction* blank_trans;
947  Split* blank_split;
948  Split* trans_split;
949  Split* split;
950  Account *template_account = NULL;
951 
952  ENTER ("reg=%p", reg);
953 
954  if (copied_item.cursor_class == CURSOR_CLASS_NONE)
955  {
956  LEAVE ("no copied cursor class");
957  return;
958  }
959 
960  blank_split = xaccSplitLookup (&info->blank_split_guid,
961  gnc_get_current_book ());
962  blank_trans = xaccSplitGetParent (blank_split);
965 
966  trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
967 
968  template_account = xaccAccountLookup (&info->template_account,
969  gnc_get_current_book ());
970 
971  /* This shouldn't happen, but be paranoid. */
972  if (trans == NULL)
973  {
974  LEAVE ("no transaction");
975  return;
976  }
977 
978  cursor_class = gnc_split_register_get_current_cursor_class (reg);
979 
980  /* Can't do anything with this. */
981  if (cursor_class == CURSOR_CLASS_NONE)
982  {
983  LEAVE ("no current cursor class");
984  return;
985  }
986 
987  /* This shouldn't happen, but be paranoid. */
988  if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
989  {
990  g_warning ("BUG DETECTED: transaction cursor with no anchoring split!");
991  LEAVE ("transaction cursor with no anchoring split");
992  return;
993  }
994 
995  if (cursor_class == CURSOR_CLASS_SPLIT)
996  {
997  const char* message = _ ("You are about to overwrite an existing split. "
998  "Are you sure you want to do that?");
999  const char* anchor_message = _ ("This is the split anchoring this transaction "
1000  "to the register. You may not overwrite it from "
1001  "this register window. You may overwrite it if "
1002  "you navigate to a register that shows another "
1003  "side of this same transaction.");
1004 
1005  if (copied_item.cursor_class == CURSOR_CLASS_TRANS)
1006  {
1007  /* An entire transaction was copied, but we're just on a split. */
1008  LEAVE ("can't copy trans to split");
1009  return;
1010  }
1011 
1012  if (split != NULL)
1013  {
1014  /* the General Journal does not have any anchoring splits */
1015  if ((reg->type != GENERAL_JOURNAL) &&
1016  split == gnc_split_register_get_current_trans_split (reg, NULL))
1017  {
1018  gnc_warning_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
1019  "%s", anchor_message);
1020  LEAVE ("anchore split");
1021  return;
1022  }
1023  else if (!gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
1024  FALSE, "%s", message))
1025  {
1026  LEAVE ("user cancelled");
1027  return;
1028  }
1029  }
1030 
1031  /* Open the transaction for editing. */
1032  if (gnc_split_register_begin_edit_or_warn (info, trans))
1033  {
1034  LEAVE ("can't begin editing");
1035  return;
1036  }
1037 
1038  gnc_suspend_gui_refresh ();
1039 
1040  if (split == NULL)
1041  {
1042  /* We are on a null split in an expanded transaction. */
1043  split = xaccMallocSplit (gnc_get_current_book ());
1044  xaccSplitSetParent (split, trans);
1045  }
1046 
1047  if (copied_item.ftype != GNC_TYPE_SPLIT)
1048  {
1049  LEAVE ("copy buffer doesn't represent a split");
1050  return;
1051  }
1052  gnc_float_split_to_split (copied_item.fs, split, template_account);
1053  }
1054  else
1055  {
1056  const char *message = _("You are about to overwrite an existing "
1057  "transaction. "
1058  "Are you sure you want to do that?");
1059  Account * copied_leader;
1060  Account * default_account;
1061  int trans_split_index;
1062  int split_index;
1063  int num_splits;
1064 
1065  if (copied_item.cursor_class == CURSOR_CLASS_SPLIT)
1066  {
1067  LEAVE ("can't copy split to transaction");
1068  return;
1069  }
1070 
1071  if (copied_item.ftype != GNC_TYPE_TRANSACTION)
1072  {
1073  LEAVE ("copy buffer doesn't represent a transaction");
1074  return;
1075  }
1076 
1077  if ((reg->type != SEARCH_LEDGER) && (reg->type != GENERAL_JOURNAL))
1078  {
1079  if (gnc_float_txn_has_template (copied_item.ft))
1080  {
1081  const gchar *msg_text = _("Scheduled transactions can only be pasted to the General Journal");
1082 
1083  gnc_warning_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)), "%s", msg_text);
1084 
1085  LEAVE ("Paste only allowed to General Journal from scheduled transactions");
1086  return;
1087  }
1088  }
1089 
1090  /* Ask before overwriting an existing transaction. */
1091  if (split != blank_split &&
1092  !gnc_verify_dialog (GTK_WINDOW (gnc_split_register_get_parent (reg)),
1093  FALSE, "%s", message))
1094  {
1095  LEAVE ("user cancelled");
1096  return;
1097  }
1098 
1099  /* Open the transaction for editing. */
1100  if (gnc_split_register_begin_edit_or_warn (info, trans))
1101  {
1102  LEAVE ("can't begin editing");
1103  return;
1104  }
1105 
1106  gnc_suspend_gui_refresh ();
1107 
1108  DEBUG ("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
1109  trans, split, blank_trans, blank_split);
1110 
1111  split_index = xaccTransGetSplitIndex (trans, split);
1112  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
1113 
1114  copied_leader = xaccAccountLookup (&copied_item.leader_guid,
1115  gnc_get_current_book ());
1116  default_account = gnc_split_register_get_default_account (reg);
1117 
1118  if (copied_leader && default_account)
1119  {
1120  gnc_float_txn_to_txn_swap_accounts (copied_item.ft, trans,
1121  copied_leader,
1122  default_account,
1123  FALSE);
1124  }
1125  else
1126  {
1127  if (reg->is_template)
1128  {
1129  gnc_float_txn_to_template_txn (copied_item.ft, trans,
1130  template_account, FALSE);
1131  }
1132  else
1133  gnc_float_txn_to_txn (copied_item.ft, trans, FALSE);
1134  }
1135  num_splits = xaccTransCountSplits (trans);
1136  if (split_index >= num_splits)
1137  split_index = 0;
1138 
1139  if (trans == blank_trans)
1140  {
1141  /* In pasting, the blank split is deleted. Pick a new one. */
1142  gint anchor_split_index = copied_item.anchor_split_index;
1143  if (anchor_split_index > num_splits)
1144  anchor_split_index = 0;
1145 
1146  blank_split = xaccTransGetSplit (trans, anchor_split_index);
1147  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
1148  info->blank_split_edited = TRUE;
1149  info->auto_complete = FALSE;
1150  DEBUG ("replacement blank_split=%p", blank_split);
1151 
1152  /* NOTE: At this point, the blank transaction virtual cell is still
1153  * anchored by the old, deleted blank split. The register will
1154  * have to be reloaded (redrawn) to correct this. */
1155  }
1156 
1157  info->cursor_hint_trans = trans;
1158  info->cursor_hint_split = xaccTransGetSplit (trans, split_index);
1159  info->cursor_hint_trans_split = xaccTransGetSplit (trans,
1160  trans_split_index);
1161  info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
1162  }
1163 
1164  /* Refresh the GUI. */
1165  gnc_resume_gui_refresh ();
1166  LEAVE (" ");
1167 }
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:2048

◆ gnc_split_register_redraw()

void gnc_split_register_redraw ( SplitRegister *  reg)

Causes a redraw of the register window associated with reg.

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

1552 {
1553  gnc_ledger_display_refresh_by_split_register (reg);
1554 }

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

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

3040 {
3041  g_return_if_fail (reg);
3042  reg->do_auto_complete = do_auto_complete;
3043 }

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

3198 {
3199  gnc_table_model_set_read_only (reg->table->model, read_only);
3200 }

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

3032 {
3033  g_return_if_fail (reg);
3034  gnc_table_model_set_reverse_sort (reg->table->model, reverse_sort);
3035 }

◆ gnc_split_register_set_template_account()

void gnc_split_register_set_template_account ( SplitRegister *  reg,
Account template_account 
)

Set the template account for use in a template register.

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

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

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

◆ gnc_split_register_set_trans_visible()

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

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

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

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

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

◆ gnc_split_register_show_present_divider()

void gnc_split_register_show_present_divider ( SplitRegister *  reg,
gboolean  show_present 
)

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

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

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

2579 {
2580  SRInfo* info = gnc_split_register_get_info (reg);
2581 
2582  if (reg == NULL)
2583  return;
2584 
2585  info->show_present_divider = show_present;
2586 }

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

1388 {
1389  SRInfo* info = gnc_split_register_get_info (reg);
1390  Transaction* pending_trans;
1391  Transaction* trans;
1392  Split* blank_split;
1393  Split* split;
1394 
1395  if (!reg) return;
1396 
1397  blank_split = xaccSplitLookup (&info->blank_split_guid,
1398  gnc_get_current_book ());
1399  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1400  gnc_get_current_book ());
1401 
1402  /* get the current split based on cursor position */
1404  if (split == NULL)
1405  return;
1406 
1407  /* Bail if trying to unvoid the blank split. */
1408  if (split == blank_split)
1409  return;
1410 
1411  /* not voided. */
1412  if (xaccSplitGetReconcile (split) != VREC)
1413  return;
1414 
1415  info->trans_expanded = FALSE;
1416 
1417  gnc_suspend_gui_refresh ();
1418 
1419  trans = xaccSplitGetParent (split);
1420 
1421  xaccTransUnvoid (trans);
1422 
1423  /* Check pending transaction */
1424  if (trans == pending_trans)
1425  {
1426  info->pending_trans_guid = *guid_null ();
1427  pending_trans = NULL;
1428  }
1429 
1430  gnc_resume_gui_refresh ();
1431 }
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:165
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 1337 of file split-register.c.

1338 {
1339  SRInfo* info = gnc_split_register_get_info (reg);
1340  Transaction* pending_trans;
1341  Transaction* trans;
1342  Split* blank_split;
1343  Split* split;
1344 
1345  if (!reg) return;
1346 
1347  blank_split = xaccSplitLookup (&info->blank_split_guid,
1348  gnc_get_current_book ());
1349  pending_trans = xaccTransLookup (&info->pending_trans_guid,
1350  gnc_get_current_book ());
1351 
1352  /* get the current split based on cursor position */
1354  if (split == NULL)
1355  return;
1356 
1357  /* Bail if trying to void the blank split. */
1358  if (split == blank_split)
1359  return;
1360 
1361  /* already voided. */
1362  if (xaccSplitGetReconcile (split) == VREC)
1363  return;
1364 
1365  info->trans_expanded = FALSE;
1366 
1367  gnc_suspend_gui_refresh ();
1368 
1369  trans = xaccSplitGetParent (split);
1370  xaccTransVoid (trans, reason);
1371 
1372  /* Check pending transaction */
1373  if (trans == pending_trans)
1374  {
1375  info->pending_trans_guid = *guid_null ();
1376  pending_trans = NULL;
1377  }
1378  if (xaccTransIsOpen (trans))
1379  {
1380  PERR ("We should not be voiding an open transaction.");
1381  xaccTransCommitEdit (trans);
1382  }
1383  gnc_resume_gui_refresh ();
1384 }
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:165
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.