Example #1
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);
}
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(" ");
}