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"); }
/* Returned result should not be touched by the caller. * NULL return value means the edit was rejected. */ const char * gnc_table_modify_update (Table *table, VirtualLocation virt_loc, const char *change, int change_len, const char *newval, int newval_len, int *cursor_position, int *start_selection, int *end_selection, gboolean *cancelled) { gboolean changed = FALSE; CellModifyVerifyFunc mv; BasicCell *cell; CellBlock *cb; int cell_row; int cell_col; char * old_value; g_return_val_if_fail (table, NULL); g_return_val_if_fail (table->model, NULL); if (gnc_table_model_read_only (table->model)) { PWARN ("change to read-only table"); return NULL; } cb = table->current_cursor; cell_row = virt_loc.phys_row_offset; cell_col = virt_loc.phys_col_offset; ENTER (""); if (!gnc_table_confirm_change (table, virt_loc)) { if (cancelled) *cancelled = TRUE; LEAVE("change cancelled"); return NULL; } if (cancelled) *cancelled = FALSE; /* OK, if there is a callback for this cell, call it */ cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); if (!cell) { LEAVE("no cell"); return NULL; } mv = cell->modify_verify; old_value = g_strdup (cell->value); if (mv) { mv (cell, change, change_len, newval, newval_len, cursor_position, start_selection, end_selection); } else { gnc_basic_cell_set_value (cell, newval); } if (g_strcmp0 (old_value, cell->value) != 0) { changed = TRUE; cell->changed = TRUE; } g_free (old_value); if (table->gui_handlers.redraw_help) table->gui_handlers.redraw_help (table); LEAVE ("change %d %d (relrow=%d relcol=%d) val=%s\n", virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_col, cell_row, cell_col, cell->value ? cell->value : "(null)"); if (changed) return cell->value; else return NULL; }
gboolean gnc_table_direct_update (Table *table, VirtualLocation virt_loc, char **newval_ptr, int *cursor_position, int *start_selection, int *end_selection, gpointer gui_data) { gboolean result; BasicCell *cell; CellBlock *cb; int cell_row; int cell_col; char * old_value; g_return_val_if_fail (table, FALSE); g_return_val_if_fail (table->model, FALSE); if (gnc_table_model_read_only (table->model)) { PWARN ("input to read-only table"); return FALSE; } cb = table->current_cursor; cell_row = virt_loc.phys_row_offset; cell_col = virt_loc.phys_col_offset; cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); if (!cell) return FALSE; ENTER (""); if (cell->direct_update == NULL) { LEAVE("no direct update"); return FALSE; } old_value = g_strdup (cell->value); result = cell->direct_update (cell, cursor_position, start_selection, end_selection, gui_data); if (g_strcmp0 (old_value, cell->value) != 0) { if (!gnc_table_confirm_change (table, virt_loc)) { gnc_basic_cell_set_value (cell, old_value); *newval_ptr = NULL; result = TRUE; } else { cell->changed = TRUE; *newval_ptr = cell->value; } } else *newval_ptr = NULL; g_free (old_value); if (table->gui_handlers.redraw_help) table->gui_handlers.redraw_help (table); LEAVE(""); return result; }
static void gnc_date_cell_modify_verify (BasicCell *_cell, const char *change, int change_len, const char *newval, int newval_len, int *cursor_position, int *start_selection, int *end_selection) { DateCell *cell = (DateCell *) _cell; PopBox *box = cell->cell.gui_private; gboolean accept = FALSE; if (box->in_date_select) { gnc_basic_cell_set_value (_cell, newval); return; } /* if user hit backspace, accept the change */ if (change == NULL) accept = TRUE; else if (change_len == 0) accept = TRUE; else { int count = 0; unsigned char separator = dateSeparator (); gboolean ok = TRUE; const gchar *c; gunichar uc; /* accept only numbers or a date separator. Note that the * separator of '-' (for DATE_FORMAT_ISO) takes precedence * over the accelerator below! */ c = change; while (*c) { uc = g_utf8_get_char (c); if (!g_unichar_isdigit (uc) && (separator != uc)) ok = FALSE; if (separator == uc) count++; c = g_utf8_next_char (c); } c = _cell->value; while (*c) { uc = g_utf8_get_char (c); if (separator == uc) count++; c = g_utf8_next_char (c); } if (2 < count) ok = FALSE; if (ok) accept = TRUE; } /* keep a copy of the new value */ if (accept) { gnc_basic_cell_set_value_internal (&cell->cell, newval); gnc_parse_date (&(box->date), newval); if (!box->date_picker) return; block_picker_signals (cell); gnc_date_picker_set_date (box->date_picker, box->date.tm_mday, box->date.tm_mon, box->date.tm_year + 1900); unblock_picker_signals (cell); } }