Commit 22a7ee1a authored by Jody Goldberg's avatar Jody Goldberg Committed by Jody Goldberg

add support for referencing names in other workbooks.

2001-10-29  Jody Goldberg <jgoldberg@home.com>

	* src/parser.y : add support for referencing names in other workbooks.

	* src/expr.c (expr_tree_new_name) : take an optional sheet and
	  workbook as scoping info.
	(expr_eval_real) : handle inactive names.
	(do_expr_tree_to_string) : improve scoping.
	(expr_rewrite) : handle inactives and scope changes.

	* src/expr-name.c (expr_name_lookup) : add the notion of active and a
	  ref count so that we can do a delayed destruction and invalidation.
	(expr_name_add) : make it clearer that the return is not meant
	  to be freed.
	(expr_name_create) : don't free the result of expr_name_lookup.
	(expr_name_ref) : generalize.
	(expr_name_unref) : ditto.
	(expr_name_remove) : deactivate the name.
parent 12ce1526
......@@ -8,10 +8,7 @@ release, and longer term bugs.
Release Critical
----------------
- Check name scope when relocating
- name dialog
: selecting a name in a different scope does not change the scope radio
button properly.
: We should start with the expr entry set to either the current cell,
or by selecting the first named expression in scope that contains the
current cell.
......@@ -27,8 +24,6 @@ Pending Patches
http://bugzilla.gnome.org/show_bug.cgi?id=60468 oleo
Status of acuster's latex fix ?
Long term breakage
------------------
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* src/parser.y : add support for referencing names in other workbooks.
* src/expr.c (expr_tree_new_name) : take an optional sheet and
workbook as scoping info.
(expr_eval_real) : handle inactive names.
(do_expr_tree_to_string) : improve scoping.
(expr_rewrite) : handle inactives and scope changes.
* src/expr-name.c (expr_name_lookup) : add the notion of active and a
ref count so that we can do a delayed destruction and invalidation.
(expr_name_add) : make it clearer that the return is not meant
to be freed.
(expr_name_create) : don't free the result of expr_name_lookup.
(expr_name_ref) : generalize.
(expr_name_unref) : ditto.
(expr_name_remove) : deactivate the name.
2001-10-27 Almer S. Tigelaar <almer@gnome.org>
* src/GNOME_Gnumeric.xml: Tidy view menu.
......
Gnumeric 0.73
Adrian Custer:
* Improve latex exporter to support multiple pages and basic support
for merges.
Almer:
* More work on validation.
Andreas:
* Allow analysis tool output to be directed onto a range
on another sheet.
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* src/parser.y : add support for referencing names in other workbooks.
* src/expr.c (expr_tree_new_name) : take an optional sheet and
workbook as scoping info.
(expr_eval_real) : handle inactive names.
(do_expr_tree_to_string) : improve scoping.
(expr_rewrite) : handle inactives and scope changes.
* src/expr-name.c (expr_name_lookup) : add the notion of active and a
ref count so that we can do a delayed destruction and invalidation.
(expr_name_add) : make it clearer that the return is not meant
to be freed.
(expr_name_create) : don't free the result of expr_name_lookup.
(expr_name_ref) : generalize.
(expr_name_unref) : ditto.
(expr_name_remove) : deactivate the name.
2001-10-27 Almer S. Tigelaar <almer@gnome.org>
* src/GNOME_Gnumeric.xml: Tidy view menu.
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* src/parser.y : add support for referencing names in other workbooks.
* src/expr.c (expr_tree_new_name) : take an optional sheet and
workbook as scoping info.
(expr_eval_real) : handle inactive names.
(do_expr_tree_to_string) : improve scoping.
(expr_rewrite) : handle inactives and scope changes.
* src/expr-name.c (expr_name_lookup) : add the notion of active and a
ref count so that we can do a delayed destruction and invalidation.
(expr_name_add) : make it clearer that the return is not meant
to be freed.
(expr_name_create) : don't free the result of expr_name_lookup.
(expr_name_ref) : generalize.
(expr_name_unref) : ditto.
(expr_name_remove) : deactivate the name.
2001-10-27 Almer S. Tigelaar <almer@gnome.org>
* src/GNOME_Gnumeric.xml: Tidy view menu.
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* src/parser.y : add support for referencing names in other workbooks.
* src/expr.c (expr_tree_new_name) : take an optional sheet and
workbook as scoping info.
(expr_eval_real) : handle inactive names.
(do_expr_tree_to_string) : improve scoping.
(expr_rewrite) : handle inactives and scope changes.
* src/expr-name.c (expr_name_lookup) : add the notion of active and a
ref count so that we can do a delayed destruction and invalidation.
(expr_name_add) : make it clearer that the return is not meant
to be freed.
(expr_name_create) : don't free the result of expr_name_lookup.
(expr_name_ref) : generalize.
(expr_name_unref) : ditto.
(expr_name_remove) : deactivate the name.
2001-10-27 Almer S. Tigelaar <almer@gnome.org>
* src/GNOME_Gnumeric.xml: Tidy view menu.
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* ms-excel-read.c (biff_name_data_get_name) : adjust to signature
change in expr_tree_new_name. FIXME : how does XL mark names from
explicit scopes.
2001-10-23 Jody Goldberg <jgoldberg@home.com>
* ms-excel-write.c (write_rowinfo) : duplicate code.
......
......@@ -862,7 +862,7 @@ biff_name_data_get_name (ExcelSheet const *esheet, int idx)
}
if (bnd->type == BNDName && bnd->v.name)
return expr_tree_new_name (bnd->v.name);
return expr_tree_new_name (bnd->v.name, NULL, NULL);
return expr_tree_new_constant (value_new_string (bnd->name));
}
......
2001-10-29 Jody Goldberg <jgoldberg@home.com>
* dialog-printer-setup.c (do_print_destroy_cb) : warning suppression.
2001-10-28 Jody Goldberg <jgoldberg@home.com>
* dialog-define-names.c (name_guru_display_scope) : set active on
......
......@@ -278,6 +278,8 @@ name_guru_populate_list (NameGuruState *state)
state->cur_name = NULL;
gtk_list_clear_items (state->list, 0, -1);
g_list_free (state->expr_names);
state->expr_names = sheet_get_available_names (state->sheet);
......@@ -300,7 +302,6 @@ name_guru_populate_list (NameGuruState *state)
name_guru_update_sensitivity (state, TRUE);
}
/**
* cb_name_guru_remove:
* @ignored:
......@@ -312,23 +313,18 @@ static void
cb_name_guru_remove (GtkWidget *ignored, NameGuruState *state)
{
g_return_if_fail (state != NULL);
g_return_if_fail (state->cur_name != NULL);
if (state->cur_name != NULL) {
if (!name_guru_warn (state))
return;
state->expr_names = g_list_remove (state->expr_names, state->cur_name);
expr_name_remove (state->cur_name);
state->cur_name = NULL;
if (!name_guru_warn (state))
return;
gtk_list_clear_items (state->list, 0, -1);
name_guru_populate_list (state);
} else {
g_warning ("Why is the delete button sensitive ? ...\n");
}
state->expr_names = g_list_remove (state->expr_names, state->cur_name);
expr_name_remove (state->cur_name);
state->cur_name = NULL;
name_guru_populate_list (state);
}
/**
* cb_name_guru_add:
* @state:
......@@ -379,7 +375,7 @@ cb_name_guru_add (NameGuruState *state)
gnumeric_notice (state->wbcg, GNOME_MESSAGE_BOX_ERROR,
_("You cannot redefine a builtin name."));
} else {
char *error = NULL;
char const *error = NULL;
ParsePos pos;
if (name_guru_scope_is_sheet (state))
parse_pos_init (&pos, NULL, state->sheet,
......@@ -402,7 +398,6 @@ cb_name_guru_add (NameGuruState *state)
g_return_val_if_fail (expr_name != NULL, FALSE);
gtk_list_clear_items (state->list, 0, -1);
name_guru_populate_list (state);
gtk_widget_grab_focus (GTK_WIDGET (state->name));
......
......@@ -1560,7 +1560,7 @@ do_setup_page (PrinterSetupState *state)
}
static void
do_print_cb (GtkWidget *w, PrinterSetupState *state)
cb_do_print (GtkWidget *w, PrinterSetupState *state)
{
WorkbookControlGUI *wbcg;
Sheet *sheet;
......@@ -1573,20 +1573,20 @@ do_print_cb (GtkWidget *w, PrinterSetupState *state)
}
static void
do_print_preview_cb (GtkWidget *w, PrinterSetupState *state)
cb_do_print_preview (GtkWidget *w, PrinterSetupState *state)
{
fetch_settings (state);
sheet_print (state->wbcg, state->sheet, TRUE, PRINT_ACTIVE_SHEET);
}
static void
do_print_cancel_cb (GtkWidget *w, PrinterSetupState *state)
cb_do_print_cancel (GtkWidget *w, PrinterSetupState *state)
{
gnome_dialog_close (GNOME_DIALOG (state->dialog));
}
static void
do_print_ok_cb (GtkWidget *w, PrinterSetupState *state)
cb_do_print_ok (GtkWidget *w, PrinterSetupState *state)
{
/* Detach BEFORE we finish editing */
wbcg_edit_detach_guru (state->wbcg);
......@@ -1597,7 +1597,7 @@ do_print_ok_cb (GtkWidget *w, PrinterSetupState *state)
}
static void
do_print_set_focus_cb (GtkWidget *window, GtkWidget *focus_widget,
cb_do_print_set_focus (GtkWidget *window, GtkWidget *focus_widget,
PrinterSetupState *state)
{
if (IS_GNUMERIC_EXPR_ENTRY (focus_widget))
......@@ -1608,16 +1608,16 @@ do_print_set_focus_cb (GtkWidget *window, GtkWidget *focus_widget,
}
static void
do_print_destroy_cb (GtkWidget *button, PrinterSetupState *state)
cb_do_print_destroy (GtkWidget *button, PrinterSetupState *state)
{
wbcg_edit_detach_guru (state->wbcg);
wbcg_edit_finish (state->wbcg, FALSE);
if (state->customize_header)
gnome_dialog_close(state->customize_header);
gnome_dialog_close (GNOME_DIALOG (state->customize_header));
if (state->customize_footer)
gnome_dialog_close(state->customize_footer);
gnome_dialog_close (GNOME_DIALOG (state->customize_footer));
printer_setup_state_free (state);
}
......@@ -1635,16 +1635,16 @@ do_setup_main_dialog (PrinterSetupState *state)
w = glade_xml_get_widget (state->gui, "ok");
gtk_signal_connect (GTK_OBJECT (w), "clicked",
GTK_SIGNAL_FUNC (do_print_ok_cb), state);
GTK_SIGNAL_FUNC (cb_do_print_ok), state);
w = glade_xml_get_widget (state->gui, "print");
gtk_signal_connect (GTK_OBJECT (w), "clicked",
GTK_SIGNAL_FUNC (do_print_cb), state);
GTK_SIGNAL_FUNC (cb_do_print), state);
w = glade_xml_get_widget (state->gui, "preview");
gtk_signal_connect (GTK_OBJECT (w), "clicked",
GTK_SIGNAL_FUNC (do_print_preview_cb), state);
GTK_SIGNAL_FUNC (cb_do_print_preview), state);
w = glade_xml_get_widget (state->gui, "cancel");
gtk_signal_connect (GTK_OBJECT (w), "clicked",
GTK_SIGNAL_FUNC (do_print_cancel_cb), state);
GTK_SIGNAL_FUNC (cb_do_print_cancel), state);
/* Hide non-functional buttons for now */
w = glade_xml_get_widget (state->gui, "options");
......@@ -1653,11 +1653,11 @@ do_setup_main_dialog (PrinterSetupState *state)
wbcg_edit_attach_guru (state->wbcg, state->dialog);
gtk_signal_connect (
GTK_OBJECT (state->dialog), "set-focus",
GTK_SIGNAL_FUNC (do_print_set_focus_cb), state);
GTK_SIGNAL_FUNC (cb_do_print_set_focus), state);
/* Lifecyle management */
gtk_signal_connect (GTK_OBJECT (state->dialog), "destroy",
GTK_SIGNAL_FUNC (do_print_destroy_cb),
GTK_SIGNAL_FUNC (cb_do_print_destroy),
(gpointer) state);
}
......
......@@ -25,14 +25,81 @@
/* We don't expect that many global names ! */
static GList *global_names = NULL;
void
expr_name_invalidate_refs_sheet (Sheet const *sheet)
{
#if 0
static gboolean warned = FALSE;
if (!warned)
g_warning ("Implement Me !. expr_name_invalidate_refs_sheet\n");
warned = TRUE;
#endif
}
void
expr_name_invalidate_refs_wb (Workbook const *wb)
{
#if 0
static gboolean warned = FALSE;
if (!warned)
g_warning ("Implement Me !. expr_name_invalidate_refs_wb\n");
warned = TRUE;
#endif
}
static void
cb_collect_name_deps (gpointer key, gpointer value, gpointer user_data)
{
GSList **list = user_data;
*list = g_slist_prepend (*list, key);
}
static GSList *
expr_name_unlink_deps (NamedExpression *nexpr)
{
GSList *ptr, *deps = NULL;
g_hash_table_foreach (nexpr->dependents, cb_collect_name_deps, &deps);
/* pull them out */
for (ptr = deps ; ptr != NULL ; ptr = ptr->next) {
Dependent *dep = ptr->data;
if (dependent_is_linked (dep)) {
CellPos *pos = dependent_is_cell (dep)
? &(DEP_TO_CELL (dep)->pos) : NULL;
dependent_unlink (dep, pos);
}
}
return deps;
}
static void
expr_name_link_deps (GSList *deps)
{
GSList *ptr = deps;
/* put them back */
for (; ptr != NULL ; ptr = ptr->next) {
Dependent *dep = ptr->data;
if (!dependent_is_linked (dep)) {
CellPos *pos = dependent_is_cell (dep)
? &(DEP_TO_CELL (dep)->pos) : NULL;
dependent_link (dep, pos);
cb_dependent_queue_recalc (dep, NULL);
}
}
g_slist_free (deps);
}
static NamedExpression *
expr_name_lookup_list (GList *p, const char *name)
expr_name_lookup_list (GList *p, char const *name)
{
while (p) {
NamedExpression *expr_name = p->data;
g_return_val_if_fail (expr_name != NULL, 0);
if (g_strcasecmp (expr_name->name->str, name) == 0)
return expr_name;
NamedExpression *nexpr = p->data;
g_return_val_if_fail (nexpr != NULL, 0);
if (g_strcasecmp (nexpr->name->str, name) == 0)
return nexpr;
p = g_list_next (p);
}
return NULL;
......@@ -40,7 +107,7 @@ expr_name_lookup_list (GList *p, const char *name)
/* FIXME : Why not use hash tables ? */
NamedExpression *
expr_name_lookup (const ParsePos *pos, const char *name)
expr_name_lookup (ParsePos const *pos, char const *name)
{
NamedExpression *res = NULL;
Sheet const *sheet = NULL;
......@@ -65,21 +132,22 @@ expr_name_lookup (const ParsePos *pos, const char *name)
static NamedExpression *
named_expr_new (char const *name, gboolean builtin)
{
NamedExpression *expr_name;
NamedExpression *nexpr;
g_return_val_if_fail (name != NULL, NULL);
expr_name = g_new0 (NamedExpression,1);
nexpr = g_new0 (NamedExpression,1);
expr_name->ref_count = 1;
expr_name->builtin = builtin;
expr_name->name = string_get (name);
expr_name->dependents =
nexpr->ref_count = 1;
nexpr->builtin = builtin;
nexpr->active = TRUE;
nexpr->name = string_get (name);
nexpr->dependents =
g_hash_table_new (g_direct_hash, g_direct_equal);
g_return_val_if_fail (expr_name->name != NULL, NULL);
g_return_val_if_fail (nexpr->name != NULL, NULL);
return expr_name;
return nexpr;
}
/*
......@@ -87,7 +155,7 @@ named_expr_new (char const *name, gboolean builtin)
* to this one we are checking we will come to serious grief.
*/
static gboolean
name_refer_circular (const char *name, ExprTree *expr)
name_refer_circular (char const *name, ExprTree *expr)
{
g_return_val_if_fail (expr != NULL, TRUE);
......@@ -98,15 +166,15 @@ name_refer_circular (const char *name, ExprTree *expr)
case OPER_ANY_UNARY:
return name_refer_circular (name, expr->unary.value);
case OPER_NAME: {
NamedExpression const *expr_name = expr->name.name;
if (expr_name->builtin)
NamedExpression const *nexpr = expr->name.name;
if (nexpr->builtin)
return FALSE;
if (!g_strcasecmp (expr_name->name->str, name))
if (!g_strcasecmp (nexpr->name->str, name))
return TRUE;
/* And look inside this name tree too */
return name_refer_circular (name, expr_name->t.expr_tree);
return name_refer_circular (name, nexpr->t.expr_tree);
}
case OPER_FUNCALL: {
GList *l = expr->func.arg_list;
......@@ -136,9 +204,9 @@ name_refer_circular (const char *name, ExprTree *expr)
**/
NamedExpression *
expr_name_add (ParsePos const *pp, const char *name,
ExprTree *expr, char **error_msg)
ExprTree *expr, char const **error_msg)
{
NamedExpression *expr_name;
NamedExpression *nexpr;
GList **scope = NULL;
g_return_val_if_fail (pp != NULL, NULL);
......@@ -148,13 +216,16 @@ expr_name_add (ParsePos const *pp, const char *name,
/* printf ("Adding name '%s' to %p %p\n", name, wb, sheet);*/
if (pp->sheet != NULL) {
scope = &(pp->sheet->names);
*error_msg = _("already defined in sheet");
if (error_msg)
*error_msg = _("already defined in sheet");
} else if (pp->wb != NULL) {
scope = &(pp->wb->names);
*error_msg = _("already defined in workbook");
if (error_msg)
*error_msg = _("already defined in workbook");
} else {
scope = &global_names;
*error_msg = _("already globally defined ");
if (error_msg)
*error_msg = _("already globally defined ");
}
if (expr_name_lookup_list (*scope, name) != NULL)
......@@ -163,16 +234,17 @@ expr_name_add (ParsePos const *pp, const char *name,
*error_msg = _("'%s' has a circular reference");
return NULL;
}
*error_msg = NULL;
if (error_msg)
*error_msg = NULL;
expr_name = named_expr_new (name, FALSE);
expr_name->t.expr_tree = expr;
parse_pos_init (&expr_name->pos,
nexpr = named_expr_new (name, FALSE);
nexpr->t.expr_tree = expr;
parse_pos_init (&nexpr->pos,
pp->wb, pp->sheet, pp->eval.col, pp->eval.row);
*scope = g_list_append (*scope, expr_name);
*scope = g_list_append (*scope, nexpr);
return expr_name;
return nexpr;
}
/**
......@@ -180,7 +252,7 @@ expr_name_add (ParsePos const *pp, const char *name,
* @pp:
* @name:
* @value:
* @error_msg:
* @error:
*
* Parses a texual name in @value, and enters the value
* either as a workbook name if @sheet == NULL or a sheet
......@@ -192,7 +264,11 @@ NamedExpression *
expr_name_create (ParsePos const *pp, const char *name,
const char *value, ParseError *error)
{
ExprTree *tree = expr_parse_string (value, pp, NULL, error);
NamedExpression *res;
char const *err = NULL;
ExprTree *tree;
tree = expr_parse_string (value, pp, NULL, error);
if (!tree)
return NULL;
......@@ -200,78 +276,88 @@ expr_name_create (ParsePos const *pp, const char *name,
* use the message part of the struct to pass a name
* creation error back to the calling routine
*/
return expr_name_add (pp, name, tree, &error->message);
res = expr_name_add (pp, name, tree, &err);
if (err != NULL)
error->message = g_strdup (err);
return res;
}
void
expr_name_ref (NamedExpression *expr_name)
expr_name_ref (NamedExpression *nexpr)
{
g_return_if_fail (expr_name != NULL);
g_return_if_fail (nexpr != NULL);
expr_name->ref_count++;
nexpr->ref_count++;
}
void
expr_name_unref (NamedExpression *expr_name)
expr_name_unref (NamedExpression *nexpr)
{
g_return_if_fail (expr_name != NULL);
g_return_if_fail (nexpr != NULL);
if (expr_name->ref_count-- > 1)
if (nexpr->ref_count-- > 1)
return;
if (expr_name->name) {
string_unref (expr_name->name);
expr_name->name = NULL;
if (nexpr->name) {
string_unref (nexpr->name);
nexpr->name = NULL;
}
if (!expr_name->builtin && expr_name->t.expr_tree) {
expr_tree_unref (expr_name->t.expr_tree);
expr_name->t.expr_tree = NULL;
if (!nexpr->builtin && nexpr->t.expr_tree) {
expr_tree_unref (nexpr->t.expr_tree);
nexpr->t.expr_tree = NULL;
}
if (expr_name->dependents != NULL) {
g_hash_table_destroy (expr_name->dependents);
expr_name->dependents = NULL;
if (nexpr->dependents != NULL) {
g_hash_table_destroy (nexpr->dependents);
nexpr->dependents = NULL;
}
expr_name->pos.wb = NULL;
expr_name->pos.sheet = NULL;
nexpr->pos.wb = NULL;
nexpr->pos.sheet = NULL;
g_free (expr_name);
g_free (nexpr);
}
static void
expr_name_unlink (NamedExpression *expr_name)
expr_name_unlink (NamedExpression *nexpr)
{
Workbook *wb = NULL;
Sheet *sheet = NULL;
/* printf ("Removing : '%s'\n", expr_name->name->str);*/
if (expr_name->pos.sheet) {
sheet = expr_name->pos.sheet;
g_return_if_fail (g_list_find (sheet->names, expr_name) != NULL);
sheet->names = g_list_remove (sheet->names, expr_name);
} else if (expr_name->pos.wb) {
wb = expr_name->pos.wb;
g_return_if_fail (g_list_find (wb->names, expr_name) != NULL);
wb->names = g_list_remove (wb->names, expr_name);
/* printf ("Removing : '%s'\n", nexpr->name->str);*/
if (nexpr->pos.sheet) {
sheet = nexpr->pos.sheet;
g_return_if_fail (g_list_find (sheet->names, nexpr) != NULL);
sheet->names = g_list_remove (sheet->names, nexpr);
} else if (nexpr->pos.wb) {
wb = nexpr->pos.wb;
g_return_if_fail (g_list_find (wb->names, nexpr) != NULL);
wb->names = g_list_remove (wb->names, nexpr);
} else {
g_return_if_fail (g_list_find (global_names, expr_name) != NULL);
global_names = g_list_remove (global_names, expr_name);
g_return_if_fail (g_list_find (global_names, nexpr) != NULL);
global_names = g_list_remove (global_names, nexpr);
}
}
static void
expr_name_invalidate_refs (NamedExpression *nexpr)
{
}
void
expr_name_remove (NamedExpression *expr_name)
expr_name_remove (NamedExpression *nexpr)
{
g_return_if_fail (expr_name != NULL);
g_return_if_fail (nexpr != NULL);
g_return_if_fail (nexpr->active);
expr_name_unlink (expr_name);
expr_name_invalidate_refs_name (expr_name);
expr_name_unref (expr_name);
expr_name_unlink (nexpr);
expr_name_invalidate_refs (nexpr);
nexpr->active = FALSE;
expr_name_unref (nexpr);
}
/*
/**
* expr_name_list_destroy :
*
* Frees names in the local scope.
......@@ -289,8 +375,9 @@ expr_name_list_destroy (GList *names)
/* Empty the name list */
for (p = names ; p != NULL ; p = g_list_next (p)) {
NamedExpression *expr_name = p->data;
expr_name_unref (expr_name);
NamedExpression *nexpr = p->data;
nexpr->active = FALSE;
expr_name_unref (nexpr);
}
g_list_free (names);
return NULL;
......@@ -315,100 +402,28 @@ expr_name_as_string (NamedExpression const *nexpr, ParsePos const *pp)
}
Value *
expr_name_eval (NamedExpression const *expr_name,
expr_name_eval (NamedExpression const *nexpr,
EvalPos const *pos, ExprEvalFlags flags)
{
g_return_val_if_fail (pos, NULL);
if (!expr_name)
if (!nexpr)
return value_new_error (pos, gnumeric_err_NAME);
if (