/*
 * Instance initialization
 */
static void
gnc_item_edit_init (GncItemEdit *item_edit)
{
    /* Set invalid values so that we know when we have been fully
           initialized */
    gtk_orientable_set_orientation (GTK_ORIENTABLE(item_edit),
                                    GTK_ORIENTATION_HORIZONTAL);

    item_edit->sheet = NULL;
    item_edit->editor = NULL;

    item_edit->is_popup = FALSE;
    item_edit->show_popup = FALSE;

    item_edit->popup_toggle.ebox = NULL;
    item_edit->popup_toggle.tbutton = NULL;
    item_edit->popup_toggle.arrow_down = TRUE;
    item_edit->popup_toggle.signals_connected = FALSE;

    item_edit->popup_item = NULL;
    item_edit->popup_get_height = NULL;
    item_edit->popup_autosize = NULL;
    item_edit->popup_set_focus = NULL;
    item_edit->popup_post_show = NULL;
    item_edit->popup_user_data = NULL;

    item_edit->style = NULL;

    gnc_virtual_location_init(&item_edit->virt_loc);
}
Example #2
0
static void
gnc_table_init (Table * table)
{
    table->num_virt_rows = -1;
    table->num_virt_cols = -1;

    table->current_cursor = NULL;

    gnc_virtual_location_init (&table->current_cursor_loc);

    /* initialize private data */

    table->virt_cells = NULL;
    table->ui_data = NULL;
}
Example #3
0
void
gnc_table_set_size (Table * table, int virt_rows, int virt_cols)
{
    /* Invalidate the current cursor position, if the array is
     * shrinking. This must be done since the table is probably
     * shrinking because some rows were deleted, and the cursor
     * could be on the deleted rows. */
    if ((virt_rows < table->num_virt_rows) ||
            (virt_cols < table->num_virt_cols))
    {
        gnc_virtual_location_init (&table->current_cursor_loc);
        table->current_cursor = NULL;
    }

    gnc_table_resize (table, virt_rows, virt_cols);
}
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(" ");
}
Example #5
0
static void
gnc_table_move_cursor_internal (Table *table,
                                VirtualLocation new_virt_loc,
                                gboolean do_move_gui)
{
    int cell_row, cell_col;
    VirtualLocation virt_loc;
    VirtualCell *vcell;
    CellBlock *curs;

    ENTER("new_virt=(%d %d) do_move_gui=%d\n",
          new_virt_loc.vcell_loc.virt_row,
          new_virt_loc.vcell_loc.virt_col, do_move_gui);

    /* call the callback, allowing the app to commit any changes
     * associated with the current location of the cursor. Note that
     * this callback may recursively call this routine. */
    if (table->control->move_cursor && table->control->allow_move)
    {
        table->control->move_cursor (&new_virt_loc, table->control->user_data);

        /* The above callback can cause this routine to be called
         * recursively. As a result of this recursion, the cursor may
         * have gotten repositioned. We need to make sure we make
         * passive again. */
        if (do_move_gui)
            gnc_table_refresh_current_cursor_gui (table, FALSE);
    }

    /* invalidate the cursor for now; we'll fix it back up below */
    gnc_virtual_location_init (&table->current_cursor_loc);

    curs = table->current_cursor;
    table->current_cursor = NULL;

    /* check for out-of-bounds conditions (which may be deliberate) */
    if ((new_virt_loc.vcell_loc.virt_row < 0) ||
            (new_virt_loc.vcell_loc.virt_col < 0))
    {
        /* if the location is invalid, then we should take this
         * as a command to unmap the cursor gui. */
        if (do_move_gui && curs)
        {
            for (cell_row = 0; cell_row < curs->num_rows; cell_row++)
                for (cell_col = 0; cell_col < curs->num_cols; cell_col++)
                {
                    BasicCell *cell;

                    cell = gnc_cellblock_get_cell (curs, cell_row, cell_col);
                    if (cell)
                    {
                        cell->changed = FALSE;
                        cell->conditionally_changed = FALSE;

                        if (cell->gui_move)
                            cell->gui_move (cell);
                    }
                }
        }

        LEAVE("out of bounds\n");
        return;
    }

    if (!gnc_table_virtual_loc_valid (table, new_virt_loc, TRUE))
    {
        PWARN("bad table location");
        LEAVE("");
        return;
    }

    /* ok, we now have a valid position. Find the new cursor to use,
     * and initialize its cells */
    vcell = gnc_table_get_virtual_cell (table, new_virt_loc.vcell_loc);
    curs = vcell->cellblock;
    table->current_cursor = curs;

    /* record the new position */
    table->current_cursor_loc = new_virt_loc;

    virt_loc.vcell_loc = new_virt_loc.vcell_loc;

    /* update the cell values to reflect the new position */
    for (cell_row = 0; cell_row < curs->num_rows; cell_row++)
        for (cell_col = 0; cell_col < curs->num_cols; cell_col++)
        {
            BasicCell *cell;
            CellIOFlags io_flags;

            virt_loc.phys_row_offset = cell_row;
            virt_loc.phys_col_offset = cell_col;

            cell = gnc_cellblock_get_cell(curs, cell_row, cell_col);
            if (cell)
            {
                /* if a cell has a GUI, move that first, before setting
                 * the cell value.  Otherwise, we'll end up putting the
                 * new values in the old cell locations, and that would
                 * lead to confusion of all sorts. */
                if (do_move_gui && cell->gui_move)
                    cell->gui_move (cell);

                /* OK, now copy the string value from the table at large
                 * into the cell handler. */
                io_flags = gnc_table_get_io_flags (table, virt_loc);
                if (io_flags & XACC_CELL_ALLOW_SHADOW)
                {
                    const char *entry;
                    gboolean conditionally_changed = FALSE;

                    entry = gnc_table_get_entry_internal (table, virt_loc,
                                                          &conditionally_changed);

                    gnc_basic_cell_set_value (cell, entry);

                    cell->changed = FALSE;
                    cell->conditionally_changed = conditionally_changed;
                }
            }
        }

    LEAVE("did move\n");
}