Example #1
0
static gboolean
gnc_table_find_valid_cell_horiz (Table *table,
                                 VirtualLocation *virt_loc,
                                 gboolean exact_cell)
{
    VirtualLocation vloc;
    VirtualCell *vcell;
    int left;
    int right;

    if (table == NULL)
        return FALSE;

    if (virt_loc == NULL)
        return FALSE;

    if (gnc_table_virtual_cell_out_of_bounds (table, virt_loc->vcell_loc))
        return FALSE;

    if (gnc_table_virtual_loc_valid (table, *virt_loc, exact_cell))
        return TRUE;

    vloc = *virt_loc;

    vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc);
    if (vcell == NULL)
        return FALSE;
    if (vcell->cellblock == NULL)
        return FALSE;

    if (vloc.phys_col_offset < 0)
        vloc.phys_col_offset = 0;
    if (vloc.phys_col_offset >= vcell->cellblock->num_cols)
        vloc.phys_col_offset = vcell->cellblock->num_cols - 1;

    left  = vloc.phys_col_offset - 1;
    right = vloc.phys_col_offset + 1;

    while (left >= 0 || right < vcell->cellblock->num_cols)
    {
        vloc.phys_col_offset = right;
        if (gnc_table_virtual_loc_valid(table, vloc, FALSE))
        {
            *virt_loc = vloc;
            return TRUE;
        }

        vloc.phys_col_offset = left;
        if (gnc_table_virtual_loc_valid(table, vloc, FALSE))
        {
            *virt_loc = vloc;
            return TRUE;
        }

        left--;
        right++;
    }

    return FALSE;
}
Example #2
0
static void
get_cell_borders (GnucashSheet *sheet, VirtualLocation virt_loc,
                  PhysicalCellBorders *borders)
{
    VirtualLocation v_loc;
    PhysicalCellBorders neighbor;

    gnucash_sheet_get_borders (sheet, virt_loc, borders);

    /* top */
    v_loc = virt_loc;
    if (gnc_table_move_vertical_position (sheet->table, &v_loc, -1))
    {
        gnucash_sheet_get_borders (sheet, v_loc, &neighbor);
        borders->top = MAX (borders->top, neighbor.bottom);
    }

    /* bottom */
    v_loc = virt_loc;
    if (gnc_table_move_vertical_position (sheet->table, &v_loc, 1))
    {
        gnucash_sheet_get_borders (sheet, v_loc, &neighbor);
        borders->bottom = MAX (borders->bottom, neighbor.top);
    }

    /* left */
    v_loc = virt_loc;
    v_loc.phys_col_offset--;
    if (gnc_table_virtual_loc_valid (sheet->table, v_loc, TRUE))
    {
        gnucash_sheet_get_borders (sheet, v_loc, &neighbor);
        borders->left = MAX (borders->left, neighbor.right);
    }

    /* right */
    v_loc = virt_loc;
    v_loc.phys_col_offset++;
    if (gnc_table_virtual_loc_valid (sheet->table, v_loc, TRUE))
    {
        gnucash_sheet_get_borders (sheet, v_loc, &neighbor);
        borders->right = MAX (borders->right, neighbor.left);
    }
}
Example #3
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");
}
Example #4
0
gboolean
gnc_table_traverse_update(Table *table,
                          VirtualLocation virt_loc,
                          gncTableTraversalDir dir,
                          VirtualLocation *dest_loc)
{
    gboolean abort_move;

    if ((table == NULL) || (dest_loc == NULL))
        return FALSE;

    ENTER("proposed (%d %d) -> (%d %d)\n",
          virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_row,
          dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col);

    /* first, make sure our destination cell is valid. If it is out
     * of bounds report an error. I don't think this ever happens. */
    if (gnc_table_virtual_cell_out_of_bounds (table, dest_loc->vcell_loc))
    {
        PERR("destination (%d, %d) out of bounds (%d, %d)\n",
             dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col,
             table->num_virt_rows, table->num_virt_cols);
        LEAVE("");
        return TRUE;
    }

    /* next, check the current row and column.  If they are out of bounds
     * we can recover by treating the traversal as a mouse point. This can
     * occur whenever the register widget is resized smaller, maybe?. */
    if (!gnc_table_virtual_loc_valid (table, virt_loc, TRUE))
    {
        PINFO("source (%d, %d) out of bounds (%d, %d)\n",
              virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_col,
              table->num_virt_rows, table->num_virt_cols);

        dir = GNC_TABLE_TRAVERSE_POINTER;
    }

    /* process forward-moving traversals */
    switch (dir)
    {
    case GNC_TABLE_TRAVERSE_RIGHT:
    case GNC_TABLE_TRAVERSE_LEFT:
        gnc_table_find_valid_cell_horiz(table, dest_loc, FALSE);

        break;

    case GNC_TABLE_TRAVERSE_UP:
    case GNC_TABLE_TRAVERSE_DOWN:
    {
        VirtualLocation new_loc = *dest_loc;
        int increment;
        int col_offset = 0;
        gboolean second_traversal = FALSE;

        /* Keep going in the specified direction until we find a valid
         * row to land on, or we hit the end of the table. At the end,
         * turn around and go back until we find a valid row or we get
         * to where we started. If we still can't find anything, try
         * going left and right. */
        increment = (dir == GNC_TABLE_TRAVERSE_DOWN) ? 1 : -1;

        while (!gnc_table_virtual_loc_valid(table, new_loc, FALSE))
        {
            if (virt_loc_equal (new_loc, virt_loc))
            {
                new_loc = *dest_loc;
                gnc_table_find_valid_cell_horiz(table, &new_loc, FALSE);
                break;
            }

            if (!gnc_table_move_vertical_position (table, &new_loc, increment))
            {
                /* Special case: if there is no valid cell at all in the column
                 * we are scanning, (both up and down directions didn't work)
                 * attempt to do the same in the next column.
                 * Hack alert: there is no check to see if there really is a
                 * valid next column. However this situation so far only happens
                 * after a pagedown/pageup key event in the SX transaction editor
                 * which always tests the first column to start (which has no
                 * editable cells) and in that situation there is a valid next column.
                 */
                if (!second_traversal)
                    second_traversal = TRUE;
                else
                {
                    second_traversal = FALSE;
                    col_offset++;
                }
                increment *= -1;
                new_loc = *dest_loc;
                new_loc.phys_col_offset = new_loc.phys_col_offset + col_offset;
            }
        }

        *dest_loc = new_loc;
    }

    if (!gnc_table_virtual_loc_valid(table, *dest_loc, FALSE))
    {
        LEAVE("");
        return TRUE;
    }

    break;

    case GNC_TABLE_TRAVERSE_POINTER:
        if (!gnc_table_find_valid_cell_horiz(table, dest_loc, TRUE))
        {
            LEAVE("");
            return TRUE;
        }

        break;

    default:
        g_return_val_if_fail (FALSE, TRUE);
        break;
    }

    /* Call the table traverse callback for any modifications. */
    if (table->control->traverse)
        abort_move = table->control->traverse (dest_loc, dir,
                                               table->control->user_data);
    else
        abort_move = FALSE;

    LEAVE("dest_row = %d, dest_col = %d\n",
          dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col);

    return abort_move;
}