Commit b676840e authored by Jody Goldberg's avatar Jody Goldberg
Browse files

- More work on array-formulas, still no cut/copy/paste. But its harder

  to cause a core dump :-)  Some docs.
- Have patterns match Excel.
- Easy optimization in the common case to do 1 intersection rather than 4
    for a single cell.
- Some command line flags for debugging excel import.
parent cbbbdf84
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
1999-07-05 Jody Goldberg <jgoldberg@home.com>
* src/cell.c (cell_set_formula) : Rework array-formula logic to deal
with cell_set_array_formula releasing the wrapper generated by the
parser.
(cell_set_text) : Crude but effective prohibition for editing 1 cell
in an array.
* src/eval.c : Add more debug info.
(search_cell_deps) : Rename search_range_deps.
(search_cell_deps) : New function. Special case of a single cell
only needs 1 call to intersect.
* src/expr.c (do_expr_tree_invalidate_references,
do_expr_tree_fixup_references) : Implement for OPER_ARRAY.
(expr_tree_get_const_str) : New function.
* src/format.c (format_number) : Made debug warning more verbose but
only print it the 1st time.
* src/gnumeric-util.[c,h] (gnumeric_no_modify_array_notice) : New.
* src/sheet.c (sheet_clear_region): Use gnumeric_no_modify_array_notice.
(avoid_dividing_array_horizontal, avoid_dividing_array_vertical) : New.
(sheet_insert_row, sheet_insert_row) : Use them.
(sheet_fill_selection_with) : Add flag to differentiate fills and
array-formulas. Check to ensure that the array/fill operation does
not overwrite a subset of an array.
* src/gnumeric-sheet.c (gnumeric_sheet_key_mode_sheet) : Pass is_array.
(gnumeric_sheet_patterns) : Adjust to more exactly match Excel.
NOTE : They are listed in DISPLAY order not excel's internal index
scheme, that requires a map.
* src/gnumeric-sheet.h : Increase number of patterns.
* src/pattern-selector.c : Adjust layout to match Excel. Still need to
figure out how to get the stipples on a white background.
* src/main.c : Add debug_excel_{read,formulas,color,chart} to
allow run time vs compile time verbosity.
1999-07-05 Morten Welinder <terra@diku.dk>
* src/expr.c (value_array_resize): Shined up, fixed, not tested.
......
......@@ -129,7 +129,13 @@ documentation for these:
- Home: move to the beginning of the row.
- Contorl-Home: move to the cell A1
- Control-Home: move to the cell A1
- Control-Enter: copies current edit text to the selected range.
- Control-Shift-Enter: If there is a single range selected and the
current edit text is a formula, the formula is made into an
'array-formula'
o Auto-convert-on-input features: When you enter text in Gnumeric
it is now matched against the known formats of Gnumeric and if
......@@ -140,3 +146,11 @@ documentation for these:
this: ="10-Jan"+45.
Autofill will also work on this.
o Gnumeric command line debug arguments.
- dump-func-defs
- debug
- debug_excel_read
- debug_excel_formulas
- debug_excel_color
- debug_excel_chart
......@@ -53,9 +53,9 @@ cell_set_formula (Cell *cell, const char *text)
cell_modified (cell);
new_expr = expr_parse_string (&text [1],
eval_pos_cell (&fp, cell),
&desired_format,
&error_msg);
eval_pos_cell (&fp, cell),
&desired_format,
&error_msg);
if (new_expr == NULL){
cell->parsed_node = NULL;
cell->flags |= CELL_ERROR;
......@@ -67,31 +67,40 @@ cell_set_formula (Cell *cell, const char *text)
return;
}
if (new_expr->oper == OPER_ARRAY){
if (new_expr->u.array.x == 0 && new_expr->u.array.y == 0){
cell->parsed_node = new_expr;
cell_set_array_formula (cell->sheet,
cell->row->pos,
cell->col->pos,
cell->row->pos + new_expr->u.array.rows -1,
cell->col->pos + new_expr->u.array.cols -1,
new_expr->u.array.corner.func.expr);
} else
new_expr = NULL;
} else
cell->parsed_node = new_expr;
if (cell->flags & CELL_ERROR)
cell->flags &= ~CELL_ERROR;
if (cell->flags & CELL_ERROR)
cell->flags &= ~CELL_ERROR;
if (desired_format && strcmp (cell->style->format->format, "General") == 0){
if (desired_format &&
strcmp (cell->style->format->format, "General") == 0){
style_format_unref (cell->style->format);
cell->style->format = style_format_new (desired_format);
}
/* Don't touch things if this was part of an array not at the corner */
if (new_expr)
cell_formula_changed (cell);
if (new_expr->oper == OPER_ARRAY){
/* The corner sets up the entire array block */
if (new_expr->u.array.x != 0 || new_expr->u.array.y != 0)
{
expr_tree_unref (new_expr);
return;
}
/*
* NOTE : The wrapper supplied by the parser will be released
* and recreated. new_expr will NOT be valid on exit
* from cell_set_array_formula.
*/
cell->parsed_node = new_expr;
cell_set_array_formula (cell->sheet,
cell->row->pos, cell->col->pos,
cell->row->pos +
new_expr->u.array.rows -1,
cell->col->pos +
new_expr->u.array.cols -1,
new_expr->u.array.corner.func.expr);
} else {
cell->parsed_node = new_expr;
cell_formula_changed (cell);
}
}
/*
......@@ -706,6 +715,7 @@ cell_content_changed (Cell *cell)
cell_queue_recalc_list (deps, TRUE);
}
/*
* cell_set_text
*
......@@ -717,6 +727,12 @@ cell_set_text (Cell *cell, const char *text)
g_return_if_fail (cell != NULL);
g_return_if_fail (text != NULL);
if (cell->parsed_node != NULL && cell->parsed_node->oper == OPER_ARRAY)
{
gnumeric_no_modify_array_notice (cell->sheet->workbook);
return;
}
cell_queue_redraw (cell);
cell_set_text_simple (cell, text);
......
......@@ -334,7 +334,7 @@ typedef struct {
int end_col, end_row;
Sheet *sheet;
GList *list;
} get_dep_closure_t;
} get_range_dep_closure_t;
static gboolean
intersects (Sheet *sheet, int col, int row, DependencyRange *range)
......@@ -347,10 +347,10 @@ intersects (Sheet *sheet, int col, int row, DependencyRange *range)
}
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
search_range_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_dep_closure_t *c = closure;
get_range_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
......@@ -372,7 +372,7 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
GList *
region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
get_dep_closure_t closure;
get_range_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
......@@ -384,23 +384,46 @@ region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col
closure.sheet = sheet;
closure.list = NULL;
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
g_hash_table_foreach (dependency_hash, &search_range_deps, &closure);
return closure.list;
}
typedef struct {
int col, row;
Sheet *sheet;
GList *list;
} get_cell_dep_closure_t;
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_cell_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
/* No intersection is the common case */
if (!intersects (sheet, c->col, c->row, range))
return;
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
}
}
GList *
cell_get_dependencies (Sheet *sheet, int col, int row)
{
get_dep_closure_t closure;
get_cell_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
closure.start_col = col;
closure.start_row = row;
closure.end_col = col;
closure.end_row = row;
closure.col = col;
closure.row = row;
closure.sheet = sheet;
closure.list = NULL;
......@@ -539,14 +562,28 @@ workbook_recalc (Workbook *wb)
cell->generation = generation;
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
deps = cell_get_dependencies (cell->sheet,
cell->col->pos, cell->row->pos);
#ifdef DEBUG_EVALUATION
printf ("\nDepends for %s:%s :\n",
cell->sheet->name,
cell_name(cell->col->pos, cell->row->pos));
#endif
for (l = deps; l; l = l->next){
Cell *one_cell;
one_cell = l->data;
if (one_cell->generation != generation)
if (one_cell->generation != generation){
cell_queue_recalc (one_cell);
#ifdef DEBUG_EVALUATION
printf ("\t%s:%s,\n",
one_cell->sheet->name,
cell_name(one_cell->col->pos,
one_cell->row->pos));
#endif
}
}
g_list_free (deps);
}
......
......@@ -334,7 +334,7 @@ typedef struct {
int end_col, end_row;
Sheet *sheet;
GList *list;
} get_dep_closure_t;
} get_range_dep_closure_t;
static gboolean
intersects (Sheet *sheet, int col, int row, DependencyRange *range)
......@@ -347,10 +347,10 @@ intersects (Sheet *sheet, int col, int row, DependencyRange *range)
}
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
search_range_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_dep_closure_t *c = closure;
get_range_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
......@@ -372,7 +372,7 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
GList *
region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col, int end_row)
{
get_dep_closure_t closure;
get_range_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
......@@ -384,23 +384,46 @@ region_get_dependencies (Sheet *sheet, int start_col, int start_row, int end_col
closure.sheet = sheet;
closure.list = NULL;
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
g_hash_table_foreach (dependency_hash, &search_range_deps, &closure);
return closure.list;
}
typedef struct {
int col, row;
Sheet *sheet;
GList *list;
} get_cell_dep_closure_t;
static void
search_cell_deps (gpointer key, gpointer value, gpointer closure)
{
DependencyRange *range = key;
get_cell_dep_closure_t *c = closure;
Sheet *sheet = c->sheet;
GList *l;
/* No intersection is the common case */
if (!intersects (sheet, c->col, c->row, range))
return;
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
}
}
GList *
cell_get_dependencies (Sheet *sheet, int col, int row)
{
get_dep_closure_t closure;
get_cell_dep_closure_t closure;
if (!dependency_hash)
dependency_hash_init ();
closure.start_col = col;
closure.start_row = row;
closure.end_col = col;
closure.end_row = row;
closure.col = col;
closure.row = row;
closure.sheet = sheet;
closure.list = NULL;
......@@ -539,14 +562,28 @@ workbook_recalc (Workbook *wb)
cell->generation = generation;
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
deps = cell_get_dependencies (cell->sheet,
cell->col->pos, cell->row->pos);
#ifdef DEBUG_EVALUATION
printf ("\nDepends for %s:%s :\n",
cell->sheet->name,
cell_name(cell->col->pos, cell->row->pos));
#endif
for (l = deps; l; l = l->next){
Cell *one_cell;
one_cell = l->data;
if (one_cell->generation != generation)
if (one_cell->generation != generation){
cell_queue_recalc (one_cell);
#ifdef DEBUG_EVALUATION
printf ("\t%s:%s,\n",
one_cell->sheet->name,
cell_name(one_cell->col->pos,
one_cell->row->pos));
#endif
}
}
g_list_free (deps);
}
......
......@@ -260,6 +260,17 @@ expr_tree_get_const_int (ExprTree const * const expr)
return expr->u.constant->v.v_int;
}
char const *
expr_tree_get_const_str (ExprTree const *const expr)
{
g_return_val_if_fail (expr != NULL, NULL);
g_return_val_if_fail (expr->oper == OPER_CONSTANT, NULL);
g_return_val_if_fail (expr->u.constant, NULL);
g_return_val_if_fail (expr->u.constant->type == VALUE_STRING, NULL);
return expr->u.constant->v.str->str;
}
ExprTree *
expr_parse_string (const char *expr, const EvalPosition *fp,
const char **desired_format, char **error_msg)
......@@ -1669,8 +1680,8 @@ eval_expr (FunctionEvalInfo *s, ExprTree *tree)
else
a = NULL;
}
g_return_val_if_fail (a != NULL,
function_error (s, gnumeric_err_NA));
if (a == NULL) /* Seems like errors return NULL */
return NULL;
if (a->type == VALUE_CELLRANGE || a->type == VALUE_ARRAY){
int const num_x = value_area_get_width (&s->pos, a);
......@@ -1907,7 +1918,7 @@ do_expr_decode_tree (ExprTree *tree, const EvalPosition *fp, int paren_level)
res = do_expr_decode_tree (
array->u.array.corner.func.expr,
&tmp_pos, 0);
}
}
} else
{
res = do_expr_decode_tree (
......@@ -2084,9 +2095,22 @@ do_expr_tree_invalidate_references (ExprTree *src, const struct expr_tree_frob_r
}
case OPER_ARRAY:
{
/* FIXME FIXME FIXME : what should this do ? */
return NULL;
g_assert_not_reached ();
ArrayRef * a = &src->u.array;
if (a->x == 0 && a->y == 0)
{
ExprTree *func = do_expr_tree_invalidate_references (
a->corner.func.expr, info);
if (func != NULL)
{
ExprTree *res =
expr_tree_array_formula (0, 0,
a->rows, a->cols);
res->u.array.corner.func.value = NULL;
res->u.array.corner.func.expr = func;
return res;
}
}
return NULL;
}
}
......@@ -2098,7 +2122,7 @@ do_expr_tree_invalidate_references (ExprTree *src, const struct expr_tree_frob_r
/*
* Invalidate (== turn into error expressions) cell and range references that
* will disappear completely during a deletions of columns or rows. Note that
* this is not intended for use when just the cell contents is delete.
* this is not intended for use when just the cell contents is deleted.
*/
ExprTree *
expr_tree_invalidate_references (ExprTree *src, EvalPosition *src_fp,
......@@ -2296,12 +2320,23 @@ do_expr_tree_fixup_references (ExprTree *src, const struct expr_tree_frob_refere
}
case OPER_ARRAY:
{
/*
* FIXME FIXME FIXME : This is the mirror of above.
* Read and find out what they do
*/
return NULL;
g_assert_not_reached ();
ArrayRef * a = &src->u.array;
if (a->x == 0 && a->y == 0)
{
ExprTree *func =
do_expr_tree_fixup_references (a->corner.func.expr,
info);
if (func != NULL)
{
ExprTree *res =
expr_tree_array_formula (0, 0,
a->rows, a->cols);
res->u.array.corner.func.value = NULL;
res->u.array.corner.func.expr = func;
return res;
}
}