Commit dfb8a858 authored by Arturo Espinosa's avatar Arturo Espinosa

Autocalc works (but I managed to break the recursive detection stuff, will



Autocalc works (but I managed to break the recursive detection
stuff, will fix that tomorrow).

Quick-computations on the selected area (like Excel) works with
different user-selectable functions.

Fixed the horrible crash due to not removing my strings from the
hash table ;-)

Miguel
parent d2c3b2ba
1998-08-10 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c (workbook_recalc): Queue computation for cells that
have been recomputed.
* src/expr.c (eval_expr): Implement the concatenation operator.
1998-08-09 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/expr.c (eval_expr): Implement comparission.
* src/str.c (string_unref_ptr, string_unref): Remove the string
from the string_hash_table when the refcount reaches zero.
* src/symbol.c (symbol_unref): Remove the symbol from the hash
table when the refcount reaches zero.
1998-08-07 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/gnumeric-sheet.c: Renamed all references to (GnumericSheet
......
1998-08-10 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c (workbook_recalc): Queue computation for cells that
have been recomputed.
* src/expr.c (eval_expr): Implement the concatenation operator.
1998-08-09 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/expr.c (eval_expr): Implement comparission.
* src/str.c (string_unref_ptr, string_unref): Remove the string
from the string_hash_table when the refcount reaches zero.
* src/symbol.c (symbol_unref): Remove the symbol from the hash
table when the refcount reaches zero.
1998-08-07 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/gnumeric-sheet.c: Renamed all references to (GnumericSheet
......
1998-08-10 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c (workbook_recalc): Queue computation for cells that
have been recomputed.
* src/expr.c (eval_expr): Implement the concatenation operator.
1998-08-09 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/expr.c (eval_expr): Implement comparission.
* src/str.c (string_unref_ptr, string_unref): Remove the string
from the string_hash_table when the refcount reaches zero.
* src/symbol.c (symbol_unref): Remove the symbol from the hash
table when the refcount reaches zero.
1998-08-07 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/gnumeric-sheet.c: Renamed all references to (GnumericSheet
......
1998-08-10 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c (workbook_recalc): Queue computation for cells that
have been recomputed.
* src/expr.c (eval_expr): Implement the concatenation operator.
1998-08-09 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/expr.c (eval_expr): Implement comparission.
* src/str.c (string_unref_ptr, string_unref): Remove the string
from the string_hash_table when the refcount reaches zero.
* src/symbol.c (symbol_unref): Remove the symbol from the hash
table when the refcount reaches zero.
1998-08-07 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/gnumeric-sheet.c: Renamed all references to (GnumericSheet
......
......@@ -26,7 +26,7 @@ cell_set_formula (Cell *cell, char *text)
g_return_if_fail (cell != NULL);
g_return_if_fail (text != NULL);
cell->parsed_node = expr_parse_string (&text [1],
cell->col->pos,
cell->row->pos,
......@@ -44,10 +44,25 @@ cell_set_formula (Cell *cell, char *text)
}
void
cell_set_text (Cell *cell, char *text)
cell_calc_dimensions (Cell *cell)
{
GdkFont *font;
char *rendered_text;
GdkFont *font;
g_return_if_fail (cell != NULL);
rendered_text = CELL_TEXT_GET (cell);
font = cell->style->font->font;
cell->width = cell->col->margin_a + cell->col->margin_b +
gdk_text_width (font, rendered_text, strlen (rendered_text));
cell->height = font->ascent + font->descent;
}
void
cell_set_text (Cell *cell, char *text)
{
GList *deps;
g_return_if_fail (cell != NULL);
......@@ -55,12 +70,16 @@ cell_set_text (Cell *cell, char *text)
/* The value entered */
if (cell->entered_text)
string_unref_ptr (&cell->entered_text);
string_unref (cell->entered_text);
cell->entered_text = string_get (text);
if (cell->parsed_node){
cell_drop_dependencies (cell);
cell_formula_unlink (cell);
expr_tree_unref (cell->parsed_node);
cell->parsed_node = NULL;
}
if (text [0] == '='){
......@@ -71,7 +90,7 @@ cell_set_text (Cell *cell, char *text)
char *p;
if (cell->text)
string_unref_ptr (&cell->text);
string_unref (cell->text);
cell->text = string_get (text);
......@@ -105,6 +124,7 @@ cell_set_text (Cell *cell, char *text)
/* In this case we need to format the text */
}
cell->value = v;
cell_calc_dimensions (cell);
}
/* Queue all of the dependencies for this cell */
......@@ -117,12 +137,4 @@ cell_set_text (Cell *cell, char *text)
/* Finish setting the values for this cell */
cell->flags = 0;
rendered_text = CELL_TEXT_GET (cell);
font = cell->style->font->font;
cell->width = cell->col->margin_a + cell->col->margin_b +
gdk_text_width (font, rendered_text, strlen (rendered_text));
cell->height = font->ascent + font->descent;
}
......@@ -54,8 +54,10 @@ typedef struct {
#define CELL_TEXT_GET(cell) ((cell)->text ? cell->text->str : cell->entered_text->str)
#define CELL_IS_FORMULA(cell) (cell->entered_text->str [0] == '=')
#define MAX_ITERATIONS(cell) 1
void cell_set_text (Cell *cell, char *text);
void cell_set_formula (Cell *cell, char *text);
void cell_calc_dimensions (Cell *cell);
#endif /* GNUMERIC_CELL_H */
......@@ -27,9 +27,9 @@ cell_eval (Cell *cell)
return;
cell->iteration++;
if (cell->text)
string_unref_ptr (&cell->text);
string_unref (cell->text);
v = eval_expr (cell->sheet, cell->parsed_node,
cell->col->pos,
......@@ -51,6 +51,8 @@ cell_eval (Cell *cell)
g_free (str);
}
cell_calc_dimensions (cell);
sheet_redraw_cell_region (cell->sheet,
cell->col->pos, cell->row->pos,
cell->col->pos, cell->row->pos);
......@@ -143,7 +145,7 @@ add_cell_range_deps (Cell *cell, CellRef *a, CellRef *b)
*result = range;
result->ref_count = 1;
result->cell_list = g_list_prepend (NULL, cell);
g_hash_table_insert (dependency_hash, result, result);
}
......@@ -319,10 +321,9 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
printf ("Cell: %d,%d\n", cell->col->pos, cell->row->pos);
printf ("Found dependenat: %d, %d\n", cell->col->pos, cell->row->pos);
c->list = g_list_prepend (c->list, cell);
}
}
......@@ -339,7 +340,6 @@ cell_get_dependencies (Sheet *sheet, int col, int row)
closure.sheet = sheet;
closure.list = NULL;
printf ("Looking for dependencies of %d,%d\n", col, row);
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
return closure.list;
......@@ -388,9 +388,12 @@ void
workbook_recalc (Workbook *wb)
{
Cell *cell;
GList *deps;
while ((cell = pick_next_cell_from_queue (wb))){
printf ("Processing %d %d\n", cell->col->pos, cell->row->pos);
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
if (deps)
cell_queue_recalc_list (deps);
}
}
......@@ -27,9 +27,9 @@ cell_eval (Cell *cell)
return;
cell->iteration++;
if (cell->text)
string_unref_ptr (&cell->text);
string_unref (cell->text);
v = eval_expr (cell->sheet, cell->parsed_node,
cell->col->pos,
......@@ -51,6 +51,8 @@ cell_eval (Cell *cell)
g_free (str);
}
cell_calc_dimensions (cell);
sheet_redraw_cell_region (cell->sheet,
cell->col->pos, cell->row->pos,
cell->col->pos, cell->row->pos);
......@@ -143,7 +145,7 @@ add_cell_range_deps (Cell *cell, CellRef *a, CellRef *b)
*result = range;
result->ref_count = 1;
result->cell_list = g_list_prepend (NULL, cell);
g_hash_table_insert (dependency_hash, result, result);
}
......@@ -319,10 +321,9 @@ search_cell_deps (gpointer key, gpointer value, gpointer closure)
for (l = range->cell_list; l; l = l->next){
Cell *cell = l->data;
c->list = g_list_prepend (c->list, cell);
printf ("Cell: %d,%d\n", cell->col->pos, cell->row->pos);
printf ("Found dependenat: %d, %d\n", cell->col->pos, cell->row->pos);
c->list = g_list_prepend (c->list, cell);
}
}
......@@ -339,7 +340,6 @@ cell_get_dependencies (Sheet *sheet, int col, int row)
closure.sheet = sheet;
closure.list = NULL;
printf ("Looking for dependencies of %d,%d\n", col, row);
g_hash_table_foreach (dependency_hash, &search_cell_deps, &closure);
return closure.list;
......@@ -388,9 +388,12 @@ void
workbook_recalc (Workbook *wb)
{
Cell *cell;
GList *deps;
while ((cell = pick_next_cell_from_queue (wb))){
printf ("Processing %d %d\n", cell->col->pos, cell->row->pos);
cell_eval (cell);
deps = cell_get_dependencies (cell->sheet, cell->col->pos, cell->row->pos);
if (deps)
cell_queue_recalc_list (deps);
}
}
#include <config.h>
#include <gnome.h>
#include <math.h>
#include <string.h>
#include "gnumeric.h"
#include "expr.h"
......@@ -59,6 +60,12 @@ eval_expr_release (ExprTree *tree)
symbol_unref (tree->u.function.symbol);
break;
case OP_EQUAL:
case OP_GT:
case OP_LT:
case OP_GTE:
case OP_LTE:
case OP_NOT_EQUAL:
case OP_ADD:
case OP_SUB:
case OP_MULT:
......@@ -72,9 +79,6 @@ eval_expr_release (ExprTree *tree)
case OP_NEG:
eval_expr_release (tree->u.value);
break;
default:
g_warning ("Unknown ExprTree type passed to eval_expr_release\n");
}
g_free (tree);
}
......@@ -128,8 +132,6 @@ value_release (Value *value)
case VALUE_CELLRANGE:
break;
default:
g_warning ("Unknown value type passed to value_release\n");
}
g_free (value);
}
......@@ -325,17 +327,92 @@ eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **e
return v;
}
enum {
typedef enum {
IS_EQUAL,
IS_LESS,
IS_BIGGER,
};
IS_GREATER,
TYPE_ERROR
} compare_t;
static compare_t
compare_int_int (int a, int b)
{
if (a == b)
return IS_EQUAL;
else if (a < b)
return IS_LESS;
else
return IS_GREATER;
}
static compare_t
compare_float_float (float_t a, float_t b)
{
if (a == b)
return IS_EQUAL;
else if (a < b)
return IS_LESS;
else
return IS_GREATER;
}
static int
/*
* Compares two (Value *) and returns one of compare_t
*/
static compare_t
compare (Value *a, Value *b)
{
g_warning ("Value comparission is not yet implemented\n");
return IS_EQUAL;
if (a->type == VALUE_INTEGER){
int f;
switch (b->type){
case VALUE_INTEGER:
return compare_int_int (a->v.v_int, b->v.v_int);
case VALUE_FLOAT:
return compare_float_float (a->v.v_int, b->v.v_float);
case VALUE_STRING:
f = value_get_as_double (b);
return compare_float_float (a->v.v_int, f);
default:
return TYPE_ERROR;
}
}
if (a->type == VALUE_FLOAT){
float_t f;
switch (b->type){
case VALUE_INTEGER:
return compare_float_float (a->v.v_float, b->v.v_int);
case VALUE_FLOAT:
return compare_float_float (a->v.v_float, b->v.v_float);
case VALUE_STRING:
f = value_get_as_double (b);
return compare_float_float (a->v.v_float, f);
default:
return TYPE_ERROR;
}
}
if (a->type == VALUE_STRING && b->type == VALUE_STRING){
int t;
t = strcasecmp (a->v.str->str, b->v.str->str);
if (t == 0)
return IS_EQUAL;
else if (t > 0)
return IS_GREATER;
else
return IS_LESS;
}
return TYPE_ERROR;
}
Value *
......@@ -374,13 +451,20 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
comp = compare (a, b);
if (comp == TYPE_ERROR){
value_release (a);
value_release (b);
*error_string = _("Type error");
return NULL;
}
switch (tree->oper){
case OP_EQUAL:
res->v.v_int = comp == IS_EQUAL;
break;
case OP_GT:
res->v.v_int = comp == IS_BIGGER;
res->v.v_int = comp == IS_GREATER;
break;
case OP_LT:
......@@ -392,7 +476,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
break;
case OP_GTE:
res->v.v_int = (comp == IS_EQUAL || comp == IS_BIGGER);
res->v.v_int = (comp == IS_EQUAL || comp == IS_GREATER);
break;
case OP_NOT_EQUAL:
......@@ -507,10 +591,35 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
value_release (b);
return res;
case OP_CONCAT:
g_warning ("Concat not implemented yet\n");
*error_string = _("OOPS");
return NULL;
case OP_CONCAT: {
char *sa, *sb, *tmp;
a = eval_expr (sheet, tree->u.binary.value_a,
eval_col, eval_row, error_string);
if (!a)
return NULL;
b = eval_expr (sheet, tree->u.binary.value_b,
eval_col, eval_row, error_string);
if (!b){
value_release (a);
return NULL;
}
res = g_new (Value, 1);
res->type = VALUE_STRING;
sa = value_string (a);
sb = value_string (b);
tmp = g_copy_strings (sa, sb, NULL);
res->v.str = string_get (tmp);
g_free (sa);
g_free (sb);
g_free (tmp);
value_release (a);
value_release (b);
return res;
}
case OP_FUNCALL:
return eval_funcall (sheet, tree, eval_col, eval_row, error_string);
......
......@@ -337,11 +337,14 @@ cancel_pending_input (GnumericSheet *gsheet)
{
stop_cell_selection (gsheet);
if (gsheet->item_editor){
if (!gsheet->item_editor)
return;
if (gsheet->editing_cell){
cell_set_text (gsheet->editing_cell,
gsheet->editing_saved_text->str);
destroy_item_editor (gsheet);
}
destroy_item_editor (gsheet);
}
static void
......
......@@ -337,11 +337,14 @@ cancel_pending_input (GnumericSheet *gsheet)
{
stop_cell_selection (gsheet);
if (gsheet->item_editor){
if (!gsheet->item_editor)
return;
if (gsheet->editing_cell){
cell_set_text (gsheet->editing_cell,
gsheet->editing_saved_text->str);
destroy_item_editor (gsheet);
}
destroy_item_editor (gsheet);
}
static void
......
......@@ -595,31 +595,37 @@ sheet_selection_equal (SheetSelection *a, SheetSelection *b)
return 1;
}
static void
workbook_label_set (Workbook *wb, char *text)
{
gnome_canvas_item_set (wb->auto_expr_label,
"text", text,
NULL);
}
static void
sheet_selection_changed_hook (Sheet *sheet)
void
sheet_update_auto_expr (Sheet *sheet)
{
Workbook *wb = sheet->workbook;
Value *v;
char *error;
g_return_if_fail (sheet != NULL);
g_return_if_fail (IS_SHEET (sheet));
/* defaults */
v = NULL;
error = "ERROR";
if (wb->auto_expr)
v = eval_expr (sheet, wb->auto_expr, 0, 0, &error);
v = eval_expr (sheet, wb->auto_expr, 0, 0, &error);
if (v){
char *s;
s = value_string (v);
workbook_label_set (wb, s);
workbook_auto_expr_label_set (wb, s);
g_free (s);
value_release (v);
} else
workbook_label_set (wb, error);
workbook_auto_expr_label_set (wb, error);
}
static void
sheet_selection_changed_hook (Sheet *sheet)
{
sheet_update_auto_expr (sheet);
}
void
......
......@@ -20,6 +20,7 @@ typedef struct {
/* The auto-expression */
ExprTree *auto_expr;
String *auto_expr_desc;
GnomeCanvasItem *auto_expr_label;
/* Styles */
......@@ -156,6 +157,8 @@ void sheet_redraw_cell_region (Sheet *sheet, int start_col, int start_ro
void sheet_redraw_selection (Sheet *sheet, SheetSelection *ss);
void sheet_redraw_all (Sheet *sheet);
void sheet_update_auto_expr (Sheet *sheet);
/*
* Workbook
*/
......@@ -164,6 +167,7 @@ Workbook *workbook_new_with_sheets (int sheet_count);
void workbook_attach_sheet (Workbook *, Sheet *);
Sheet *workbook_focus_current_sheet (Workbook *wb);
Sheet *workbook_get_current_sheet (Workbook *wb);
void workbook_auto_expr_label_set (Workbook *wb, char *text);
/*
* Does any pending recalculations
......
......@@ -60,6 +60,7 @@ string_unref (String *string)
g_return_if_fail (string->ref_count > 0);
if (--(string->ref_count) == 0){
g_hash_table_remove (string_hash_table, string->str);
g_free (string->str);
g_free (string);
}
......@@ -78,6 +79,7 @@ string_unref_ptr (String **string_ptr)
g_return_if_fail ((*string_ptr)->ref_count > 0);
if (--((*string_ptr)->ref_count) == 0){
g_hash_table_remove (string_hash_table, (*string_ptr)->str);
g_free ((*string_ptr)->str);
g_free (*string_ptr);
*string_ptr = NULL;
......
......@@ -115,6 +115,7 @@ symbol_unref (Symbol *sym)
g_return_if_fail (sym->ref_count > 0);
if (--(sym->ref_count) == 0){
g_hash_table_remove (symbol_hash_table, sym->str);
g_free (sym->str);
g_free (sym);
}
......
......@@ -156,6 +156,77 @@ workbook_setup_edit_area (Workbook *wb)
wb);
}
struct {
char *displayed_name;
char *function;
} quick_compute_routines [] = {
{ N_("Sum"), "SUM(SELECTION())" },
{ N_("Min"), "MIN(SELECTION())" },
{ N_("Max"), "MAX(SELECTION())" },
{ N_("Average"), "AVERAGE(SELECTION())" },
{ N_("Count"), "COUNT(SELECTION())" },
{ NULL, NULL }
};
/*
* Sets the expression that gets evaluated whenever the
* selection in the sheet changes
*/
static char *
workbook_set_auto_expr (Workbook *wb, char *description, char *expression)
{
char *error = NULL;
if (wb->auto_expr){
g_assert (wb->auto_expr->ref_count == 1);
expr_tree_unref (wb->auto_expr);
string_unref (wb->auto_expr_desc);
}
wb->auto_expr = expr_parse_string (expression, 0, 0, &error);
wb->auto_expr_desc = string_get (description);
return error;
}
static void
change_auto_expr (GtkWidget *item, Workbook *wb)
{
char *expr, *name;
expr = gtk_object_get_data (GTK_OBJECT (item), "expr");
name = gtk_object_get_data (GTK_OBJECT (item), "name");
workbook_set_auto_expr (wb, name, expr);
sheet_update_auto_expr (workbook_get_current_sheet (wb));
}
static void
change_auto_expr_menu (GtkWidget *widget, GdkEventButton *event, Workbook *wb)
{
static GtkWidget *menu;
if (!menu){
GtkWidget *item;
int i;
menu = gtk_menu_new ();
for (i = 0; quick_compute_routines [i].displayed_name; i++){
item = gtk_menu_item_new_with_label (
_(quick_compute_routines [i].displayed_name));
gtk_menu_append (GTK_MENU (menu), item);