Esempio n. 1
0
static void add_quickfill_completions(TableLayout *layout, Transaction *trans,
                                      Split *split, gboolean has_last_num)
{
    Split *s;
    int i = 0;

    gnc_quickfill_cell_add_completion(
        (QuickFillCell *) gnc_table_layout_get_cell(layout, DESC_CELL),
        xaccTransGetDescription(trans));

    gnc_quickfill_cell_add_completion(
        (QuickFillCell *) gnc_table_layout_get_cell(layout, NOTES_CELL),
        xaccTransGetNotes(trans));

    if (!has_last_num)
        gnc_num_cell_set_last_num(
            (NumCell *) gnc_table_layout_get_cell(layout, NUM_CELL),
            gnc_get_num_action(trans, split));

    while ((s = xaccTransGetSplit(trans, i)) != NULL)
    {
        gnc_quickfill_cell_add_completion(
            (QuickFillCell *) gnc_table_layout_get_cell(layout, MEMO_CELL),
            xaccSplitGetMemo(s));
        i++;
    }
}
Esempio n. 2
0
static void
gnc_split_register_load_xfer_cells (SplitRegister *reg, Account *base_account)
{
    Account *root = NULL;
    QuickFill *qf;
    ComboCell *cell;
    GtkListStore *store;

    if (base_account)
        root = gnc_account_get_root(base_account);
    if (root == NULL)
        root = gnc_get_current_root_account();
    if (root == NULL)
        return;

    qf = gnc_get_shared_account_name_quickfill (root, QKEY, skip_cb, NULL);
    store = gnc_get_shared_account_name_list_store (root, QKEY, skip_cb, NULL);

    cell = (ComboCell *)
           gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
    gnc_combo_cell_use_quickfill_cache (cell, qf);
    gnc_combo_cell_use_list_store_cache (cell, store);

    cell = (ComboCell *)
           gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL);
    gnc_combo_cell_use_quickfill_cache (cell, qf);
    gnc_combo_cell_use_list_store_cache (cell, store);
}
Esempio n. 3
0
static void
load_xfer_type_cells (GncEntryLedger *ledger)
{
    Account *root;
    ComboCell *cell;
    QuickFill *qf = NULL;
    GtkListStore *store = NULL;

    root = gnc_book_get_root_account (ledger->book);
    if (root == NULL) return;

    /* Use a common, shared quickfill.  For the ORDER or INVOICE,
     * ledgers, we don't want expense-type accounts in the menu.
     * For BILL, etc. then leave out the income types.
     */
    switch (ledger->type)
    {
    case GNCENTRY_ORDER_ENTRY:
    case GNCENTRY_ORDER_VIEWER:
    case GNCENTRY_INVOICE_ENTRY:
    case GNCENTRY_INVOICE_VIEWER:
    case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
    case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
        qf = gnc_get_shared_account_name_quickfill (root, IKEY,
                skip_expense_acct_cb, NULL);
        store = gnc_get_shared_account_name_list_store (root, IKEY,
                skip_expense_acct_cb, NULL);
        break;

    case GNCENTRY_BILL_ENTRY:
    case GNCENTRY_BILL_VIEWER:
    case GNCENTRY_EXPVOUCHER_ENTRY:
    case GNCENTRY_EXPVOUCHER_VIEWER:
    case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
    case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
    case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
    case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
    case GNCENTRY_NUM_REGISTER_TYPES:
        qf = gnc_get_shared_account_name_quickfill (root, EKEY,
                skip_income_acct_cb, NULL);
        store = gnc_get_shared_account_name_list_store (root, EKEY,
                skip_income_acct_cb, NULL);
        break;
    default:
	PWARN ("Bad GncEntryLedgerType");
	break;
    }

    cell = (ComboCell *)
           gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
    gnc_combo_cell_use_quickfill_cache (cell, qf);
    gnc_combo_cell_use_list_store_cache (cell, store);

    cell = (ComboCell *)
           gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
    gnc_combo_cell_use_quickfill_cache (cell, qf);
    gnc_combo_cell_use_list_store_cache (cell, store);
}
Esempio n. 4
0
static void load_payment_type_cells (GncEntryLedger *ledger)
{
    ComboCell *cell;
    const GncOwner *owner;
    GncEmployee *employee;

    cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
            ENTRY_PAYMENT_CELL);
    if (!cell) return;

    if (!ledger->invoice) return;

    owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
    if (gncOwnerGetType (owner) != GNC_OWNER_EMPLOYEE)
        return;

    employee = gncOwnerGetEmployee (owner);
    g_return_if_fail (employee);

    gnc_combo_cell_clear_menu (cell);
    gnc_combo_cell_add_menu_item (cell, _("Cash"));

    if (gncEmployeeGetCCard (employee))
        gnc_combo_cell_add_menu_item (cell, _("Charge"));
}
Esempio n. 5
0
static void
change_account_separator (SRInfo *info, Table *table, SplitRegister *reg)
{
    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);
}
gnc_numeric
gnc_split_register_debcred_cell_value (SplitRegister *reg)
{
    PriceCell *cell;
    gnc_numeric new_amount;
    gnc_numeric credit;
    gnc_numeric debit;

    cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
            CRED_CELL);
    credit = gnc_price_cell_get_value (cell);

    cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
            DEBT_CELL);
    debit  = gnc_price_cell_get_value (cell);

    new_amount = gnc_numeric_sub_fixed (debit, credit);

    return new_amount;
}
static gnc_numeric
gnc_split_register_get_rate_cell (SplitRegister *reg, const char *cell_name)
{
    PriceCell *rate_cell;

    rate_cell = (PriceCell*) gnc_table_layout_get_cell (reg->table->layout,
                cell_name);
    if (rate_cell)
        return gnc_price_cell_get_value (rate_cell);

    /* Uhh, just return '1' */
    return gnc_numeric_create (100, 100);
}
Esempio n. 8
0
static void load_discount_how_cells (GncEntryLedger *ledger)
{
    RecnCell *cell;

    if (!ledger) return;

    cell = (RecnCell *)
           gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DISHOW_CELL);

    if (!cell) return;

    gnc_recn_cell_set_valid_flags (cell, "123", '1');
    gnc_recn_cell_set_flag_order (cell, "123");
    gnc_recn_cell_set_string_getter (cell, gnc_entry_ledger_how_string_getter);
}
Esempio n. 9
0
static void
gnc_split_register_load_type_cells (SplitRegister *reg)
{
    RecnCell *cell;

    if (!reg) return;

    cell = (RecnCell *)
           gnc_table_layout_get_cell (reg->table->layout, TYPE_CELL);

    if (!cell) return;

    /* FIXME: These should get moved to an i18n function */
    gnc_recn_cell_set_valid_flags (cell, "IP?", 'I');
    gnc_recn_cell_set_flag_order (cell, "IP");
}
Esempio n. 10
0
static void load_taxtable_type_cells (GncEntryLedger *ledger)
{
    GList *list;
    ComboCell *cell;

    cell = (ComboCell *)
           gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
    gnc_combo_cell_clear_menu (cell);

    list = gncTaxTableGetTables (ledger->book);
    for ( ; list ; list = list->next )
    {
        GncTaxTable *table = list->data;
        const char *name = gncTaxTableGetName (table);
        if (name != NULL)
            gnc_combo_cell_add_menu_item (cell, (char*)name);
    }
}
Esempio n. 11
0
static void
gnc_split_register_load_recn_cells (SplitRegister *reg)
{
    RecnCell *cell;
    const char * s;

    if (!reg) return;

    cell = (RecnCell *)
           gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);

    if (!cell) return;

    s = gnc_get_reconcile_valid_flags ();
    gnc_recn_cell_set_valid_flags (cell, s, *s);
    gnc_recn_cell_set_flag_order (cell, gnc_get_reconcile_flag_order ());
    gnc_recn_cell_set_string_getter (cell, gnc_get_reconcile_str);
}
Esempio n. 12
0
static gboolean
gnc_entry_ledger_verify_acc_cell_ok (GncEntryLedger *ledger,
                                     const char *cell_name,
                                     const char *cell_msg)
{
    ComboCell *cell;
    const char *name;

    cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
            cell_name);
    g_return_val_if_fail (cell, TRUE);
    name = cell->cell.value;
    if (!name || *name == '\0')
    {
        const char *format = ("%s %s");
        const char *gen_msg = _("Invalid Entry: You need to supply an account in the right currency for this position.");

        gnc_error_dialog (ledger->parent, format, gen_msg, cell_msg);
        return FALSE;
    }
    return TRUE;
}
Esempio n. 13
0
static void
load_description_cell (GncEntryLedger *ledger)
{
    QuickFill *shared_quickfill;
    QuickFillCell *cell;

    switch (ledger->type)
    {
    case GNCENTRY_INVOICE_ENTRY:
    case GNCENTRY_INVOICE_VIEWER:
    case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
    case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
        shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_INVOICES, TRUE);
        break;
    default:
        shared_quickfill = gnc_get_shared_entry_desc_quickfill(ledger->book, DESC_QF_KEY_BILLS, FALSE);
        break;
    };

    cell = (QuickFillCell *)
           gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DESC_CELL);
    gnc_quickfill_cell_use_quickfill_cache (cell, shared_quickfill);
}
Esempio n. 14
0
/* XXX This code is a cut-n-paste job from the SplitRegister code;
 * the split-register should be generalized to the point where a cut-n-paste
 * like this isn't required, and this should be trashed.
 */
void gnc_entry_ledger_load (GncEntryLedger *ledger, GList *entry_list)
{
    GncEntry *blank_entry, *find_entry;
    CursorBuffer *cursor_buffer;
    Table *table;

    GList *node;
    CellBlock *cursor_header, *cursor;
    VirtualCellLocation vcell_loc;
    VirtualLocation save_loc;
    gboolean start_primary_color = TRUE;

    int new_entry_row = -1;

    if (!ledger) return;

    /* Load up cells */
    load_discount_type_cells (ledger);
    load_discount_how_cells (ledger);
    gnc_entry_ledger_load_xfer_cells (ledger);

    blank_entry = gnc_entry_ledger_get_blank_entry (ledger);

    if (blank_entry == NULL && ledger->invoice == NULL && entry_list == NULL)
        return;

    if (blank_entry == NULL && ledger->invoice)
    {
        switch (ledger->type)
        {
        case GNCENTRY_ORDER_ENTRY:
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_BILL_ENTRY:
        case GNCENTRY_EXPVOUCHER_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
        case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
        case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:

            gnc_suspend_gui_refresh ();

            blank_entry = gncEntryCreate (ledger->book);
            gncEntrySetDateGDate (blank_entry, &ledger->last_date_entered);
            ledger->blank_entry_guid = *gncEntryGetGUID (blank_entry);

            gnc_resume_gui_refresh ();

            /* The rest of this does not apply to expense vouchers */
            if (ledger->type != GNCENTRY_EXPVOUCHER_ENTRY)
            {
                const GncOwner *owner = gncOwnerGetEndOwner (gncInvoiceGetOwner (ledger->invoice));
                GncTaxTable *table = NULL;
                GncTaxIncluded taxincluded_p = GNC_TAXINCLUDED_USEGLOBAL;
                gboolean taxincluded = FALSE;
                gnc_numeric discount = gnc_numeric_zero ();
                gnc_numeric price = gnc_numeric_zero ();

                /* Determine the Price from Customer's or Vendor's Job */
                switch (gncOwnerGetType (gncInvoiceGetOwner (ledger->invoice)))
                {
                case GNC_OWNER_JOB:
                    price = gncJobGetRate( gncOwnerGetJob (gncInvoiceGetOwner (ledger->invoice)));
                    break;
                default:
                    break;
                }

                /* Determine the TaxIncluded and Discount values */
                switch (gncOwnerGetType (owner))
                {
                case GNC_OWNER_CUSTOMER:
                    taxincluded_p = gncCustomerGetTaxIncluded (owner->owner.customer);
                    discount = gncCustomerGetDiscount (owner->owner.customer);
                    break;
                case GNC_OWNER_VENDOR:
                    taxincluded_p = gncVendorGetTaxIncluded (owner->owner.vendor);
                    break;
                default:
                    break;
                }

                /* Compute the default taxincluded */
                switch (taxincluded_p)
                {
                case GNC_TAXINCLUDED_YES:
                    taxincluded = TRUE;
                    break;
                case GNC_TAXINCLUDED_NO:
                    taxincluded = FALSE;
                    break;
                case GNC_TAXINCLUDED_USEGLOBAL:
                    if (ledger->prefs_group)
                    {
                        taxincluded = gnc_prefs_get_bool (ledger->prefs_group, GNC_PREF_TAX_INCL);
                    }
                    else
                    {
                        taxincluded = FALSE;
                    }
                    break;
                }

                /* Compute the proper taxtable */
                switch (gncOwnerGetType (owner))
                {
                case GNC_OWNER_CUSTOMER:
                    table = gnc_business_get_default_tax_table (ledger->book,
                            GNC_OWNER_CUSTOMER);

                    if (gncCustomerGetTaxTableOverride (owner->owner.customer))
                        table = gncCustomerGetTaxTable (owner->owner.customer);
                    break;

                case GNC_OWNER_VENDOR:
                    table = gnc_business_get_default_tax_table (ledger->book,
                            GNC_OWNER_VENDOR);

                    if (gncVendorGetTaxTableOverride (owner->owner.vendor))
                        table = gncVendorGetTaxTable (owner->owner.vendor);
                    break;

                default:
                    break;
                }

                if (ledger->is_cust_doc)
                {
                    gncEntrySetInvTaxTable (blank_entry, table);
                    gncEntrySetInvTaxIncluded (blank_entry, taxincluded);
                    gncEntrySetInvDiscount (blank_entry, discount);
                    gncEntrySetInvPrice (blank_entry, price);
                }
                else
                {
                    gncEntrySetBillTaxTable (blank_entry, table);
                    gncEntrySetBillTaxIncluded (blank_entry, taxincluded);
                    gncEntrySetBillPrice (blank_entry, price);
                }
            }

            break;
        default:
            ledger->blank_entry_guid = *guid_null ();
            break;
        }
        ledger->blank_entry_edited = FALSE;
    }

    table = ledger->table;

    gnc_table_leave_update (table, table->current_cursor_loc);
    save_loc = table->current_cursor_loc;

    /* Figure out where we are going to */
    if (ledger->traverse_to_new)
    {
        find_entry = blank_entry;
    }
    else if (ledger->hint_entry)
    {
        find_entry = ledger->hint_entry;
    }
    else
    {
        find_entry = gnc_entry_ledger_get_current_entry(ledger);
        /* XXX: get current entry (cursor_hint_xxx) */
    }

    /* If the current cursor has changed we save the values for later
     * possible restoration. */
    if (gnc_table_current_cursor_changed (table, TRUE) &&
            (find_entry == gnc_entry_ledger_get_current_entry (ledger)))
    {
        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;

        virt_loc.vcell_loc.virt_row = -1;
        virt_loc.vcell_loc.virt_col = -1;
        virt_loc.phys_row_offset = -1;
        virt_loc.phys_col_offset = -1;

        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 */
    table->model->dividing_row_upper = -1;
    table->model->dividing_row = -1;
    table->model->dividing_row_lower = -1;
    cursor = gnc_table_layout_get_cursor (table->layout, "cursor");

    /* Populate the table */
    for (node = entry_list; node; node = node->next)
    {
        GncEntry *entry = node->data;

        /* Don't load the blank entry */
        if (entry == blank_entry)
            continue;

        /* If this is the first load of the ledger, fill the quickfill cells */
        {
            /* XXX */
        }

        if (entry == find_entry)
            new_entry_row = vcell_loc.virt_row;

        gnc_table_set_vcell (table, cursor, gncEntryGetGUID (entry),
                             TRUE, start_primary_color, vcell_loc);
        vcell_loc.virt_row++;

        /* Flip color for the next guy */
        start_primary_color = !start_primary_color;
    }

    /* Add the blank entry at the end. */
    if (blank_entry)
    {
        gnc_table_set_vcell (table, cursor, gncEntryGetGUID (blank_entry),
                             TRUE, start_primary_color, vcell_loc);

        if (find_entry == blank_entry)
            new_entry_row = vcell_loc.virt_row;

        vcell_loc.virt_row++;
    }

    /* Resize the table */
    gnc_table_set_size (table, vcell_loc.virt_row, 1);

    /* Restore the cursor to its rightful position */
    if (new_entry_row > 0)
        save_loc.vcell_loc.virt_row = new_entry_row;

    if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
    {
        gnc_table_move_cursor_gui (table, save_loc);

        if (find_entry == gnc_entry_ledger_get_current_entry (ledger))
            gnc_table_restore_current_cursor (table, cursor_buffer);
    }

    gnc_cursor_buffer_destroy (cursor_buffer);
    cursor_buffer = NULL;

    /* Reset the ledger */
    ledger->traverse_to_new = FALSE;
    ledger->hint_entry = NULL;

    /* Set the cell fractions */


    gnc_table_refresh_gui (table, TRUE);
    gnc_entry_ledger_show_entry (ledger, table->current_cursor_loc.vcell_loc);

    /* Set completion character */
    gnc_combo_cell_set_complete_char
    ((ComboCell *)
     gnc_table_layout_get_cell (table->layout, ENTRY_IACCT_CELL),
     gnc_get_account_separator ());

    gnc_combo_cell_set_complete_char
    ((ComboCell *)
     gnc_table_layout_get_cell (table->layout, ENTRY_BACCT_CELL),
     gnc_get_account_separator ());

    /* enable callback for cursor user-driven moves */
    gnc_table_control_allow_move (table->control, TRUE);
}
Esempio n. 15
0
static gboolean gnc_entry_ledger_traverse (VirtualLocation *p_new_virt_loc,
        gncTableTraversalDir dir,
        gpointer user_data)
{
    GncEntryLedger *ledger = user_data;
    GncEntry *entry, *new_entry;
    gint response;
    VirtualLocation virt_loc;
    int changed;
    char const *cell_name;
    gboolean exact_traversal;

    if (!ledger) return FALSE;

    exact_traversal = (dir == GNC_TABLE_TRAVERSE_POINTER);

    entry = gnc_entry_ledger_get_current_entry (ledger);
    if (!entry)
        return FALSE;

    /* no changes, make sure we aren't going off the end */
    changed = gnc_table_current_cursor_changed (ledger->table, FALSE);
    if (!changed)
        return FALSE;

    virt_loc = *p_new_virt_loc;

    cell_name = gnc_table_get_current_cell_name (ledger->table);

    /* See if we are leaving the account field */
    do
    {
        ComboCell *cell;
        char *name;
        char *cell_name = NULL;

        switch (ledger->type)
        {
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_INVOICE_VIEWER:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_VIEWER:
            cell_name = ENTRY_IACCT_CELL;
            break;
        case GNCENTRY_BILL_ENTRY:
        case GNCENTRY_BILL_VIEWER:
        case GNCENTRY_EXPVOUCHER_ENTRY:
        case GNCENTRY_EXPVOUCHER_VIEWER:
        case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
        case GNCENTRY_VEND_CREDIT_NOTE_VIEWER:
        case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
        case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER:
            cell_name = ENTRY_BACCT_CELL;
            break;
        default:
            g_warning ("Unhandled ledger type");
            break;
        }

        if (!cell_name)
            break;

        if (!gnc_cell_name_equal (cell_name, cell_name))
            break;

        if (!gnc_table_layout_get_cell_changed (ledger->table->layout,
                                                cell_name, FALSE))
            break;

        cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
                cell_name);
        if (!cell)
            break;

        name = cell->cell.value;
        if (!name || *name == '\0')
            break;

        /* Create the account if necessary. Also checks for a placeholder */
        if (!gnc_entry_ledger_get_account_by_name (ledger, (BasicCell *) cell,
                cell->cell.value,
                &ledger->full_refresh))
            return TRUE;

    }
    while (FALSE);


    /* See if we are leaving the TaxTable field */
    do
    {
        ComboCell *cell;
        GncTaxTable *table;
        char *name;

        if (!gnc_cell_name_equal (cell_name, ENTRY_TAXTABLE_CELL))
            break;

        if (!gnc_table_layout_get_cell_changed (ledger->table->layout,
                                                ENTRY_TAXTABLE_CELL, FALSE))
            break;

        cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout,
                ENTRY_TAXTABLE_CELL);
        if (!cell)
            break;

        name = cell->cell.value;
        if (!name || *name == '\0')
            break;

        table = gncTaxTableLookupByName (ledger->book, cell->cell.value);
        if (table)
            break;

        {
            const char *format = _("The tax table %s does not exist. "
                                   "Would you like to create it?");
            if (!gnc_verify_dialog (ledger->parent, TRUE, format, name))
                break;
        }

        ledger->full_refresh = FALSE;

        table = gnc_ui_tax_table_new_from_name (ledger->book, name);
        if (!table)
            break;

        ledger->full_refresh = TRUE;

        name = (char *)gncTaxTableGetName (table);
        gnc_combo_cell_set_value (cell, name);
        gnc_basic_cell_set_changed (&cell->cell, TRUE);

    }
    while (FALSE);


    /* See if we are tabbing off the end of the very last line
     * (i.e. the blank entry)
     */
    do
    {
        VirtualLocation virt_loc;

        if (!changed && !ledger->blank_entry_edited)
            break;

        if (dir != GNC_TABLE_TRAVERSE_RIGHT)
            break;

        virt_loc = ledger->table->current_cursor_loc;
        if (gnc_table_move_vertical_position (ledger->table, &virt_loc, 1))
            break;

        virt_loc = ledger->table->current_cursor_loc;
        if (gnc_table_move_tab (ledger->table, &virt_loc, TRUE))
            break;

        *p_new_virt_loc = ledger->table->current_cursor_loc;

        /* Yep, we're trying to leave the blank entry -- make sure
         * we are allowed to do so by verifying the current cursor.
         * If the current cursor is ok, then move on!
         */

        /* Verify that the cursor is ok.  If we can't save the cell, don't move! */
        if (!gnc_entry_ledger_verify_can_save (ledger))
        {
            return TRUE;
        }

        (p_new_virt_loc->vcell_loc.virt_row)++;
        p_new_virt_loc->phys_row_offset = 0;
        p_new_virt_loc->phys_col_offset = 0;

        ledger->traverse_to_new = TRUE;

        /* If we're here, we're tabbing off the end of the 'blank entry' */
        return FALSE;

    }
    while (FALSE);

    /* Now see if we are changing cursors. If not, we may be able to
     * auto-complete. */
    if (!gnc_table_virtual_cell_out_of_bounds (ledger->table,
            virt_loc.vcell_loc))
    {
        if (gnc_entry_ledger_auto_completion (ledger, dir, p_new_virt_loc))
            return FALSE;
    }

    /* Check for going off the end */
    gnc_table_find_close_valid_cell (ledger->table, &virt_loc, exact_traversal);

    /* Same entry, no problem -- we're just moving backwards in the cursor */
    new_entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);
    if (entry == new_entry)
    {
        *p_new_virt_loc = virt_loc;

        return FALSE;
    }

    /* If we are here, then we are trying to leave the cursor.  Make sure
     * the cursor we are leaving is valid.  If so, ask the user if the
     * changes should be recorded.  If not, don't go anywhere.
     */

    /* Verify this cursor -- if it's not valid, don't let them move on */
    if (!gnc_entry_ledger_verify_can_save (ledger))
    {
        *p_new_virt_loc = ledger->table->current_cursor_loc;
        return TRUE;
    }

    /*
     * XXX  GNCENTRY_INVOICE_EDIT processing to be added:
     * 1) check if the qty field changed.
     * 2) if so, check if this entry is part of an order.
     * 3) if so, ask if they want to change the entry or
     *    split the entry into two parts.
     */

    /* Ok, we are changing lines and the current entry has
     * changed. We only ask them what they want to do in
     * limited cases -- usually just let the change go through.
     */
    {
        GtkWidget *dialog;
        const char *title = _("Save the current entry?");
        const char *message =
            _("The current entry has been changed.  However, this entry is "
              "part of an existing order. Would you like to record the change "
              "and effectively change your order?");

        switch (ledger->type)
        {
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
            if (gncEntryGetOrder (entry) != NULL)
            {
                dialog = gtk_message_dialog_new(GTK_WINDOW(ledger->parent),
                                                GTK_DIALOG_DESTROY_WITH_PARENT,
                                                GTK_MESSAGE_QUESTION,
                                                GTK_BUTTONS_NONE,
                                                "%s", title);
                gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
                        "%s", message);
                gtk_dialog_add_buttons(GTK_DIALOG(dialog),
                                       _("_Don't Record"), GTK_RESPONSE_REJECT,
                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                       _("_Record"), GTK_RESPONSE_ACCEPT,
                                       NULL);
                response = gnc_dialog_run(GTK_DIALOG(dialog), "invoice_entry_changed");
                gtk_widget_destroy(dialog);
                break;
            }

            /* FALL THROUGH */
        default:
            response = GTK_RESPONSE_ACCEPT;
            break;
        }
    }

    switch (response)
    {
    case GTK_RESPONSE_ACCEPT:
        break;

    case GTK_RESPONSE_REJECT:
    {
        VirtualCellLocation vcell_loc;
        GncEntry *new_entry;

        new_entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc);

        gnc_entry_ledger_cancel_cursor_changes (ledger);

        if (gnc_entry_ledger_find_entry (ledger, new_entry, &vcell_loc))
            virt_loc.vcell_loc = vcell_loc;

        gnc_table_find_close_valid_cell (ledger->table, &virt_loc,
                                         exact_traversal);

        *p_new_virt_loc = virt_loc;
    }

    break;

    case GTK_RESPONSE_CANCEL:
    default:
        return TRUE;
    }

    return FALSE;
}
Esempio n. 16
0
static void gnc_entry_ledger_save_cells (gpointer save_data,
        gpointer user_data)
{
    GncEntryLedger *ledger = user_data;
    GncEntry *entry = save_data;

    g_return_if_fail (entry != NULL);

    /* copy the contents from the cursor to the split */

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_IACCT_CELL, TRUE))
    {
        Account *acc;

        acc = gnc_entry_ledger_get_account (ledger, ENTRY_IACCT_CELL);

        if (acc != NULL)
            gncEntrySetInvAccount (entry, acc);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_BACCT_CELL, TRUE))
    {
        Account *acc;

        acc = gnc_entry_ledger_get_account (ledger, ENTRY_BACCT_CELL);

        if (acc != NULL)
            gncEntrySetBillAccount (entry, acc);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_ACTN_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_ACTN_CELL);
        gncEntrySetAction (entry, value);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DATE_CELL, TRUE))
    {
        BasicCell *cell;
        GDate date;

        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_DATE_CELL);

        /* commit any pending changes */
        gnc_date_cell_commit ((DateCell *) cell);

        gnc_date_cell_get_date_gdate ((DateCell *) cell, &date);
        gncEntrySetDateGDate (entry, &date);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DESC_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_DESC_CELL);
        gncEntrySetDescription (entry, value);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISC_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_DISC_CELL, &amount))
            gncEntrySetInvDiscount (entry, amount);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISTYPE_CELL, TRUE))
    {
        gint type;

        type = gnc_entry_ledger_get_type (ledger, ENTRY_DISTYPE_CELL);

        if (type != -1)
            gncEntrySetInvDiscountType (entry, type);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_DISHOW_CELL, TRUE))
    {
        gint type;

        type = gnc_entry_ledger_get_type (ledger, ENTRY_DISHOW_CELL);

        if (type != -1)
            gncEntrySetInvDiscountHow (entry, type);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_QTY_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_QTY_CELL, &amount))
        {
            gncEntrySetDocQuantity (entry, amount, ledger->is_credit_note);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_BILLABLE_CELL, TRUE))
    {
        gboolean billable;

        billable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_BILLABLE_CELL);
        gncEntrySetBillable (entry, billable);
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_PAYMENT_CELL, TRUE))
    {
        const char *value;

        value = gnc_table_layout_get_cell_value (ledger->table->layout,
                ENTRY_PAYMENT_CELL);
        if (!g_strcmp0 (value, _("Cash")))
            gncEntrySetBillPayment (entry, GNC_PAYMENT_CASH);
        else if (!g_strcmp0 (value, _("Charge")))
            gncEntrySetBillPayment (entry, GNC_PAYMENT_CARD);
        else
            g_warning ("Invalid Payment cell: %s", value ? value : "(null)");
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_PRIC_CELL, TRUE))
    {
        gnc_numeric amount;

        if (gnc_entry_ledger_get_numeric (ledger, ENTRY_PRIC_CELL, &amount))
        {
            if (ledger->is_cust_doc)
                gncEntrySetInvPrice (entry, amount);
            else
                gncEntrySetBillPrice (entry, amount);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXABLE_CELL, TRUE))
    {
        gboolean taxable;

        taxable = gnc_entry_ledger_get_checkmark (ledger, ENTRY_TAXABLE_CELL);
        if (ledger->is_cust_doc)
            gncEntrySetInvTaxable (entry, taxable);
        else
            gncEntrySetBillTaxable (entry, taxable);
    }

    /* XXX: Only (re-set) these if taxable is TRUE? */
    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXTABLE_CELL, TRUE))
    {
        GncTaxTable *table;

        table = gnc_entry_ledger_get_taxtable (ledger, ENTRY_TAXTABLE_CELL);
        if (table)
        {
            if (ledger->is_cust_doc)
                gncEntrySetInvTaxTable (entry, table);
            else
                gncEntrySetBillTaxTable (entry, table);
        }
    }

    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_TAXINCLUDED_CELL, TRUE))
    {
        gboolean taxincluded;

        taxincluded = gnc_entry_ledger_get_checkmark (ledger,
                      ENTRY_TAXINCLUDED_CELL);
        if (ledger->is_cust_doc)
            gncEntrySetInvTaxIncluded (entry, taxincluded);
        else
            gncEntrySetBillTaxIncluded (entry, taxincluded);
    }

    if (ledger->type == GNCENTRY_INVOICE_ENTRY ||
            ledger->type == GNCENTRY_CUST_CREDIT_NOTE_ENTRY)
    {
        gboolean inv_value;

        inv_value = gnc_entry_ledger_get_checkmark (ledger, ENTRY_INV_CELL);

        if (inv_value)
        {
            /* Add this to the invoice (if it's not already attached) */
            if (gncEntryGetInvoice (entry) == NULL)
                gncInvoiceAddEntry (ledger->invoice, entry);

        }
        else
        {
            /* Remove from the invoice iff we're attached to an order or bill */
            if ((gncEntryGetOrder (entry) != NULL) ||
                    (gncEntryGetBill (entry) != NULL))
                gncInvoiceRemoveEntry (ledger->invoice, entry);
        }
    }
}
Esempio n. 17
0
void
gnc_split_register_load (SplitRegister *reg, GList * slist,
                         Account *default_account)
{
    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 need_divider_upper = FALSE;
    gboolean found_divider_upper = FALSE;
    gboolean found_divider = FALSE;
    gboolean has_last_num = FALSE;
    gboolean multi_line;
    gboolean dynamic;
    gboolean we_own_slist = FALSE;
    gboolean use_autoreadonly = qof_book_uses_autoreadonly(gnc_get_current_book());

    VirtualCellLocation vcell_loc;
    VirtualLocation save_loc;

    int new_trans_split_row = -1;
    int new_trans_row = -1;
    int new_split_row = -1;
    time64 present, autoreadonly_time = 0;

    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)
    {
	/* Wouldn't it be a bug to open the new transaction if there was
	 * already a pending transaction?
	*/
	g_assert(pending_trans == NULL);
	blank_split = create_blank_split (default_account, info);
    }
    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_time64_get_today_end ();
    if (use_autoreadonly)
    {
        GDate *d = qof_book_get_autoreadonly_gdate(gnc_get_current_book());
        // "d" is NULL if use_autoreadonly is FALSE
        autoreadonly_time = d ? timespecToTime64(gdate_to_timespec(*d)) : 0;
        g_date_free(d);
    }

    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)
	change_account_separator (info, table, reg);

    table->model->dividing_row_upper = -1;
    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;
	/* If the transaction has only one split, and it's not our
	 * pending_trans, then it's another register's blank split and
	 * we don't want to see it.
	 */
	else if (xaccTransCountSplits (trans) == 1 &&
		 xaccSplitGetAccount (split) == NULL)
	    continue;


        /* 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 &&
                use_autoreadonly &&
                !found_divider_upper)
        {
            if (xaccTransGetDate (trans) >= autoreadonly_time)
            {
                table->model->dividing_row_upper = vcell_loc.virt_row;
                found_divider_upper = TRUE;
            }
            else
            {
                need_divider_upper = TRUE;
            }
        }

        if (info->show_present_divider &&
                !found_divider &&
                (xaccTransGetDate (trans) > present))
        {
            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, split, 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;

    /* No upper divider yet? Store it now */
    if (info->show_present_divider &&
            use_autoreadonly &&
            !found_divider_upper && need_divider_upper)
    {
        table->model->dividing_row_upper = vcell_loc.virt_row;
        found_divider_upper = 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;

        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;

	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;

    update_info (info, reg);

    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(" ");
}
Esempio n. 18
0
static gboolean
gnc_entry_ledger_auto_completion (GncEntryLedger *ledger,
                                  gncTableTraversalDir dir,
                                  VirtualLocation *p_new_virt_loc)
{
    GncEntry *entry;
    GncEntry *blank_entry;
    GncEntry *auto_entry;
    const char* cell_name;
    const char *desc;
    BasicCell *cell = NULL;
    char *account_name = NULL;
    char *new_value = NULL;

    g_assert(ledger);
    g_assert(ledger->table);
    blank_entry = gnc_entry_ledger_get_blank_entry (ledger);

    /* auto-completion is only triggered by a tab out */
    if (dir != GNC_TABLE_TRAVERSE_RIGHT)
        return FALSE;

    entry = gnc_entry_ledger_get_current_entry (ledger);
    if (entry == NULL)
        return FALSE;

    cell_name = gnc_table_get_current_cell_name (ledger->table);

    /* Auto-completion is done only in an entry ledger */
    switch (ledger->type)
    {
    case GNCENTRY_ORDER_ENTRY:
    case GNCENTRY_INVOICE_ENTRY:
    case GNCENTRY_BILL_ENTRY:
    case GNCENTRY_EXPVOUCHER_ENTRY:
    case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
    case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
    case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
        break;
    default:
        return FALSE;
    }

    /* Further conditions before we actually do auto-completion: */
    /* There must be a blank entry */
    if (blank_entry == NULL)
        return FALSE;

    /* we must be on the blank entry */
    if (entry != blank_entry)
        return FALSE;

    /* and leaving the description cell */
    if (!gnc_cell_name_equal (cell_name, ENTRY_DESC_CELL))
        return FALSE;

    /* nothing but the date and description should be changed */
    /* FIXME, this should be refactored. */
    if (gnc_table_layout_get_cell_changed (ledger->table->layout,
                                           ENTRY_ACTN_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_QTY_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_PRIC_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_DISC_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_DISTYPE_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_DISHOW_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_IACCT_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_BACCT_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_TAXABLE_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_TAXINCLUDED_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_TAXTABLE_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_VALUE_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_TAXVAL_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_BILLABLE_CELL, TRUE)
            || gnc_table_layout_get_cell_changed (ledger->table->layout,
                    ENTRY_PAYMENT_CELL, TRUE))
        return FALSE;

    /* and the description should indeed be changed */
    if (!gnc_table_layout_get_cell_changed (ledger->table->layout,
                                            ENTRY_DESC_CELL, TRUE))
        return FALSE;

    /* to a non-empty value */
    desc = gnc_table_layout_get_cell_value (ledger->table->layout, ENTRY_DESC_CELL);
    if ((desc == NULL) || (*desc == '\0'))
        return FALSE;

    /* Ok, we are sure we want to trigger auto-completion. Now find an
     * entry to copy the values from.  FIXME: Currently we only use
     * the entries from the current invoice/bill, but it would be
     * better to draw this from a larger set of entries. */
    auto_entry =
        /* Use this for book-wide auto-completion of the invoice entries */
        find_entry_in_book_by_desc(ledger, desc);
    /* #else */
    /*     gnc_find_entry_in_reg_by_desc(ledger, desc); */
    /* #endif */

    if (auto_entry == NULL)
        return FALSE;

    /* now perform the completion */
    gnc_suspend_gui_refresh ();

    /* Auto-complete the action field */
    cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_ACTN_CELL);
    set_value_combo_cell (cell, gncEntryGetAction (auto_entry));

    /* Auto-complete the account field */
    switch (ledger->type)
    {
    case GNCENTRY_INVOICE_ENTRY:
    case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL);
        account_name = gnc_get_account_name_for_register (gncEntryGetInvAccount(auto_entry));
        break;
    case GNCENTRY_EXPVOUCHER_ENTRY:
    case GNCENTRY_BILL_ENTRY:
    case GNCENTRY_VEND_CREDIT_NOTE_ENTRY:
    case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY:
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL);
        account_name = gnc_get_account_name_for_register (gncEntryGetBillAccount(auto_entry));
        break;
    case GNCENTRY_ORDER_ENTRY:
    default:
        cell = NULL;
        account_name = NULL;
        break;
    }
    set_value_combo_cell (cell, account_name);
    g_free (account_name);

    /* Auto-complete quantity cell
     * Note: we always autofill a positive quantity value. This allows us to
     * - reuse invoice entries on credit note ledgers, meaning you can credit
     *   some invoice entry via autofill without having to manually fix the sign
     *   on the credit note.
     * - autofill credit note entries on other credit note entries (without having
     *   to juggle sign reversals internally)
     * - autofill credit note entries on invoice ledgers
     *
     * Disadvantage: invoice entries with explicitly set negative quantities will
     * be autofilled to positive quantities in later uses. But it seems less common
     * to me to require a negative entry again next time.
     */
    cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_QTY_CELL);
    set_value_price_cell (cell, gnc_numeric_abs(gncEntryGetQuantity (auto_entry)));

    /* Auto-complete price cell */
    {
        gnc_numeric price;
        switch (ledger->type)
        {
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
            price = gncEntryGetInvPrice (auto_entry);
            break;
        default:
            price = gncEntryGetBillPrice (auto_entry);
        }

        /* Auto-complete price cell */
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_PRIC_CELL);
        set_value_price_cell (cell, price);
    }

    /* We intentionally skip the discount column */

    /* Taxable?, Tax-include?, Tax table */
    {
        gboolean taxable, taxincluded;
        GncTaxTable *taxtable;
        switch (ledger->type)
        {
        case GNCENTRY_INVOICE_ENTRY:
        case GNCENTRY_CUST_CREDIT_NOTE_ENTRY:
            taxable = gncEntryGetInvTaxable (auto_entry);
            taxincluded = gncEntryGetInvTaxIncluded (auto_entry);
            taxtable = gncEntryGetInvTaxTable (auto_entry);
            break;
        default:
            taxable = gncEntryGetBillTaxable (auto_entry);
            taxincluded = gncEntryGetBillTaxIncluded (auto_entry);
            taxtable = gncEntryGetBillTaxTable (auto_entry);
        }

        /* Taxable? cell */
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXABLE_CELL);
        gnc_checkbox_cell_set_flag ((CheckboxCell *) cell, taxable);
        gnc_basic_cell_set_changed (cell, TRUE);

        /* taxincluded? cell */
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXINCLUDED_CELL);
        gnc_checkbox_cell_set_flag ((CheckboxCell *) cell, taxincluded);
        gnc_basic_cell_set_changed (cell, TRUE);

        /* Taxable? cell */
        cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL);
        set_value_combo_cell(cell, gncTaxTableGetName (taxtable));
    }


    gnc_resume_gui_refresh ();

    /* now move to the non-empty amount column unless config setting says not */
    if ( !gnc_gconf_get_bool(GCONF_GENERAL_REGISTER,
                             "tab_includes_transfer_on_memorised", NULL) )
    {
        VirtualLocation new_virt_loc;
        const char *cell_name = ENTRY_QTY_CELL;

        if (gnc_table_get_current_cell_location (ledger->table, cell_name,
                &new_virt_loc))
            *p_new_virt_loc = new_virt_loc;
    }

    return TRUE;
}