|
GnuCash 2.3.0
|
Data Structures | |
| struct | split_register_colors |
| struct | split_register |
| The type, style and table for the register. More... | |
Modules | |
| Split Register | |
GnuCash-specific ledger and journal displays based on Register Core. | |
| Register Core | |
An infrastructure for building a modular matrix of cells like a spreadsheet or checkbook register. | |
Files | |
| file | split-register.h |
API for checkbook register display area. | |
Typedefs | |
|
typedef struct split_register_colors | SplitRegisterColors |
| typedef struct split_register | SplitRegister |
| A split register created with gnc_split_register_new. | |
| typedef struct sr_info | SRInfo |
| typedef GtkWidget *(* | SRGetParentCallback )(gpointer user_data) |
Enumerations | |
| enum | CursorClass { CURSOR_CLASS_NONE = -1, CURSOR_CLASS_SPLIT, CURSOR_CLASS_TRANS, NUM_CURSOR_CLASSES } |
Functions | |
| SplitRegister * | gnc_split_register_new (SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line, gboolean is_template) |
| void | gnc_split_register_destroy (SplitRegister *reg) |
| void | gnc_split_register_config (SplitRegister *reg, SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line) |
| void | gnc_split_register_set_auto_complete (SplitRegister *reg, gboolean do_auto_complete) |
| void | gnc_split_register_set_read_only (SplitRegister *reg, gboolean read_only) |
| void | gnc_split_register_set_template_account (SplitRegister *reg, Account *template_account) |
| void | gnc_split_register_set_data (SplitRegister *reg, gpointer user_data, SRGetParentCallback get_parent) |
| CursorClass | gnc_split_register_get_current_cursor_class (SplitRegister *reg) |
| CursorClass | gnc_split_register_get_cursor_class (SplitRegister *reg, VirtualCellLocation vcell_loc) |
| Transaction * | gnc_split_register_get_current_trans (SplitRegister *reg) |
| Split * | gnc_split_register_get_current_trans_split (SplitRegister *reg, VirtualCellLocation *vcell_loc) |
| Split * | gnc_split_register_get_current_split (SplitRegister *reg) |
| Split * | gnc_split_register_get_blank_split (SplitRegister *reg) |
| gboolean | gnc_split_register_get_split_virt_loc (SplitRegister *reg, Split *split, VirtualCellLocation *vcell_loc) |
| gboolean | gnc_split_register_get_split_amount_virt_loc (SplitRegister *reg, Split *split, VirtualLocation *virt_loc) |
| Split * | gnc_split_register_duplicate_current (SplitRegister *reg) |
| void | gnc_split_register_copy_current (SplitRegister *reg) |
| void | gnc_split_register_cut_current (SplitRegister *reg) |
| void | gnc_split_register_paste_current (SplitRegister *reg) |
| void | gnc_split_register_delete_current_split (SplitRegister *reg) |
| void | gnc_split_register_delete_current_trans (SplitRegister *reg) |
| void | gnc_split_register_void_current_trans (SplitRegister *reg, const char *reason) |
| void | gnc_split_register_unvoid_current_trans (SplitRegister *reg) |
| void | gnc_split_register_empty_current_trans_except_split (SplitRegister *reg, Split *split) |
| void | gnc_split_register_empty_current_trans (SplitRegister *reg) |
| void | gnc_split_register_cancel_cursor_split_changes (SplitRegister *reg) |
| void | gnc_split_register_cancel_cursor_trans_changes (SplitRegister *reg) |
| void | gnc_split_register_load (SplitRegister *reg, GList *slist, Account *default_account) |
| gboolean | gnc_split_register_save (SplitRegister *reg, gboolean do_commit) |
| void | gnc_split_register_redraw (SplitRegister *reg) |
| gboolean | gnc_split_register_changed (SplitRegister *reg) |
| void | gnc_split_register_show_present_divider (SplitRegister *reg, gboolean show_present) |
| void | gnc_split_register_expand_current_trans (SplitRegister *reg, gboolean expand) |
| void | gnc_split_register_collapse_current_trans (SplitRegister *reg) |
| gboolean | gnc_split_register_current_trans_expanded (SplitRegister *reg) |
| const char * | gnc_split_register_get_debit_string (SplitRegister *reg) |
| const char * | gnc_split_register_get_credit_string (SplitRegister *reg) |
| gboolean | gnc_split_register_handle_exchange (SplitRegister *reg, gboolean force_dialog) |
| gboolean | gnc_split_register_begin_edit_or_warn (SRInfo *info, Transaction *trans) |
| 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_LEDGER = NUM_SINGLE_REGISTER_TYPES, INCOME_LEDGER, PORTFOLIO_LEDGER, SEARCH_LEDGER, NUM_REGISTER_TYPES } |
| Register types. More... | |
| enum | SplitRegisterStyle { REG_STYLE_LEDGER, REG_STYLE_AUTO_LEDGER, REG_STYLE_JOURNAL } |
Cell Names | |
| #define | ACTN_CELL "action" |
| #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 | 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 | |
| #define | CURSOR_SINGLE_LEDGER "cursor-single-ledger" |
| #define | CURSOR_DOUBLE_LEDGER "cursor-double-ledger" |
| #define | CURSOR_SINGLE_JOURNAL "cursor-single-journal" |
| #define | CURSOR_DOUBLE_JOURNAL "cursor-double-journal" |
| #define | CURSOR_SPLIT "cursor-split" |
| typedef GtkWidget*(* SRGetParentCallback)(gpointer user_data) |
Callback function type
Definition at line 271 of file split-register.h.
| enum CursorClass |
Types of cursors
Definition at line 228 of file split-register.h.
{
CURSOR_CLASS_NONE = -1,
CURSOR_CLASS_SPLIT,
CURSOR_CLASS_TRANS,
NUM_CURSOR_CLASSES
} CursorClass;
| enum SplitRegisterStyle |
Register styles
Definition at line 178 of file split-register.h.
{
REG_STYLE_LEDGER,
REG_STYLE_AUTO_LEDGER,
REG_STYLE_JOURNAL
} SplitRegisterStyle;
| enum SplitRegisterType |
Register types.
"registers" are single-account display windows. "ledgers" are multiple-account display windows
Definition at line 152 of file split-register.h.
{
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_LEDGER = NUM_SINGLE_REGISTER_TYPES,
INCOME_LEDGER,
PORTFOLIO_LEDGER,
SEARCH_LEDGER,
NUM_REGISTER_TYPES
} SplitRegisterType;
| 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 1192 of file split-register.c.
{
VirtualLocation virt_loc;
if (reg == NULL)
return;
virt_loc = reg->table->current_cursor_loc;
if (!gnc_table_current_cursor_changed (reg->table, FALSE))
return;
/* We're just cancelling the current split here, not the transaction.
* When cancelling edits, reload the cursor from the transaction. */
gnc_table_clear_current_cursor_changes (reg->table);
if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
gnc_table_move_cursor_gui (reg->table, virt_loc);
gnc_table_refresh_gui (reg->table, TRUE);
}
| 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 1215 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* Get the currently open transaction, rollback the edits on it, and
* then repaint everything. To repaint everything, make a note of
* all of the accounts that will be affected by this rollback. */
if (!xaccTransIsOpen (pending_trans))
{
gnc_split_register_cancel_cursor_split_changes (reg);
return;
}
if (!pending_trans)
return;
gnc_suspend_gui_refresh ();
xaccTransRollbackEdit (pending_trans);
info->pending_trans_guid = *guid_null ();
gnc_resume_gui_refresh ();
gnc_split_register_redraw(reg);
}
| gboolean gnc_split_register_changed | ( | SplitRegister * | reg | ) |
Returns TRUE if the register has changed cells.
Definition at line 2157 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
ENTER("reg=%p", reg);
if (reg == NULL)
{
LEAVE("no register");
return FALSE;
}
if (gnc_table_current_cursor_changed (reg->table, FALSE))
{
LEAVE("cursor changed");
return TRUE;
}
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
if (xaccTransIsOpen (pending_trans))
{
LEAVE("open and pending txn");
return TRUE;
}
LEAVE("register unchanged");
return FALSE;
}
| void gnc_split_register_collapse_current_trans | ( | SplitRegister * | reg | ) |
Mark the current transaction as collapsed, and do callbacks.
| 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.
| reg | a SplitRegister |
| type | a SplitRegisterType to use for the register |
| style | a SplitRegisterStyle to use for the register |
| use_double_line | TRUE to show two lines for transactions, FALSE for one |
Definition at line 2545 of file split-register.c.
{
if (!reg) return;
/* If shrinking the transaction split, put the cursor on the first row of the trans */
if (reg->use_double_line && !use_double_line)
{
VirtualLocation virt_loc = reg->table->current_cursor_loc;
if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
{
if (virt_loc.phys_row_offset)
{
gnc_table_move_vertical_position (reg->table, &virt_loc, -virt_loc.phys_row_offset);
gnc_table_move_cursor_gui (reg->table, virt_loc);
}
}
else
{
/* WTF? Go to a known safe location. */
virt_loc.vcell_loc.virt_row = 1;
virt_loc.vcell_loc.virt_col = 0;
virt_loc.phys_row_offset = 0;
virt_loc.phys_col_offset = 0;
gnc_table_move_cursor_gui (reg->table, virt_loc);
}
}
reg->type = newtype;
if (reg->type >= NUM_SINGLE_REGISTER_TYPES)
newstyle = REG_STYLE_JOURNAL;
reg->style = newstyle;
reg->use_double_line = use_double_line;
gnc_table_realize_gui (reg->table);
}
| 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 705 of file split-register.c.
{
gnc_split_register_copy_current_internal (reg, FALSE);
}
| 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 249 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
if (!reg)
return FALSE;
if (reg->style == REG_STYLE_AUTO_LEDGER ||
reg->style == REG_STYLE_JOURNAL)
return TRUE;
return info->trans_expanded;
}
| void gnc_split_register_cut_current | ( | SplitRegister * | reg | ) |
Equivalent to copying the current entity and the deleting it with the approriate delete method.
Definition at line 711 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
CursorClass cursor_class;
Transaction *trans;
Split *blank_split;
gboolean changed;
Split *split;
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
split = gnc_split_register_get_current_split (reg);
trans = gnc_split_register_get_current_trans (reg);
/* This shouldn't happen, but be paranoid. */
if (trans == NULL)
return;
cursor_class = gnc_split_register_get_current_cursor_class (reg);
/* Can't do anything with this. */
if (cursor_class == CURSOR_CLASS_NONE)
return;
/* This shouldn't happen, but be paranoid. */
if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
return;
changed = gnc_table_current_cursor_changed (reg->table, FALSE);
/* See if we were asked to cut an unchanged blank split. Don't. */
if (!changed && ((split == NULL) || (split == blank_split)))
return;
gnc_split_register_copy_current_internal (reg, TRUE);
if (cursor_class == CURSOR_CLASS_SPLIT)
gnc_split_register_delete_current_split (reg);
else
gnc_split_register_delete_current_trans (reg);
}
| 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 922 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
Transaction *trans;
Split *blank_split;
Split *split;
if (!reg) return;
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* get the current split based on cursor position */
split = gnc_split_register_get_current_split (reg);
if (split == NULL)
return;
/* If we are deleting the blank split, just cancel. The user is
* allowed to delete the blank split as a method for discarding
* any edits they may have made to it. */
if (split == blank_split)
{
gnc_split_register_cancel_cursor_split_changes (reg);
return;
}
gnc_suspend_gui_refresh ();
trans = xaccSplitGetParent(split);
/* Check pending transaction */
if (trans == pending_trans)
{
g_assert(xaccTransIsOpen(trans));
}
else
{
g_assert(!pending_trans);
if (gnc_split_register_begin_edit_or_warn(info, trans))
{
gnc_resume_gui_refresh ();
return;
}
}
xaccSplitDestroy (split);
gnc_resume_gui_refresh ();
gnc_split_register_redraw(reg);
}
| 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 977 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
Transaction *trans;
Split *blank_split;
Split *split;
gboolean was_open;
ENTER("reg=%p", reg);
if (!reg)
{
LEAVE("no register");
return;
}
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* get the current split based on cursor position */
split = gnc_split_register_get_current_split (reg);
if (split == NULL)
{
LEAVE("no split");
return;
}
gnc_suspend_gui_refresh ();
trans = xaccSplitGetParent(split);
/* If we just deleted the blank split, clean up. The user is
* allowed to delete the blank split as a method for discarding
* any edits they may have made to it. */
if (split == blank_split)
{
DEBUG("deleting blank split");
info->blank_split_guid = *guid_null();
}
else
{
info->trans_expanded = FALSE;
}
/* Check pending transaction */
if (trans == pending_trans)
{
DEBUG("clearing pending trans");
info->pending_trans_guid = *guid_null();
pending_trans = NULL;
}
was_open = xaccTransIsOpen(trans);
xaccTransDestroy(trans);
if (was_open)
{
DEBUG("committing");
xaccTransCommitEdit(trans);
}
gnc_resume_gui_refresh ();
LEAVE(" ");
}
| void gnc_split_register_destroy | ( | SplitRegister * | reg | ) |
Destroys a split register.
| reg | a SplitRegister |
Definition at line 2704 of file split-register.c.
{
g_return_if_fail(reg);
ENTER("reg=%p", reg);
gnc_gconf_general_remove_cb(KEY_ACCOUNTING_LABELS,
split_register_gconf_changed,
reg);
gnc_gconf_general_remove_cb(KEY_ACCOUNT_SEPARATOR,
split_register_gconf_changed,
reg);
gnc_split_register_cleanup (reg);
gnc_table_destroy (reg->table);
reg->table = NULL;
/* free the memory itself */
g_free (reg);
LEAVE(" ");
}
| 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 386 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info(reg);
CursorClass cursor_class;
Transaction *trans;
Split *return_split;
Split *trans_split;
Split *blank_split;
gboolean changed;
Split *split;
ENTER("reg=%p", reg);
blank_split = xaccSplitLookup(&info->blank_split_guid,
gnc_get_current_book ());
split = gnc_split_register_get_current_split (reg);
trans = gnc_split_register_get_current_trans (reg);
trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
/* This shouldn't happen, but be paranoid. */
if (trans == NULL)
{
LEAVE("no transaction");
return NULL;
}
cursor_class = gnc_split_register_get_current_cursor_class (reg);
/* Can't do anything with this. */
if (cursor_class == CURSOR_CLASS_NONE)
{
LEAVE("no cursor class");
return NULL;
}
/* This shouldn't happen, but be paranoid. */
if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
{
LEAVE("no split with transaction class");
return NULL;
}
changed = gnc_table_current_cursor_changed (reg->table, FALSE);
/* See if we were asked to duplicate an unchanged blank split.
* There's no point in doing that! */
if (!changed && ((split == NULL) || (split == blank_split)))
{
LEAVE("skip unchanged blank split");
return NULL;
}
gnc_suspend_gui_refresh ();
/* If the cursor has been edited, we are going to have to commit
* it before we can duplicate. Make sure the user wants to do that. */
if (changed)
{
GtkWidget *dialog, *window;
gint response;
const char *title = _("Save transaction before duplicating?");
const char *message =
_("The current transaction has been changed. Would you like to "
"record the changes before duplicating the transaction, or "
"cancel the duplication?");
window = gnc_split_register_get_parent(reg);
dialog = gtk_message_dialog_new(GTK_WINDOW(window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_CANCEL,
"%s", title);
gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
"%s", message);
gtk_dialog_add_button(GTK_DIALOG(dialog),
_("_Record"), GTK_RESPONSE_ACCEPT);
response = gnc_dialog_run(GTK_DIALOG(dialog), "transaction_duplicated");
gtk_widget_destroy(dialog);
if (response != GTK_RESPONSE_ACCEPT)
{
gnc_resume_gui_refresh ();
LEAVE("save cancelled");
return NULL;
}
gnc_split_register_save (reg, TRUE);
/* If the split is NULL, then we were on a blank split row
* in an expanded transaction. The new split (created by
* gnc_split_register_save above) will be the last split in the
* current transaction, as it was just added. */
if (split == NULL)
split = xaccTransGetSplit (trans, xaccTransCountSplits (trans) - 1);
}
/* Ok, we are now ready to make the copy. */
if (cursor_class == CURSOR_CLASS_SPLIT)
{
Split *new_split;
/* We are on a split in an expanded transaction.
* Just copy the split and add it to the transaction. */
new_split = xaccMallocSplit (gnc_get_current_book ());
xaccTransBeginEdit (trans);
xaccSplitSetParent (new_split, trans);
gnc_copy_split_onto_split (split, new_split, FALSE);
xaccTransCommitEdit (trans);
return_split = new_split;
info->cursor_hint_split = new_split;
info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
}
else
{
NumCell *num_cell;
Transaction *new_trans;
int trans_split_index;
int split_index;
const char *in_num = NULL;
char *out_num;
time_t date;
/* We are on a transaction row. Copy the whole transaction. */
date = info->last_date_entered;
if (gnc_strisnum (xaccTransGetNum (trans)))
{
Account *account = gnc_split_register_get_default_account (reg);
if (account)
in_num = xaccAccountGetLastNum (account);
else
in_num = xaccTransGetNum (trans);
}
if (!gnc_dup_trans_dialog (gnc_split_register_get_parent (reg),
&date, in_num, &out_num))
{
gnc_resume_gui_refresh ();
LEAVE("dup cancelled");
return NULL;
}
split_index = xaccTransGetSplitIndex(trans, split);
trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
/* we should *always* find the split, but be paranoid */
if (split_index < 0)
{
gnc_resume_gui_refresh ();
LEAVE("no split");
return NULL;
}
new_trans = xaccMallocTransaction (gnc_get_current_book ());
xaccTransBeginEdit (new_trans);
gnc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
xaccTransSetDatePostedSecs (new_trans, date);
xaccTransSetNum (new_trans, out_num);
xaccTransCommitEdit (new_trans);
num_cell = (NumCell *) gnc_table_layout_get_cell (reg->table->layout,
NUM_CELL);
if (gnc_num_cell_set_last_num (num_cell, out_num))
gnc_split_register_set_last_num (reg, out_num);
g_free (out_num);
/* This shouldn't happen, but be paranoid. */
if (split_index >= xaccTransCountSplits (new_trans))
split_index = 0;
return_split = xaccTransGetSplit (new_trans, split_index);
trans_split = xaccTransGetSplit (new_trans, trans_split_index);
info->cursor_hint_trans = new_trans;
info->cursor_hint_split = return_split;
info->cursor_hint_trans_split = trans_split;
info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
info->trans_expanded = FALSE;
}
/* Refresh the GUI. */
gnc_resume_gui_refresh ();
LEAVE(" ");
return return_split;
}
| void gnc_split_register_empty_current_trans_except_split | ( | SplitRegister * | reg, |
| Split * | split | ||
| ) |
Deletes the non-transaction splits associated wih the current cursor, if both are non-NULL.
Definition at line 1139 of file split-register.c.
{
SRInfo *info;
Transaction *trans;
Transaction *pending;
int i = 0;
Split *s;
if ((reg == NULL) || (split == NULL))
return;
gnc_suspend_gui_refresh ();
info = gnc_split_register_get_info(reg);
pending = xaccTransLookup(&info->pending_trans_guid, gnc_get_current_book());
trans = xaccSplitGetParent(split);
if (!pending)
{
if (gnc_split_register_begin_edit_or_warn(info, trans))
{
gnc_resume_gui_refresh ();
return;
}
}
else if (pending == trans)
{
g_assert(xaccTransIsOpen(trans));
}
else g_assert_not_reached();
while ((s = xaccTransGetSplit(trans, i)) != NULL)
{
if (s != split)
xaccSplitDestroy(s);
else i++;
}
gnc_resume_gui_refresh ();
gnc_split_register_redraw(reg);
}
| void gnc_split_register_expand_current_trans | ( | SplitRegister * | reg, |
| gboolean | expand | ||
| ) |
Expand the current transaction if it is collapsed.
Definition at line 189 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
VirtualLocation virt_loc;
if (!reg)
return;
if (reg->style == REG_STYLE_AUTO_LEDGER ||
reg->style == REG_STYLE_JOURNAL)
return;
/* ok, so I just wanted an excuse to use exclusive-or */
if (!(expand ^ info->trans_expanded))
return;
if (!expand)
{
virt_loc = reg->table->current_cursor_loc;
gnc_split_register_get_trans_split (reg, virt_loc.vcell_loc,
&virt_loc.vcell_loc);
if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
gnc_table_move_cursor_gui (reg->table, virt_loc);
else
{
PERR ("Can't find place to go!");
return;
}
}
info->trans_expanded = expand;
gnc_table_set_virt_cell_cursor (reg->table,
reg->table->current_cursor_loc.vcell_loc,
gnc_split_register_get_active_cursor (reg));
gnc_split_register_set_trans_visible(
reg, reg->table->current_cursor_loc.vcell_loc, expand, FALSE);
virt_loc = reg->table->current_cursor_loc;
if (!expand || !gnc_table_virtual_loc_valid (reg->table, virt_loc, FALSE))
{
if (gnc_table_find_close_valid_cell (reg->table, &virt_loc, FALSE))
gnc_table_move_cursor_gui (reg->table, virt_loc);
else
{
PERR ("Can't find place to go!");
return;
}
}
gnc_table_refresh_gui (reg->table, TRUE);
if (expand)
gnc_split_register_show_trans (reg,
reg->table->current_cursor_loc.vcell_loc);
}
| Split* gnc_split_register_get_blank_split | ( | SplitRegister * | reg | ) |
Gets the blank split for a register.
| reg | a SplitRegister |
NULL if there currently isn't one Definition at line 298 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
if (!reg) return NULL;
return xaccSplitLookup (&info->blank_split_guid, gnc_get_current_book ());
}
| const char* gnc_split_register_get_credit_string | ( | SplitRegister * | reg | ) |
Return the credit string used in the register.
Definition at line 2134 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
if (!reg)
return NULL;
if (info->credit_str)
return info->credit_str;
info->credit_str =
gnc_get_credit_string
(gnc_split_register_type_to_account_type (reg->type));
if (info->credit_str)
return info->credit_str;
info->credit_str = g_strdup (_("Credit"));
return info->credit_str;
}
| CursorClass gnc_split_register_get_current_cursor_class | ( | SplitRegister * | reg | ) |
Returns the class of a register's current cursor.
| reg | a SplitRegister |
Definition at line 477 of file split-register-util.c.
| Split* gnc_split_register_get_current_split | ( | SplitRegister * | reg | ) |
Returns the split at which the cursor is currently located.
| reg | a SplitRegister |
Definition at line 288 of file split-register.c.
{
if (reg == NULL)
return NULL;
return gnc_split_register_get_split(
reg, reg->table->current_cursor_loc.vcell_loc);
}
| 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.
| reg | a SplitRegister |
NULL Definition at line 264 of file split-register.c.
{
Split *split;
VirtualCellLocation vcell_loc;
if (reg == NULL)
return NULL;
split = gnc_split_register_get_current_split (reg);
if (split != NULL)
return xaccSplitGetParent(split);
/* Split is blank. Assume it is the blank split of a multi-line
* transaction. Go back one row to find a split in the transaction. */
vcell_loc = reg->table->current_cursor_loc.vcell_loc;
vcell_loc.virt_row--;
split = gnc_split_register_get_split (reg, vcell_loc);
return xaccSplitGetParent (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.
| reg | a SplitRegister |
| vcell_loc | a pointer to be filled with the location of the transaction's virtual cell |
Definition at line 185 of file split-register-util.c.
{
VirtualCellLocation vcell_loc;
if (reg == NULL)
return NULL;
vcell_loc = reg->table->current_cursor_loc.vcell_loc;
return gnc_split_register_get_trans_split (reg, vcell_loc, trans_split_loc);
}
| CursorClass gnc_split_register_get_cursor_class | ( | SplitRegister * | reg, |
| VirtualCellLocation | vcell_loc | ||
| ) |
Returns the class of the cursor at the given virtual cell location.
| reg | a SplitRegister |
| vcell_loc | the location of a virtual cell |
Definition at line 456 of file split-register-util.c.
{
VirtualCell *vcell;
Table *table;
if (reg == NULL)
return CURSOR_CLASS_NONE;
table = reg->table;
if (table == NULL)
return CURSOR_CLASS_NONE;
vcell = gnc_table_get_virtual_cell (table, vcell_loc);
if (vcell == NULL)
return CURSOR_CLASS_NONE;
return gnc_split_register_cursor_class (reg, vcell->cellblock);
}
| const char* gnc_split_register_get_debit_string | ( | SplitRegister * | reg | ) |
Return the debit string used in the register.
Definition at line 2111 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
if (!reg)
return NULL;
if (info->debit_str)
return info->debit_str;
info->debit_str =
gnc_get_debit_string
(gnc_split_register_type_to_account_type (reg->type));
if (info->debit_str)
return info->debit_str;
info->debit_str = g_strdup (_("Debit"));
return info->debit_str;
}
| 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.
| reg | a SplitRegister |
| split | the Split to find |
| virt_loc | a pointer to be filled with the amount cell's location |
TRUE if the split was found and the location has been stored at virt_loc, FALSE otherwise Definition at line 348 of file split-register.c.
{
VirtualLocation v_loc;
CursorClass cursor_class;
const char *cell_name;
gnc_numeric value;
if (!gnc_split_register_get_split_virt_loc (reg, split, &v_loc.vcell_loc))
return FALSE;
cursor_class = gnc_split_register_get_cursor_class (reg, v_loc.vcell_loc);
value = xaccSplitGetValue (split);
switch (cursor_class)
{
case CURSOR_CLASS_SPLIT:
case CURSOR_CLASS_TRANS:
cell_name = (gnc_numeric_negative_p (value)) ? CRED_CELL : DEBT_CELL;
break;
default:
return FALSE;
}
if (!gnc_table_get_cell_location (reg->table, cell_name,
v_loc.vcell_loc, &v_loc))
return FALSE;
if (virt_loc == NULL)
return TRUE;
*virt_loc = v_loc;
return TRUE;
}
| 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.
| reg | a SplitRegister |
| split | the Split to find |
| vcell_loc | a pointer to be filled with the location of the matching virtual cell |
TRUE if the split was found and the location has been stored at vcell_loc, FALSE otherwise Definition at line 308 of file split-register.c.
{
Table *table;
int v_row;
int v_col;
if (!reg || !split) return FALSE;
table = reg->table;
/* go backwards because typically you search for splits at the end
* and because we find split rows before transaction rows. */
for (v_row = table->num_virt_rows - 1; v_row > 0; v_row--)
for (v_col = 0; v_col < table->num_virt_cols; v_col++)
{
VirtualCellLocation vc_loc = { v_row, v_col };
VirtualCell *vcell;
Split *s;
vcell = gnc_table_get_virtual_cell (table, vc_loc);
if (!vcell || !vcell->visible)
continue;
s = xaccSplitLookup (vcell->vcell_data, gnc_get_current_book ());
if (s == split)
{
if (vcell_loc)
*vcell_loc = vc_loc;
return TRUE;
}
}
return FALSE;
}
| 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 to be called. If the dialog does not complete successfully, then return TRUE. Return FALSE in all other cases (meaning "move on")
Definition at line 1257 of file split-register-control.c.
{
SRInfo *info;
Transaction *txn;
Split *split, *osplit;
Account *xfer_acc, *reg_acc;
gnc_commodity *txn_cur, *xfer_com, *reg_com;
gnc_numeric amount, exch_rate;
XferDialog *xfer;
gboolean expanded = FALSE;
PriceCell *rate_cell;
const char *message;
CursorClass cursor_class;
ENTER("reg=%p, force_dialog=%s", reg, force_dialog ? "TRUE" : "FALSE" );
/* Make sure we NEED this for this type of register */
if (!gnc_split_reg_has_rate_cell (reg->type))
{
if (force_dialog)
{
message = _("This register does not support editing exchange rates.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("no rate cell");
return FALSE;
}
rate_cell = (PriceCell*) gnc_table_layout_get_cell(
reg->table->layout, RATE_CELL);
if (!rate_cell)
{
if (force_dialog)
{
message = _("This register does not support editing exchange rates.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("null rate cell");
return FALSE;
}
/* See if we already have an exchange rate... */
exch_rate = gnc_price_cell_get_value (rate_cell);
if (!gnc_numeric_zero_p(exch_rate) && !force_dialog)
{
LEAVE("rate already non-zero");
return FALSE;
}
/* Are we expanded? */
expanded = gnc_split_register_current_trans_expanded (reg);
cursor_class = gnc_split_register_get_current_cursor_class (reg);
/* If we're expanded AND a transaction cursor, there is nothing to do */
if (expanded && cursor_class == CURSOR_CLASS_TRANS)
{
if (force_dialog)
{
message = _("You need to select a split in order to modify its exchange "
"rate.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("expanded with transaction cursor; nothing to do");
return FALSE;
}
/* Grab the xfer account */
xfer_acc = gnc_split_register_get_account_always(
reg, expanded ? XFRM_CELL : MXFRM_CELL);
/* If this is an un-expanded, multi-split transaction, then warn the user */
if (force_dialog && !expanded && !xfer_acc)
{
message = _("You need to expand the transaction in order to modify its "
"exchange rates.");
gnc_error_dialog (gnc_split_register_get_parent (reg), "%s", message);
LEAVE("%s", message);
return TRUE;
}
/* No account -- don't run the dialog */
if (!xfer_acc)
{
if (force_dialog)
{
message = _("The entered account could not be found.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("no xfer account");
return FALSE;
}
/* Grab the txn currency and xfer commodity */
txn = gnc_split_register_get_current_trans (reg);
txn_cur = xaccTransGetCurrency (txn);
xfer_com = xaccAccountGetCommodity (xfer_acc);
/* Grab the register account and commodity (may be used later) */
reg_acc = gnc_split_register_get_default_account (reg);
reg_com = xaccAccountGetCommodity (reg_acc);
/* Grab the split and perhaps the "other" split (if it is a two-split txn) */
split = gnc_split_register_get_current_split (reg);
osplit = xaccSplitGetOtherSplit (split);
/* Check if the txn- and xfer- commodities are the same */
if (gnc_commodity_equal (txn_cur, xfer_com))
{
/* If we're not forcing the dialog, then there is no reason to
* go on. We're using the correct accounts.
*/
if (!force_dialog)
{
LEAVE("txn and account currencies match, and not forcing");
return FALSE;
}
/* Only proceed with two-split, basic, non-expanded registers */
if (expanded || osplit == NULL)
{
message = _("The two currencies involved equal each other.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
LEAVE("register is expanded or osplit == NULL; not forcing dialog");
return FALSE;
}
/* If we're forcing, then compare the current account
* commodity to the transaction currency.
*/
xfer_acc = reg_acc;
xfer_com = reg_com;
if (gnc_commodity_equal (txn_cur, xfer_com))
{
message = _("The two currencies involved equal each other.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
LEAVE("reg commodity == txn commodity; not forcing");
return FALSE;
}
}
/* If this is a non-expanded, two-split txn where BOTH splits need
* conversion rates, then require the user to actually expand the
* transaction in order to edit it.
*/
if (!expanded && osplit &&
gnc_split_register_split_needs_amount (reg, split) &&
gnc_split_register_split_needs_amount (reg, osplit))
{
message = _("You need to expand the transaction in order to modify its "
"exchange rates.");
if (force_dialog)
{
gnc_error_dialog (gnc_split_register_get_parent (reg), "%s", message);
}
LEAVE("%s", message);
return TRUE;
}
/* Strangely, if we're in a two-split, non-expanded txn, we need
* to do something really special with the exchange rate! In
* particular, we have to pick it up from the _other_ split --
* right?
* XXX: perhaps I should pop up an error here? Or maybe require the
* user to go into expanded-mode?
*/
if (!expanded && osplit && !gnc_commodity_equal(reg_com, txn_cur) &&
!gnc_commodity_equal(reg_com, xfer_com))
{
gnc_numeric amt = xaccSplitGetAmount (osplit);
gnc_numeric val = xaccSplitGetValue (osplit);
exch_rate = gnc_numeric_div (amt, val, GNC_DENOM_AUTO, GNC_HOW_DENOM_REDUCE);
}
/* Ok, we need to grab the exchange rate */
amount = gnc_split_register_debcred_cell_value (reg);
/*
* If "amount" is zero then we don't need an exchange-rate.. Return
* FALSE to let the user continue on.
*/
if (gnc_numeric_zero_p (amount))
{
if (force_dialog)
{
message = _("The split's amount is zero, so no exchange rate is needed.");
gnc_error_dialog(gnc_split_register_get_parent(reg), "%s", message);
}
LEAVE("amount is zero; no exchange rate needed");
return FALSE;
}
/* If the exch_rate is zero, we're not forcing the dialog, and this is
* _not_ the blank split, then return FALSE -- this is a "special"
* gain/loss stock transaction.
*/
info = gnc_split_register_get_info (reg);
if (gnc_numeric_zero_p(exch_rate) && !force_dialog && split &&
!info->rate_reset &&
split != gnc_split_register_get_blank_split (reg))
{
LEAVE("gain/loss split; no exchange rate needed");
return FALSE;
}
/* Show the exchange-rate dialog */
xfer = gnc_split_register_xfer_dialog(reg, txn, split);
gnc_xfer_dialog_is_exchange_dialog(xfer, &exch_rate);
if (gnc_xfer_dialog_run_exchange_dialog(
xfer, &exch_rate, amount, reg_acc, txn, xfer_com, expanded))
{
/* FIXME: How should the dialog be destroyed? */
LEAVE("leaving rate unchanged");
return TRUE;
}
/* FIXME: How should the dialog be destroyed? */
/* Set the RATE_CELL on this cursor and mark it changed */
gnc_price_cell_set_value (rate_cell, exch_rate);
gnc_basic_cell_set_changed (&rate_cell->cell, TRUE);
info->rate_account = xfer_acc;
info->rate_reset = FALSE;
LEAVE("set rate=%s", gnc_num_dbg_to_string(exch_rate));
return FALSE;
}
| void gnc_split_register_load | ( | SplitRegister * | reg, |
| GList * | slist, | ||
| Account * | default_account | ||
| ) |
Populates the rows of a register.
The rows are filled, based on the register style, with data associated with the given list of splits slist. In addition, an area for the user to begin entering new transactions is placed at the tail end of the register. This area is anchored by the "blank split".
The account default_account, if provided, is used to determine various default values for the blank split (such as currency, last check number, and transfer account) for the blank split.
| reg | a SplitRegister |
| slist | a list of splits |
| default_account | an account to provide defaults for the blank split |
Definition at line 242 of file split-register-load.c.
{
SRInfo *info;
Transaction *pending_trans;
CursorBuffer *cursor_buffer;
GHashTable *trans_table = NULL;
CellBlock *cursor_header;
CellBlock *lead_cursor;
CellBlock *split_cursor;
Transaction *blank_trans;
Transaction *find_trans;
Transaction *trans;
CursorClass find_class;
Split *find_trans_split;
Split *blank_split;
Split *find_split;
Split *split;
Table *table;
GList *node;
gboolean start_primary_color = TRUE;
gboolean found_pending = FALSE;
gboolean found_divider = FALSE;
gboolean has_last_num = FALSE;
gboolean multi_line;
gboolean dynamic;
gboolean we_own_slist = FALSE;
VirtualCellLocation vcell_loc;
VirtualLocation save_loc;
int new_trans_split_row = -1;
int new_trans_row = -1;
int new_split_row = -1;
time_t present;
g_return_if_fail(reg);
table = reg->table;
g_return_if_fail(table);
info = gnc_split_register_get_info (reg);
g_return_if_fail(info);
ENTER("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* make sure we have a blank split */
if (blank_split == NULL)
{
Transaction *new_trans;
gnc_commodity * currency = NULL;
/* Determine the proper currency to use for this transaction.
* if default_account != NULL and default_account->commodity is
* a currency, then use that. Otherwise use the default currency.
*/
if (default_account != NULL)
{
gnc_commodity * commodity = xaccAccountGetCommodity (default_account);
if (gnc_commodity_is_currency(commodity))
currency = commodity;
else
{
Account *parent_account = default_account;
/* Account commodity is not a currency, walk up the tree until
* we find a parent account that is a currency account and use
* it's currency.
*/
do
{
parent_account = gnc_account_get_parent (parent_account);
if (parent_account)
{
commodity = xaccAccountGetCommodity (parent_account);
if (gnc_commodity_is_currency(commodity))
{
currency = commodity;
break;
}
}
}
while (parent_account && !currency);
}
/* If we don't have a currency then pop up a warning dialog */
if (!currency)
{
gnc_info_dialog(NULL, "%s",
_("Could not determine the account currency. "
"Using the default currency provided by your system."));
}
}
gnc_suspend_gui_refresh ();
new_trans = xaccMallocTransaction (gnc_get_current_book ());
xaccTransBeginEdit (new_trans);
xaccTransSetCurrency (new_trans,
currency ? currency : gnc_default_currency());
xaccTransSetDatePostedSecs (new_trans, info->last_date_entered);
blank_split = xaccMallocSplit (gnc_get_current_book ());
xaccSplitSetParent(blank_split, new_trans);
/* We don't want to commit this transaction yet, because the split
doesn't even belong to an account yet. But, we don't want to
set this transaction as the pending transaction either, because
we want to pretend that it hasn't been changed. We depend on
some other code (somewhere) to commit this transaction if we
really edit it, even though it's not marked as the pending
transaction. */
/* Wouldn't it be a bug to open this transaction if there was already a
pending transaction? */
g_assert(pending_trans == NULL);
info->blank_split_guid = *xaccSplitGetGUID (blank_split);
info->blank_split_edited = FALSE;
DEBUG("created new blank_split=%p", blank_split);
gnc_resume_gui_refresh ();
}
blank_trans = xaccSplitGetParent (blank_split);
DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p",
blank_split, blank_trans, pending_trans);
info->default_account = *xaccAccountGetGUID (default_account);
// gnc_table_leave_update (table, table->current_cursor_loc);
multi_line = (reg->style == REG_STYLE_JOURNAL);
dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
lead_cursor = gnc_split_register_get_passive_cursor (reg);
split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
/* figure out where we are going to. */
if (info->traverse_to_new)
{
find_trans = blank_trans;
find_split = NULL;
find_trans_split = blank_split;
find_class = CURSOR_CLASS_SPLIT;
}
else
{
find_trans = info->cursor_hint_trans;
find_split = info->cursor_hint_split;
find_trans_split = info->cursor_hint_trans_split;
find_class = info->cursor_hint_cursor_class;
}
save_loc = table->current_cursor_loc;
/* If the current cursor has changed we save the values for later
* possible restoration. */
if (gnc_table_current_cursor_changed (table, TRUE) &&
(find_split == gnc_split_register_get_current_split (reg)))
{
cursor_buffer = gnc_cursor_buffer_new ();
gnc_table_save_current_cursor (table, cursor_buffer);
}
else
cursor_buffer = NULL;
/* disable move callback -- we don't want the cascade of
* callbacks while we are fiddling with loading the register */
gnc_table_control_allow_move (table->control, FALSE);
/* invalidate the cursor */
{
VirtualLocation virt_loc;
gnc_virtual_location_init(&virt_loc);
gnc_table_move_cursor_gui (table, virt_loc);
}
/* make sure that the header is loaded */
vcell_loc.virt_row = 0;
vcell_loc.virt_col = 0;
cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
vcell_loc.virt_row++;
/* get the current time and reset the dividing row */
present = gnc_timet_get_today_end ();
if (info->first_pass)
{
if (default_account)
{
const char *last_num = xaccAccountGetLastNum (default_account);
if (last_num)
{
NumCell *cell;
cell = (NumCell *) gnc_table_layout_get_cell(table->layout, NUM_CELL);
gnc_num_cell_set_last_num (cell, last_num);
has_last_num = TRUE;
}
}
/* load up account names into the transfer combobox menus */
gnc_split_register_load_xfer_cells (reg, default_account);
gnc_split_register_load_recn_cells (reg);
gnc_split_register_load_type_cells (reg);
}
if (info->separator_changed)
{
info->separator_changed = FALSE;
/* set the completion character for the xfer cells */
gnc_combo_cell_set_complete_char(
(ComboCell *) gnc_table_layout_get_cell(table->layout, MXFRM_CELL),
gnc_get_account_separator());
gnc_combo_cell_set_complete_char(
(ComboCell *) gnc_table_layout_get_cell(table->layout, XFRM_CELL),
gnc_get_account_separator());
/* set the confirmation callback for the reconcile cell */
gnc_recn_cell_set_confirm_cb(
(RecnCell *) gnc_table_layout_get_cell(table->layout, RECN_CELL),
gnc_split_register_recn_cell_confirm, reg);
}
table->model->dividing_row = -1;
// Ensure that the transaction and splits being edited are in the split
// list we're about to load.
if (pending_trans != NULL)
{
for (node = xaccTransGetSplitList(pending_trans); node; node = node->next)
{
Split *pending_split = (Split*)node->data;
if (!xaccTransStillHasSplit(pending_trans, pending_split)) continue;
if (g_list_find(slist, pending_split) != NULL)
continue;
if (g_list_find_custom(slist, pending_trans,
_find_split_with_parent_txn) != NULL)
continue;
if (!we_own_slist)
{
// lazy-copy
slist = g_list_copy(slist);
we_own_slist = TRUE;
}
slist = g_list_append(slist, pending_split);
}
}
if (multi_line)
trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
/* populate the table */
for (node = slist; node; node = node->next)
{
split = node->data;
trans = xaccSplitGetParent (split);
if (!xaccTransStillHasSplit(trans, split))
continue;
if (pending_trans == trans)
found_pending = TRUE;
/* Do not load splits from the blank transaction. */
if (trans == blank_trans)
continue;
if (multi_line)
{
/* Skip this split if its transaction has already been loaded. */
if (g_hash_table_lookup (trans_table, trans))
continue;
g_hash_table_insert (trans_table, trans, trans);
}
if (info->show_present_divider &&
!found_divider &&
(present < xaccTransGetDate (trans)))
{
table->model->dividing_row = vcell_loc.virt_row;
found_divider = TRUE;
}
/* If this is the first load of the register,
* fill up the quickfill cells. */
if (info->first_pass)
add_quickfill_completions(reg->table->layout, trans, has_last_num);
if (trans == find_trans)
new_trans_row = vcell_loc.virt_row;
if (split == find_trans_split)
new_trans_split_row = vcell_loc.virt_row;
gnc_split_register_add_transaction (reg, trans, split,
lead_cursor, split_cursor,
multi_line, start_primary_color,
TRUE,
find_trans, find_split, find_class,
&new_split_row, &vcell_loc);
if (!multi_line)
start_primary_color = !start_primary_color;
}
if (multi_line)
g_hash_table_destroy (trans_table);
/* add the blank split at the end. */
if (pending_trans == blank_trans)
found_pending = TRUE;
if (blank_trans == find_trans)
new_trans_row = vcell_loc.virt_row;
if (blank_split == find_trans_split)
new_trans_split_row = vcell_loc.virt_row;
/* If we didn't find the pending transaction, it was removed
* from the account. */
if (!found_pending)
{
info->pending_trans_guid = *guid_null ();
if (xaccTransIsOpen (pending_trans))
xaccTransCommitEdit (pending_trans);
else if (pending_trans)
g_assert_not_reached();
pending_trans = NULL;
}
/* go to blank on first pass */
if (info->first_pass)
{
new_split_row = -1;
new_trans_split_row = -1;
new_trans_row = -1;
save_loc.vcell_loc = vcell_loc;
save_loc.phys_row_offset = 0;
save_loc.phys_col_offset = 0;
}
gnc_split_register_add_transaction (reg, blank_trans, blank_split,
lead_cursor, split_cursor,
multi_line, start_primary_color,
info->blank_split_edited, find_trans,
find_split, find_class, &new_split_row,
&vcell_loc);
/* resize the table to the sizes we just counted above */
/* num_virt_cols is always one. */
gnc_table_set_size (table, vcell_loc.virt_row, 1);
/* restore the cursor to its rightful position */
{
VirtualLocation trans_split_loc;
Split *trans_split;
if (new_split_row > 0)
save_loc.vcell_loc.virt_row = new_split_row;
else if (new_trans_split_row > 0)
save_loc.vcell_loc.virt_row = new_trans_split_row;
else if (new_trans_row > 0)
save_loc.vcell_loc.virt_row = new_trans_row;
trans_split_loc = save_loc;
trans_split =
gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
&trans_split_loc.vcell_loc);
if (dynamic || multi_line || info->trans_expanded)
{
gnc_table_set_virt_cell_cursor(
table, trans_split_loc.vcell_loc,
gnc_split_register_get_active_cursor (reg));
gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
TRUE, multi_line);
info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
}
else
{
save_loc = trans_split_loc;
info->trans_expanded = FALSE;
}
if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
{
gnc_table_move_cursor_gui (table, save_loc);
new_split_row = save_loc.vcell_loc.virt_row;
if (find_split == gnc_split_register_get_current_split (reg))
gnc_table_restore_current_cursor (table, cursor_buffer);
}
gnc_cursor_buffer_destroy (cursor_buffer);
cursor_buffer = NULL;
}
/* Set up the hint transaction, split, transaction split, and column. */
info->cursor_hint_trans = gnc_split_register_get_current_trans (reg);
info->cursor_hint_split = gnc_split_register_get_current_split (reg);
info->cursor_hint_trans_split =
gnc_split_register_get_current_trans_split (reg, NULL);
info->cursor_hint_cursor_class =
gnc_split_register_get_current_cursor_class (reg);
info->hint_set_by_traverse = FALSE;
info->traverse_to_new = FALSE;
info->exact_traversal = FALSE;
info->first_pass = FALSE;
info->reg_loaded = TRUE;
gnc_split_register_set_cell_fractions(
reg, gnc_split_register_get_current_split (reg));
gnc_table_refresh_gui (table, TRUE);
gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
/* enable callback for cursor user-driven moves */
gnc_table_control_allow_move (table->control, TRUE);
if (we_own_slist)
g_list_free(slist);
LEAVE(" ");
}
| SplitRegister* gnc_split_register_new | ( | SplitRegisterType | type, |
| SplitRegisterStyle | style, | ||
| gboolean | use_double_line, | ||
| gboolean | is_template | ||
| ) |
Creates a new split register.
| type | a SplitRegisterType to use for the new register |
| style | a SplitRegisterStyle to use for the new register |
| use_double_line | TRUE to show two lines for transactions, FALSE for one |
| is_template | TRUE for a new template, FALSE otherwise |
Definition at line 2521 of file split-register.c.
{
SplitRegister * reg;
gboolean default_do_auto_complete = TRUE;
reg = g_new0 (SplitRegister, 1);
if (type >= NUM_SINGLE_REGISTER_TYPES)
style = REG_STYLE_JOURNAL;
gnc_split_register_init (reg,
type,
style,
use_double_line,
default_do_auto_complete,
is_template);
return reg;
}
| 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 754 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info(reg);
CursorClass cursor_class;
Transaction *trans;
Transaction *blank_trans;
Split *blank_split;
Split *trans_split;
Split *split;
ENTER("reg=%p", reg);
if (copied_class == CURSOR_CLASS_NONE)
{
LEAVE("no copied cursor class");
return;
}
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
blank_trans = xaccSplitGetParent (blank_split);
split = gnc_split_register_get_current_split (reg);
trans = gnc_split_register_get_current_trans (reg);
trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
/* This shouldn't happen, but be paranoid. */
if (trans == NULL)
{
LEAVE("no transaction");
return;
}
cursor_class = gnc_split_register_get_current_cursor_class (reg);
/* Can't do anything with this. */
if (cursor_class == CURSOR_CLASS_NONE)
{
LEAVE("no current cursor class");
return;
}
/* This shouldn't happen, but be paranoid. */
if ((split == NULL) && (cursor_class == CURSOR_CLASS_TRANS))
{
g_warning("BUG DETECTED: transaction cursor with no anchoring split!");
LEAVE("transaction cursor with no anchoring split");
return;
}
if (cursor_class == CURSOR_CLASS_SPLIT)
{
const char *message = _("You are about to overwrite an existing split. "
"Are you sure you want to do that?");
if (copied_class == CURSOR_CLASS_TRANS)
{
/* An entire transaction was copied, but we're just on a split. */
LEAVE("can't copy trans to split");
return;
}
/* Ask before overwriting an existing split. */
if (split != NULL &&
!gnc_verify_dialog (gnc_split_register_get_parent (reg),
FALSE, "%s", message))
{
LEAVE("user cancelled");
return;
}
gnc_suspend_gui_refresh ();
if (split == NULL)
{
/* We are on a null split in an expanded transaction. */
split = xaccMallocSplit(gnc_get_current_book ());
xaccSplitSetParent(split, trans);
}
gnc_copy_split_scm_onto_split(copied_item, split,
gnc_get_current_book ());
}
else
{
const char *message = _("You are about to overwrite an existing "
"transaction. "
"Are you sure you want to do that?");
Account * copied_leader;
const GncGUID *new_guid;
int trans_split_index;
int split_index;
int num_splits;
if (copied_class == CURSOR_CLASS_SPLIT)
{
LEAVE("can't copy split to transaction");
return;
}
/* Ask before overwriting an existing transaction. */
if (split != blank_split &&
!gnc_verify_dialog(gnc_split_register_get_parent(reg),
FALSE, "%s", message))
{
LEAVE("user cancelled");
return;
}
/* Open the transaction for editing. */
if (gnc_split_register_begin_edit_or_warn(info, trans))
{
LEAVE("can't begin editing");
return;
}
gnc_suspend_gui_refresh ();
DEBUG("Pasting txn, trans=%p, split=%p, blank_trans=%p, blank_split=%p",
trans, split, blank_trans, blank_split);
split_index = xaccTransGetSplitIndex(trans, split);
trans_split_index = xaccTransGetSplitIndex(trans, trans_split);
copied_leader = xaccAccountLookup(&copied_leader_guid,
gnc_get_current_book());
if (copied_leader && (gnc_split_register_get_default_account(reg) != NULL))
{
new_guid = &info->default_account;
gnc_copy_trans_scm_onto_trans_swap_accounts(copied_item, trans,
&copied_leader_guid,
new_guid, FALSE,
gnc_get_current_book ());
}
else
gnc_copy_trans_scm_onto_trans(copied_item, trans, FALSE,
gnc_get_current_book ());
num_splits = xaccTransCountSplits(trans);
if (split_index >= num_splits)
split_index = 0;
if (trans == blank_trans)
{
/* In pasting, the blank split is deleted. Pick a new one. */
blank_split = xaccTransGetSplit(trans, 0);
info->blank_split_guid = *xaccSplitGetGUID (blank_split);
info->blank_split_edited = TRUE;
DEBUG("replacement blank_split=%p", blank_split);
/* NOTE: At this point, the blank transaction virtual cell is still
* anchored by the old, deleted blank split. The register will
* have to be reloaded (redrawn) to correct this. */
}
info->cursor_hint_trans = trans;
info->cursor_hint_split = xaccTransGetSplit(trans, split_index);
info->cursor_hint_trans_split = xaccTransGetSplit(trans,
trans_split_index);
info->cursor_hint_cursor_class = CURSOR_CLASS_TRANS;
}
/* Refresh the GUI. */
gnc_resume_gui_refresh ();
LEAVE(" ");
}
| void gnc_split_register_redraw | ( | SplitRegister * | reg | ) |
Causes a redraw of the register window associated with reg.
Definition at line 1246 of file split-register.c.
{
gnc_ledger_display_refresh_by_split_register (reg);
}
| 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 1440 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
Transaction *blank_trans;
Transaction *trans;
Account *account;
Split *blank_split;
const char *memo;
const char *desc;
Split *split;
ENTER("reg=%p, do_commit=%s", reg, do_commit ? "TRUE" : "FALSE");
if (!reg)
{
LEAVE("no register");
return FALSE;
}
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
blank_trans = xaccSplitGetParent (blank_split);
/* get the handle to the current split and transaction */
split = gnc_split_register_get_current_split (reg);
trans = gnc_split_register_get_current_trans (reg);
if (trans == NULL)
{
LEAVE("no transaction");
return FALSE;
}
/* use the changed flag to avoid heavy-weight updates
* of the split & transaction fields. This will help
* cut down on unnecessary register redraws. */
if (!gnc_table_current_cursor_changed (reg->table, FALSE))
{
if (!do_commit)
{
LEAVE("commit unnecessary");
return FALSE;
}
if (!xaccTransIsOpen(trans))
{
LEAVE("transaction not open");
return FALSE;
}
if (trans == pending_trans ||
(trans == blank_trans && info->blank_split_edited))
{
/* We are going to commit. */
gnc_suspend_gui_refresh ();
if (trans == blank_trans)
{
/* We have to clear the blank split before the
* refresh or a new one won't be created. */
info->last_date_entered = xaccTransGetDate (trans);
info->blank_split_guid = *guid_null ();
info->blank_split_edited = FALSE;
}
/* We have to clear the pending guid *before* committing the
* trans, because the event handler will find it otherwise. */
if (trans == pending_trans)
info->pending_trans_guid = *guid_null ();
PINFO("committing trans (%p)", trans);
xaccTransCommitEdit(trans);
gnc_resume_gui_refresh ();
}
else
DEBUG("leaving trans (%p) open", trans);
LEAVE("unchanged cursor");
return TRUE;
}
DEBUG("save split=%p", split);
DEBUG("blank_split=%p, blank_trans=%p, pending_trans=%p, trans=%p",
blank_split, blank_trans, pending_trans, trans);
/* Act on any changes to the current cell before the save. */
(void) gnc_split_register_check_cell (reg,
gnc_table_get_current_cell_name (reg->table));
if (!gnc_split_register_auto_calc (reg, split))
{
LEAVE("auto calc failed");
return FALSE;
}
/* Validate the transfer account names */
(void)gnc_split_register_get_account (reg, MXFRM_CELL);
(void)gnc_split_register_get_account (reg, XFRM_CELL);
/* Maybe deal with exchange-rate transfers */
if (gnc_split_register_handle_exchange (reg, FALSE))
{
LEAVE("no exchange rate");
return TRUE;
}
gnc_suspend_gui_refresh ();
/* determine whether we should commit the pending transaction */
if (pending_trans != trans)
{
// FIXME: How could the pending transaction not be open?
// FIXME: For that matter, how could an open pending
// transaction ever not be the current trans?
if (xaccTransIsOpen (pending_trans))
{
g_warning("Impossible? commiting pending %p", pending_trans);
xaccTransCommitEdit (pending_trans);
}
else if (pending_trans)
{
g_critical("BUG DETECTED! pending transaction (%p) not open",
pending_trans);
g_assert_not_reached();
}
if (trans == blank_trans)
{
/* Don't begin editing the blank trans, because it's
already open, but mark it pending now. */
g_assert(xaccTransIsOpen(blank_trans));
/* This is now the pending transaction */
info->pending_trans_guid = *xaccTransGetGUID(blank_trans);
}
else
{
PINFO("beginning edit of trans %p", trans);
if (gnc_split_register_begin_edit_or_warn(info, trans))
{
gnc_resume_gui_refresh ();
LEAVE("transaction opened elsewhere");
return FALSE;
}
}
pending_trans = trans;
}
g_assert(xaccTransIsOpen(trans));
/* If we are saving a brand new transaction and the blank split hasn't
* been edited, then we need to give it a default account. */
/* Q: Why check 'split == blank_split'? Isn't 'trans == blank_trans'
* even better? What if there were some way that we could be on
* a row other than the transaction row or blank split row, but
* the blank split still hasn't been edited? It seems to be assumed
* that it isn't possible, but... -Charles, Jan 2009 */
if (split == blank_split && !info->blank_split_edited)
{
/* If we've reached this point, it means that the blank split is
* anchoring the transaction - see gnc_split_register_add_transaction()
* for an explanation - and the transaction has been edited (as evidenced
* by the earlier check for a changed cursor.) Since the blank split
* itself has not been edited, we'll have to assign a default account. */
account = gnc_split_register_get_default_account(reg);
if (account)
xaccSplitSetAccount(blank_split, account);
xaccTransSetDateEnteredSecs(trans, time(NULL));
}
if (split == NULL)
{
/* If we were asked to save data for a row for which there is no
* associated split, then assume that this was an "empty" row - see
* gnc_split_register_add_transaction() for an explanation. This row
* is used to add splits to an existing transaction, or to add the
* 2nd through nth split rows to a brand new transaction.
* xaccSRGetCurrent will handle this case, too. We will create
* a new split, copy the row contents to that split, and append
* the split to the pre-existing transaction. */
Split *trans_split;
split = xaccMallocSplit (gnc_get_current_book ());
xaccTransAppendSplit (trans, split);
gnc_table_set_virt_cell_data (reg->table,
reg->table->current_cursor_loc.vcell_loc,
xaccSplitGetGUID (split));
DEBUG("assigned cell to new split=%p", split);
trans_split = gnc_split_register_get_current_trans_split (reg, NULL);
if ((info->cursor_hint_trans == trans) &&
(info->cursor_hint_trans_split == trans_split) &&
(info->cursor_hint_split == NULL))
{
info->cursor_hint_split = split;
info->cursor_hint_cursor_class = CURSOR_CLASS_SPLIT;
}
}
DEBUG("updating trans=%p", trans);
{
SRSaveData *sd;
sd = gnc_split_register_save_data_new (
trans, split, (info->trans_expanded ||
reg->style == REG_STYLE_AUTO_LEDGER ||
reg->style == REG_STYLE_JOURNAL));
gnc_table_save_cells (reg->table, sd);
gnc_split_register_save_data_destroy (sd);
}
memo = xaccSplitGetMemo (split);
memo = memo ? memo : "(null)";
desc = xaccTransGetDescription (trans);
desc = desc ? desc : "(null)";
PINFO ("finished saving split \"%s\" of trans \"%s\"", memo, desc);
/* If the modified split is the "blank split", then it is now an
* official part of the account. Set the blank split to NULL, so we
* can be sure of getting a new blank split. Also, save the date
* for the new blank split. */
if (trans == blank_trans)
{
if (do_commit)
{
info->blank_split_guid = *guid_null ();
blank_split = NULL;
info->last_date_entered = xaccTransGetDate (trans);
}
else
info->blank_split_edited = TRUE;
}
/* If requested, commit the current transaction and set the pending
* transaction to NULL. */
if (do_commit)
{
g_assert(trans == blank_trans || trans == pending_trans);
if (pending_trans == trans)
{
pending_trans = NULL;
info->pending_trans_guid = *guid_null ();
}
xaccTransCommitEdit (trans);
}
gnc_table_clear_current_cursor_changes (reg->table);
gnc_resume_gui_refresh ();
LEAVE(" ");
return TRUE;
}
| void gnc_split_register_set_auto_complete | ( | SplitRegister * | reg, |
| gboolean | do_auto_complete | ||
| ) |
Sets whether a register uses auto-completion.
| reg | a SplitRegister |
| do_auto_complete | TRUE to use auto-completion, FALSE otherwise |
Definition at line 2587 of file split-register.c.
{
g_return_if_fail(reg);
reg->do_auto_complete = do_auto_complete;
}
| void gnc_split_register_set_data | ( | SplitRegister * | reg, |
| gpointer | user_data, | ||
| SRGetParentCallback | get_parent | ||
| ) |
Sets the user data and callback hooks for the register.
| void gnc_split_register_set_read_only | ( | SplitRegister * | reg, |
| gboolean | read_only | ||
| ) |
Sets whether a register window is "read only".
| reg | a SplitRegister |
| read_only | TRUE to use "read only" mode, FALSE otherwise |
Definition at line 2727 of file split-register.c.
{
gnc_table_model_set_read_only (reg->table->model, read_only);
}
| void gnc_split_register_set_template_account | ( | SplitRegister * | reg, |
| Account * | template_account | ||
| ) |
Set the template account for use in a template register.
| reg | a SplitRegister |
| template_account | the account to use for the template |
Definition at line 115 of file split-register-util.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
g_return_if_fail (reg != NULL);
info->template_account = *xaccAccountGetGUID (template_account);
}
| 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 2189 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
if (reg == NULL)
return;
info->show_present_divider = show_present;
}
| void gnc_split_register_unvoid_current_trans | ( | SplitRegister * | reg | ) |
Unvoids the transaction associated with the current cursor, if non-NULL.
Definition at line 1092 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
Transaction *trans;
Split *blank_split;
Split *split;
if (!reg) return;
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* get the current split based on cursor position */
split = gnc_split_register_get_current_split (reg);
if (split == NULL)
return;
/* Bail if trying to unvoid the blank split. */
if (split == blank_split)
return;
/* not voided. */
if (xaccSplitGetReconcile (split) != VREC)
return;
info->trans_expanded = FALSE;
gnc_suspend_gui_refresh ();
trans = xaccSplitGetParent(split);
xaccTransUnvoid(trans);
/* Check pending transaction */
if (trans == pending_trans)
{
info->pending_trans_guid = *guid_null();
pending_trans = NULL;
}
gnc_resume_gui_refresh ();
}
| 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 1042 of file split-register.c.
{
SRInfo *info = gnc_split_register_get_info (reg);
Transaction *pending_trans;
Transaction *trans;
Split *blank_split;
Split *split;
if (!reg) return;
blank_split = xaccSplitLookup (&info->blank_split_guid,
gnc_get_current_book ());
pending_trans = xaccTransLookup (&info->pending_trans_guid,
gnc_get_current_book ());
/* get the current split based on cursor position */
split = gnc_split_register_get_current_split (reg);
if (split == NULL)
return;
/* Bail if trying to void the blank split. */
if (split == blank_split)
return;
/* already voided. */
if (xaccSplitGetReconcile (split) == VREC)
return;
info->trans_expanded = FALSE;
gnc_suspend_gui_refresh ();
trans = xaccSplitGetParent(split);
xaccTransVoid(trans, reason);
/* Check pending transaction */
if (trans == pending_trans)
{
info->pending_trans_guid = *guid_null();
pending_trans = NULL;
}
if (xaccTransIsOpen(trans))
{
PERR("We should not be voiding an open transaction.");
xaccTransCommitEdit(trans);
}
gnc_resume_gui_refresh ();
}
1.7.4