GnuCash 2.3.0
Data Structures | Modules | Files | Typedefs | Enumerations | Functions
Registers, Ledgers and Journals
GUI

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

SplitRegistergnc_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)
Transactiongnc_split_register_get_current_trans (SplitRegister *reg)
Splitgnc_split_register_get_current_trans_split (SplitRegister *reg, VirtualCellLocation *vcell_loc)
Splitgnc_split_register_get_current_split (SplitRegister *reg)
Splitgnc_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)
Splitgnc_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

T* cells are transaction summary cells

#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 Documentation

typedef GtkWidget*(* SRGetParentCallback)(gpointer user_data)

Callback function type

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


Enumeration Type Documentation

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;

Register styles

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

{
    REG_STYLE_LEDGER,
    REG_STYLE_AUTO_LEDGER,
    REG_STYLE_JOURNAL
} SplitRegisterStyle;

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;

Function Documentation

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.

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 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.

Parameters:
rega 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.

Parameters:
rega SplitRegister
Returns:
the Split used as the blank split, or 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.

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

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

{
    Table *table;

    if (reg == NULL)
        return CURSOR_CLASS_NONE;

    table = reg->table;
    if (table == NULL)
        return CURSOR_CLASS_NONE;

    return gnc_split_register_cursor_class (reg, table->current_cursor);
}
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 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.

Parameters:
rega SplitRegister
Returns:
the Transaction at the cursor location, or 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.

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 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.

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

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.

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 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.

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 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.

Parameters:
rega SplitRegister
slista list of splits
default_accountan 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.

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 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.

Parameters:
rega SplitRegister
do_auto_completeTRUE 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".

Parameters:
rega SplitRegister
read_onlyTRUE 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.

Parameters:
rega SplitRegister
template_accountthe 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 ();
}
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines