[gnumeric] Validations: fix handling of expressions.



commit a5e192efbc781e2aee4a8fc6c2bc54e45991aa8c
Author: Morten Welinder <terra gnome org>
Date:   Thu May 10 15:58:40 2012 -0400

    Validations: fix handling of expressions.
    
    With this change we use managed dependents which in turn means that the
    expressions will auto-update as needed when rows or columns are inserted
    or deleted.

 ChangeLog                               |   20 ++++++++
 NEWS                                    |    1 +
 plugins/excel/ms-excel-read.c           |    4 +-
 plugins/excel/ms-excel-write.c          |   16 +++---
 plugins/excel/xlsx-read.c               |    7 ++-
 plugins/excel/xlsx-write.c              |    4 +-
 plugins/openoffice/openoffice-read.c    |   13 +++--
 plugins/openoffice/openoffice-write.c   |   34 +++++++-------
 src/dialogs/dialog-cell-format.c        |    8 ++-
 src/mstyle.c                            |   15 +++++--
 src/sheet-style.c                       |   14 +++++-
 src/validation.c                        |   75 +++++++++++++++++-------------
 src/validation.h                        |    4 +-
 src/widgets/gnm-validation-combo-view.c |    4 +-
 src/workbook.c                          |   21 +++-----
 src/xml-sax-read.c                      |    1 +
 src/xml-sax-write.c                     |    8 ++--
 test/GnumericTest.pm                    |    4 ++
 18 files changed, 158 insertions(+), 95 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b8602b7..bca40ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2012-05-10  Morten Welinder  <terra gnome org>
+
+	* src/workbook.c (workbook_dispose): Dispose of views early.
+	(This is desirable since the views hold the auto-expression value
+	which in turn may references sheets via validations in the
+	format.)
+
+	* src/validation.h (GnmValidation): Use GnmDependent, not raw
+	GnmExprTop, for storing expressions.  All users changed.
+
+	* src/validation.c (validation_new): Add new "sheet" argument.
+	All callers changed.  Hook up expressions as managed dependents.
+	Fixes #674914.
+
+	* src/sheet-style.c (GnmSheetStyleData): Document the rules for
+	the style_hash member.
+
+	* src/mstyle.c (gnm_style_update): Don't use the validation's
+	address for the hash value -- use just whether it is NULL.
+
 2012-05-02  Morten Welinder  <terra gnome org>
 
 	* src/wbc-gtk.c (wbc_gtk_create_status_area): Get the
diff --git a/NEWS b/NEWS
index 31e9aac..f6a0207 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ Andreas:
 Morten:
 	* Minor doc improvement for non-C locales.  [Part of #675000]
 	* Fix fullscreen criticals.
+	* Improve handling of expressions in validations.  [#674914]
 
 --------------------------------------------------------------------------
 Gnumeric 1.11.3
diff --git a/plugins/excel/ms-excel-read.c b/plugins/excel/ms-excel-read.c
index 52e1a72..312f885 100644
--- a/plugins/excel/ms-excel-read.c
+++ b/plugins/excel/ms-excel-read.c
@@ -5523,7 +5523,9 @@ excel_read_DV (BiffQuery *q, ExcelReadSheet *esheet)
 	mstyle = gnm_style_new ();
 	gnm_style_set_validation
 		(mstyle,
-		 validation_new (style, type, op, error_title, error_msg,
+		 validation_new (style, type, op,
+				 esheet->sheet,
+				 error_title, error_msg,
 				 texpr1,
 				 texpr2,
 				 options & 0x0100, 0 == (options & 0x0200)));
diff --git a/plugins/excel/ms-excel-write.c b/plugins/excel/ms-excel-write.c
index 47acb52..8671b2b 100644
--- a/plugins/excel/ms-excel-write.c
+++ b/plugins/excel/ms-excel-write.c
@@ -1256,10 +1256,10 @@ excel_write_DV (XLValInputPair const *vip, gpointer dummy, ExcelWriteSheet *eshe
 	GSF_LE_SET_GUINT16 (data+2, 0); /* Undocumented, use 0 for now */
 	ms_biff_put_var_write (bp, data, 4);
 
-	if (vip->v != NULL && vip->v->texpr[0] != NULL) {
+	if (vip->v != NULL && vip->v->deps[0].texpr != NULL) {
 		unsigned pos = bp->curpos;
 		guint16 len = excel_write_formula (esheet->ewb,
-				vip->v->texpr[0],
+				vip->v->deps[0].texpr,
 				esheet->gnum_sheet, col, row,
 				EXCEL_CALLED_FROM_VALIDATION);
 		unsigned end_pos = bp->curpos;
@@ -1272,10 +1272,10 @@ excel_write_DV (XLValInputPair const *vip, gpointer dummy, ExcelWriteSheet *eshe
 	GSF_LE_SET_GUINT16 (data  , 0); /* bogus len fill in later */
 	GSF_LE_SET_GUINT16 (data+2, 0); /* Undocumented, use 0 for now */
 	ms_biff_put_var_write (bp, data, 4);
-	if (vip->v != NULL && vip->v->texpr[1] != NULL) {
+	if (vip->v != NULL && vip->v->deps[1].texpr != NULL) {
 		unsigned pos = bp->curpos;
 		guint16 len = excel_write_formula (esheet->ewb,
-				vip->v->texpr[1],
+				vip->v->deps[1].texpr,
 				esheet->gnum_sheet, col, row,
 				EXCEL_CALLED_FROM_VALIDATION);
 		unsigned end_pos = bp->curpos;
@@ -1529,10 +1529,10 @@ excel_write_prep_validations (ExcelWriteSheet *esheet)
 	for (; ptr != NULL ; ptr = ptr->next) {
 		sr = ptr->data;
 		v  = gnm_style_get_validation (sr->style);
-		if (v->texpr[0] != NULL)
-			excel_write_prep_expr (esheet->ewb, v->texpr[0]);
-		if (v->texpr[1] != NULL)
-			excel_write_prep_expr (esheet->ewb, v->texpr[1]);
+		if (v->deps[0].texpr != NULL)
+			excel_write_prep_expr (esheet->ewb, v->deps[0].texpr);
+		if (v->deps[1].texpr != NULL)
+			excel_write_prep_expr (esheet->ewb, v->deps[1].texpr);
 	}
 }
 
diff --git a/plugins/excel/xlsx-read.c b/plugins/excel/xlsx-read.c
index f5bff91..79e371a 100644
--- a/plugins/excel/xlsx-read.c
+++ b/plugins/excel/xlsx-read.c
@@ -1744,8 +1744,11 @@ xlsx_CT_DataValidation_begin (GsfXMLIn *xin, xmlChar const **attrs)
 	if (showErrorMessage) {
 		GnmRange const *r = state->validation_regions->data;
 		state->pos = r->start;
-		state->validation = validation_new (val_style, val_type, val_op,
-			errorTitle, error, NULL, NULL, allowBlank, showDropDown);
+		state->validation = validation_new
+			(val_style, val_type, val_op,
+			 state->sheet,
+			 errorTitle, error,
+			 NULL, NULL, allowBlank, showDropDown);
 	}
 
 	if (showInputMessage && (NULL != promptTitle || NULL != prompt))
diff --git a/plugins/excel/xlsx-write.c b/plugins/excel/xlsx-write.c
index ace5c07..413c2ce 100644
--- a/plugins/excel/xlsx-write.c
+++ b/plugins/excel/xlsx-write.c
@@ -1416,9 +1416,9 @@ xlsx_write_validation (XLValInputPair const *vip, gpointer dummy, XLSXClosure *i
 	if (NULL != vip->v) {
 		GnmRange const *first = vip->ranges->data;
 		xlsx_write_validation_expr (info, &first->start,
-			"formula1", vip->v->texpr[0]);
+			"formula1", vip->v->deps[0].texpr);
 		xlsx_write_validation_expr (info, &first->start,
-			"formula2", vip->v->texpr[1]);
+			"formula2", vip->v->deps[1].texpr);
 	}
 
 	gsf_xml_out_end_element (info->xml); /*  </dataValidation> */
diff --git a/plugins/openoffice/openoffice-read.c b/plugins/openoffice/openoffice-read.c
index 2c9e051..2df37f2 100644
--- a/plugins/openoffice/openoffice-read.c
+++ b/plugins/openoffice/openoffice-read.c
@@ -2242,7 +2242,7 @@ odf_validation_new_list (GsfXMLIn *xin, odf_validation_t *val, guint offset)
 	char *start = NULL, *end = NULL;
 	GString *str;
 	GnmExprTop const *texpr = NULL;
-	GnmParsePos   pp;
+	GnmParsePos pp;
 
 
 	start = strchr (val->condition + offset, '(');
@@ -2287,6 +2287,7 @@ odf_validation_new_list (GsfXMLIn *xin, odf_validation_t *val, guint offset)
 		validation = validation_new (val->style,
 					     GNM_VALIDATION_TYPE_IN_LIST,
 					     GNM_VALIDATION_OP_NONE,
+					     state->pos.sheet,
 					     val->title, 
 					     val->message->str,
 					     texpr,
@@ -2301,12 +2302,12 @@ odf_validation_new_list (GsfXMLIn *xin, odf_validation_t *val, guint offset)
 
 static GnmValidation *
 odf_validation_new_single_expr (GsfXMLIn *xin, odf_validation_t *val,
-				    char const *start, ValidationType val_type,
-				    ValidationOp val_op)
+				char const *start, ValidationType val_type,
+				ValidationOp val_op)
 {
 	OOParseState *state = (OOParseState *)xin->user_state;
 	GnmExprTop const *texpr = NULL;
-	GnmParsePos   pp;
+	GnmParsePos pp;
 
 	pp = state->pos;
 	if (val->base_cell_address != NULL) {
@@ -2335,6 +2336,7 @@ odf_validation_new_single_expr (GsfXMLIn *xin, odf_validation_t *val,
 		return validation_new (val->style,
 				       val_type,
 				       val_op,
+				       state->pos.sheet,
 				       val->title, 
 				       val->message->str,
 				       texpr,
@@ -2351,7 +2353,7 @@ odf_validation_new_pair_expr (GsfXMLIn *xin, odf_validation_t *val,
 {
 	OOParseState *state = (OOParseState *)xin->user_state;
 	GnmExprTop const *texpr = NULL;
-	GnmParsePos   pp;
+	GnmParsePos pp;
 	GnmExprTop const *texpr_a = NULL, *texpr_b = NULL;
 	char *pair = NULL;
 	guint len = strlen (start);
@@ -2408,6 +2410,7 @@ odf_validation_new_pair_expr (GsfXMLIn *xin, odf_validation_t *val,
 		return validation_new (val->style,
 				       val_type,
 				       val_op,
+				       state->pos.sheet,
 				       val->title, 
 				       val->message->str,
 				       texpr_a,
diff --git a/plugins/openoffice/openoffice-write.c b/plugins/openoffice/openoffice-write.c
index bfdb6d1..3648751 100644
--- a/plugins/openoffice/openoffice-write.c
+++ b/plugins/openoffice/openoffice-write.c
@@ -4080,9 +4080,11 @@ odf_validation_append_expression_pair (GnmOOExport *state, GString *str,
 				       GnmParsePos *pp)
 {
 		str = g_string_append_c (str, '(');
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str,
+						  val->deps[0].texpr, pp);
 		str = g_string_append_c (str, ',');
-		odf_validation_append_expression (state, str, val->texpr[1], pp);
+		odf_validation_append_expression (state, str,
+						  val->deps[1].texpr, pp);
 		str = g_string_append_c (str, ')');
 }
 
@@ -4111,27 +4113,27 @@ odf_validation_general (GnmOOExport *state, GnmValidation const *val,
 		break;
 	case GNM_VALIDATION_OP_EQUAL:
 		str = g_string_append (str, "cell-content() = ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_NOT_EQUAL:
 		str = g_string_append (str, "cell-content() != ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_GT:
 		str = g_string_append (str, "cell-content() > ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_LT:
 		str = g_string_append (str, "cell-content() < ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_GTE:
 		str = g_string_append (str, "cell-content() >= ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_LTE:
 		str = g_string_append (str, "cell-content() <= ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	}
 
@@ -4160,27 +4162,27 @@ odf_validation_length (GnmOOExport *state, GnmValidation const *val,
 		break;
 	case GNM_VALIDATION_OP_EQUAL:
 		str = g_string_append (str, "cell-content-text-length() = ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_NOT_EQUAL:
 		str = g_string_append (str, "cell-content-text-length() != ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_GT:
 		str = g_string_append (str, "cell-content-text-length() > ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_LT:
 		str = g_string_append (str, "cell-content-text-length() < ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_GTE:
 		str = g_string_append (str, "of:cell-content-text-length() >= ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	case GNM_VALIDATION_OP_LTE:
 		str = g_string_append (str, "cell-content-text-length() <= ");
-		odf_validation_append_expression (state, str, val->texpr[0], pp);
+		odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 		break;
 	}
 
@@ -4196,7 +4198,7 @@ odf_validation_custom (GnmOOExport *state, GnmValidation const *val,
 	GString *str = g_string_new (NULL);
 
 	str = g_string_append (str, "of:is-true-formula(");
-	odf_validation_append_expression (state, str, val->texpr[0], pp);
+	odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 	str = g_string_append_c (str, ')');
 
 	gsf_xml_out_add_cstr (state->xml, TABLE "condition", str->str);
@@ -4211,7 +4213,7 @@ odf_validation_in_list (GnmOOExport *state, GnmValidation const *val,
 	GString *str;
 
 	str = g_string_new ("of:cell-content-is-in-list(");
-	odf_validation_append_expression (state, str, val->texpr[0], pp);
+	odf_validation_append_expression (state, str, val->deps[0].texpr, pp);
 	str = g_string_append_c (str, ')');
 
 	gsf_xml_out_add_cstr (state->xml, TABLE "condition", str->str);
diff --git a/src/dialogs/dialog-cell-format.c b/src/dialogs/dialog-cell-format.c
index 328d673..b40d8bf 100644
--- a/src/dialogs/dialog-cell-format.c
+++ b/src/dialogs/dialog-cell-format.c
@@ -1607,7 +1607,9 @@ validation_rebuild_validation (FormatState *state)
 			gnm_style_set_validation
 				(state->result,
 				 validation_new
-				 (style, type, op, title, msg,
+				 (style, type, op,
+				  state->sheet,
+				  title, msg,
 				  texpr0,
 				  texpr1,
 				  allow_blank,
@@ -1905,9 +1907,9 @@ fmt_dialog_init_validation_page (FormatState *state)
 		parse_pos_init (&pp, state->sheet->workbook, state->sheet,
 			state->sv->edit_pos.col, state->sv->edit_pos.row);
 		gnm_expr_entry_load_from_expr (state->validation.expr0.entry,
-			v->texpr[0], &pp);
+					       v->deps[0].texpr, &pp);
 		gnm_expr_entry_load_from_expr (state->validation.expr1.entry,
-			v->texpr[1], &pp);
+					       v->deps[1].texpr, &pp);
 	}
 
 	cb_validation_sensitivity (NULL, state);
diff --git a/src/mstyle.c b/src/mstyle.c
index ca8e27f..ebf02d3 100644
--- a/src/mstyle.c
+++ b/src/mstyle.c
@@ -243,7 +243,8 @@ gnm_style_update (GnmStyle *style)
 
 	/* From here on, fields are not in MS XL */
 
-	hash ^= GPOINTER_TO_UINT (style->validation);
+	if (style->validation)
+		hash ^= 0x1379;
 	hash = (hash << 7) ^ (hash >> (sizeof (hash) * 8 - 7));
 
 	hash ^= GPOINTER_TO_UINT (style->hlink);
@@ -339,6 +340,12 @@ gnm_style_hash (gconstpointer style)
     ? a->conditions == b->conditions					\
     : FALSE)))))))))))))))))))))))))
 
+/*
+ * Note: the above is suboptimal from validation and down.
+ *
+ * We are comparing pointers (which at least safely matches what we do
+ * with the hash), but I think we want proper equality.
+ */
 
 static gboolean
 elem_is_eq (GnmStyle const *a, GnmStyle const *b, GnmStyleElement elem)
@@ -424,16 +431,16 @@ elem_clear_contents (GnmStyle *style, GnmStyleElement elem)
 		return;
 	case MSTYLE_HLINK:
 		if (style->hlink)
-			g_object_unref (G_OBJECT (style->hlink));
+			g_object_unref (style->hlink);
 		return;
 	case MSTYLE_INPUT_MSG:
 		if (style->input_msg)
-			g_object_unref (G_OBJECT (style->input_msg));
+			g_object_unref (style->input_msg);
 		return;
 	case MSTYLE_CONDITIONS:
 		if (style->conditions) {
 			clear_conditional_merges (style);
-			g_object_unref (G_OBJECT (style->conditions));
+			g_object_unref (style->conditions);
 		}
 		return;
 	default:
diff --git a/src/sheet-style.c b/src/sheet-style.c
index af2399f..f076e4e 100644
--- a/src/sheet-style.c
+++ b/src/sheet-style.c
@@ -41,7 +41,18 @@
 
 typedef union _CellTile CellTile;
 struct _GnmSheetStyleData {
+	/*
+	 * style_hash is a set of all styles used by this sheet.  These
+	 * styles are all linked.
+	 *
+	 * We always re-use styles from here when we can, but there can
+	 * still be duplicates.  This happens when styles are changed
+	 * while they are in the hash; such changes maintain the hash
+	 * value.  For example, this happens when an expression used by
+	 * a validation style changes due to row/col insert/delete.
+	 */
 	GHashTable *style_hash;
+
 	CellTile   *styles;
 	GnmStyle   *default_style;
 	GnmColor   *auto_pattern_color;
@@ -535,7 +546,8 @@ sheet_style_init_size (Sheet *sheet, int cols, int rows)
 
 	sheet->style_data = g_new (GnmSheetStyleData, 1);
 	sheet->style_data->style_hash =
-		g_hash_table_new (gnm_style_hash, (GCompareFunc) gnm_style_equal);
+		g_hash_table_new (gnm_style_hash,
+				  (GCompareFunc) gnm_style_equal);
 #warning "FIXME: Allocating a GnmColor here is dubious."
 	sheet->style_data->auto_pattern_color = g_new (GnmColor, 1);
 	*sheet->style_data->auto_pattern_color =  *style_color_auto_pattern ();
diff --git a/src/validation.c b/src/validation.c
index fa60cbb..8da03ee 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -245,19 +245,21 @@ gnm_validation_op_get_type (void)
  **/
 GnmValidation *
 validation_new (ValidationStyle style,
-		ValidationType  type,
-		ValidationOp    op,
+		ValidationType type,
+		ValidationOp op,
+		Sheet *sheet,
 		char const *title, char const *msg,
 		GnmExprTop const *texpr0, GnmExprTop const *texpr1,
 		gboolean allow_blank, gboolean use_dropdown)
 {
 	GnmValidation *v;
-	int nops, i;
+	int nops;
 
 	g_return_val_if_fail (type >= 0, NULL);
 	g_return_val_if_fail (type < G_N_ELEMENTS (typeinfo), NULL);
 	g_return_val_if_fail (op >= GNM_VALIDATION_OP_NONE, NULL);
 	g_return_val_if_fail (op < (int)G_N_ELEMENTS (opinfo), NULL);
+	g_return_val_if_fail (IS_SHEET (sheet), NULL);
 
 	switch (type) {
 	case GNM_VALIDATION_TYPE_CUSTOM:
@@ -282,21 +284,27 @@ validation_new (ValidationStyle style,
 	v->ref_count = 1;
 	v->title = title && title[0] ? go_string_new (title) : NULL;
 	v->msg = msg && msg[0] ? go_string_new (msg) : NULL;
-	v->texpr[0] = texpr0;
-	v->texpr[1] = texpr1;
+
+	dependent_managed_init (&v->deps[0], sheet);
+	if (texpr0) {
+		if (nops > 0)
+			dependent_managed_set_expr (&v->deps[0], texpr0);
+		gnm_expr_top_unref (texpr0);
+	}
+
+	dependent_managed_init (&v->deps[1], sheet);
+	if (texpr1) {
+		if (nops > 1)
+			dependent_managed_set_expr (&v->deps[1], texpr1);
+		gnm_expr_top_unref (texpr1);
+	}
+
 	v->style = style;
 	v->type = type;
 	v->op = op;
 	v->allow_blank = (allow_blank != FALSE);
 	v->use_dropdown = (use_dropdown != FALSE);
 
-	/* Clear excess expressions.  */
-	for (i = nops; i < 2; i++)
-		if (v->texpr[i]) {
-			gnm_expr_top_unref (v->texpr[i]);
-			v->texpr[i] = NULL;
-		}
-
 	return v;
 }
 
@@ -328,10 +336,7 @@ validation_unref (GnmValidation const *val)
 			v->msg = NULL;
 		}
 		for (i = 0 ; i < 2 ; i++)
-			if (v->texpr[i] != NULL) {
-				gnm_expr_top_unref (v->texpr[i]);
-				v->texpr[i] = NULL;
-			}
+			dependent_managed_set_expr (&v->deps[i], NULL);
 		g_free (v);
 	}
 }
@@ -343,7 +348,7 @@ validation_unref (GnmValidation const *val)
  * @indx : 0 or 1
  *
  * Assign an expression to a validation.  validation_is_ok can be used to
- * verify that @v has all of the requisit information.
+ * verify that @v has all of the required information.
  **/
 void
 validation_set_expr (GnmValidation *v,
@@ -351,11 +356,7 @@ validation_set_expr (GnmValidation *v,
 {
 	g_return_if_fail (indx <= 1);
 
-	if (NULL != texpr)
-		gnm_expr_top_ref (texpr);
-	if (NULL != v->texpr[indx])
-		gnm_expr_top_unref (v->texpr[indx]);
-	v->texpr[indx] = texpr;
+	dependent_managed_set_expr (&v->deps[indx], texpr);
 }
 
 GError *
@@ -365,13 +366,17 @@ validation_is_ok (GnmValidation const *v)
 
 	switch (v->type) {
 	case GNM_VALIDATION_TYPE_CUSTOM:
-	case GNM_VALIDATION_TYPE_IN_LIST:	nops = 1; break;
-	case GNM_VALIDATION_TYPE_ANY:	nops = 0; break;
+	case GNM_VALIDATION_TYPE_IN_LIST:
+		nops = 1;
+		break;
+	case GNM_VALIDATION_TYPE_ANY:
+		nops = 0;
+		break;
 	default: nops = (v->op == GNM_VALIDATION_OP_NONE) ? 0 : opinfo[v->op].nops;
 	}
 
 	for (i = 0 ; i < 2 ; i++)
-		if (v->texpr[i] == NULL) {
+		if (v->deps[i].texpr == NULL) {
 			if (i < nops)
 				return g_error_new (1, 0, N_("Missing formula for validation"));
 		} else {
@@ -504,9 +509,11 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 		x = value_get_as_float (val);
 		break;
 
-	case GNM_VALIDATION_TYPE_IN_LIST:
-		if (NULL != v->texpr[0]) {
-			GnmValue *list = gnm_expr_top_eval (v->texpr[0], &ep,
+	case GNM_VALIDATION_TYPE_IN_LIST: {
+		GnmExprTop const *texpr = v->deps[0].texpr;
+		if (texpr) {
+			GnmValue *list = gnm_expr_top_eval
+				(texpr, &ep,
 				 GNM_EXPR_EVAL_PERMIT_NON_SCALAR | GNM_EXPR_EVAL_PERMIT_EMPTY);
 			GnmValue *res = value_area_foreach (list, &ep, CELL_ITER_IGNORE_BLANK,
 				 (GnmValueIterFunc) cb_validate_custom, val);
@@ -514,7 +521,7 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 			if (res == NULL) {
 				GnmParsePos pp;
 				char *expr_str = gnm_expr_top_as_string
-					(v->texpr[0],
+					(texpr,
 					 parse_pos_init_evalpos (&pp, &ep),
 					 ep.sheet->convs);
 				char *msg = g_strdup_printf (_("%s does not contain the new value."), expr_str);
@@ -523,6 +530,7 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 			}
 		}
 		return GNM_VALIDATION_STATUS_VALID;
+	}
 
 	case GNM_VALIDATION_TYPE_TEXT_LENGTH:
 		/* XL appears to use a very basic value->string mapping that
@@ -535,11 +543,12 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 
 	case GNM_VALIDATION_TYPE_CUSTOM: {
 		gboolean valid;
+		GnmExprTop const *texpr = v->deps[0].texpr;
 
-		if (v->texpr[0] == NULL)
+		if (!texpr)
 			return GNM_VALIDATION_STATUS_VALID;
 
-		val = gnm_expr_top_eval (v->texpr[0], &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
+		val = gnm_expr_top_eval (texpr, &ep, GNM_EXPR_EVAL_SCALAR_NON_EMPTY);
 		valid = value_get_as_bool (val, NULL);
 		value_release (val);
 
@@ -548,7 +557,7 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 		else {
 			GnmParsePos pp;
 			char *expr_str = gnm_expr_top_as_string
-				(v->texpr[0],
+				(texpr,
 				 parse_pos_init_evalpos (&pp, &ep),
 				 ep.sheet->convs);
 			char *msg = g_strdup_printf (_("%s is not true."), expr_str);
@@ -567,7 +576,7 @@ validation_eval (WorkbookControl *wbc, GnmStyle const *mstyle,
 
 	nok = 0;
 	for (i = 0; i < opinfo[v->op].nops; i++) {
-		GnmExprTop const *texpr_i = v->texpr[i];
+		GnmExprTop const *texpr_i = v->deps[i].texpr;
 		GnmExprTop const *texpr;
 		GnmValue *cres;
 
diff --git a/src/validation.h b/src/validation.h
index b8adb64..e88604d 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -3,6 +3,7 @@
 # define _GNM_VALIDATION_H_
 
 #include "gnumeric.h"
+#include "dependent.h"
 
 G_BEGIN_DECLS
 
@@ -45,7 +46,7 @@ struct _GnmValidation {
 
 	GOString         *title;
 	GOString         *msg;
-	GnmExprTop const *texpr[2];
+	GnmDependent      deps[2];
 	ValidationStyle   style;
 	ValidationType	  type;
 	ValidationOp	  op;
@@ -66,6 +67,7 @@ GType gnm_validation_op_get_type (void);
 GnmValidation *validation_new   (ValidationStyle style,
 				 ValidationType type,
 				 ValidationOp op,
+				 Sheet *sheet,
 				 char const *title, char const *msg,
 				 GnmExprTop const *texpr0,
 				 GnmExprTop const *texpr1,
diff --git a/src/widgets/gnm-validation-combo-view.c b/src/widgets/gnm-validation-combo-view.c
index 307b786..df048da 100644
--- a/src/widgets/gnm-validation-combo-view.c
+++ b/src/widgets/gnm-validation-combo-view.c
@@ -107,11 +107,11 @@ vcombo_create_list (SheetObject *so,
 
 	g_return_val_if_fail (val != NULL, NULL);
 	g_return_val_if_fail (val->type == GNM_VALIDATION_TYPE_IN_LIST, NULL);
-	g_return_val_if_fail (val->texpr[0] != NULL, NULL);
+	g_return_val_if_fail (val->deps[0].texpr != NULL, NULL);
 	g_return_val_if_fail (sv != NULL, NULL);
 
 	eval_pos_init_editpos (&ep, sv);
-	v = gnm_expr_top_eval (val->texpr[0], &ep,
+	v = gnm_expr_top_eval (val->deps[0].texpr, &ep,
 			       GNM_EXPR_EVAL_PERMIT_NON_SCALAR |
 			       GNM_EXPR_EVAL_PERMIT_EMPTY |
 			       GNM_EXPR_EVAL_ARRAY_CONTEXT);
diff --git a/src/workbook.c b/src/workbook.c
index edf1281..60ad994 100644
--- a/src/workbook.c
+++ b/src/workbook.c
@@ -108,6 +108,14 @@ workbook_dispose (GObject *wb_object)
 	WORKBOOK_FOREACH_CONTROL (wb, view, control,
 		wb_control_sheet_remove_all (control););
 
+	/* Get rid of all the views */
+	WORKBOOK_FOREACH_VIEW (wb, wbv, {
+		wb_view_detach_from_workbook (wbv);
+		g_object_unref (wbv);
+	});
+	if (wb->wb_views != NULL)
+		g_warning ("Unexpected left over views");
+
 	command_list_release (wb->undo_commands);
 	wb->undo_commands = NULL;
 	command_list_release (wb->redo_commands);
@@ -132,19 +140,6 @@ workbook_dispose (GObject *wb_object)
 	}
 	g_slist_free (sheets);
 
-	/* TODO : This should be earlier when we figure out how to deal with
-	 * the issue raised by 'pristine'.
-	 */
-	/* Get rid of all the views */
-	if (wb->wb_views != NULL) {
-		WORKBOOK_FOREACH_VIEW (wb, wbv, {
-			wb_view_detach_from_workbook (wbv);
-			g_object_unref (wbv);
-		});
-		if (wb->wb_views != NULL)
-			g_warning ("Unexpected left over views");
-	}
-
 	workbook_parent_class->dispose (wb_object);
 }
 
diff --git a/src/xml-sax-read.c b/src/xml-sax-read.c
index 98c0d0e..b438bff 100644
--- a/src/xml-sax-read.c
+++ b/src/xml-sax-read.c
@@ -1629,6 +1629,7 @@ xml_sax_validation_end (GsfXMLIn *xin, G_GNUC_UNUSED GsfXMLBlob *blob)
 		validation_new (state->validation.style,
 				state->validation.type,
 				state->validation.op,
+				state->sheet,
 				state->validation.title,
 				state->validation.msg,
 				state->validation.texpr[0],
diff --git a/src/xml-sax-write.c b/src/xml-sax-write.c
index a41be86..a0c6f44 100644
--- a/src/xml-sax-write.c
+++ b/src/xml-sax-write.c
@@ -579,13 +579,13 @@ xml_write_style (GnmOutputXML *state, GnmStyle const *style)
 
 		parse_pos_init_sheet (&pp, (Sheet *)state->sheet);
 
-		if (v->texpr[0] != NULL &&
-		    (tmp = gnm_expr_top_as_string (v->texpr[0], &pp, state->convs)) != NULL) {
+		if (v->deps[0].texpr != NULL &&
+		    (tmp = gnm_expr_top_as_string (v->deps[0].texpr, &pp, state->convs)) != NULL) {
 			gsf_xml_out_simple_element (state->output, GNM "Expression0", tmp);
 			g_free (tmp);
 		}
-		if (v->texpr[1] != NULL &&
-		    (tmp = gnm_expr_top_as_string (v->texpr[1], &pp, state->convs)) != NULL) {
+		if (v->deps[1].texpr != NULL &&
+		    (tmp = gnm_expr_top_as_string (v->deps[1].texpr, &pp, state->convs)) != NULL) {
 			gsf_xml_out_simple_element (state->output, GNM "Expression1", tmp);
 			g_free (tmp);
 		}
diff --git a/test/GnumericTest.pm b/test/GnumericTest.pm
index a7a630f..4f7d482 100644
--- a/test/GnumericTest.pm
+++ b/test/GnumericTest.pm
@@ -326,6 +326,10 @@ sub test_exporter {
     $code = system ("$ssconvert '$file' '$tmp1' 2>&1 | sed -e 's/^/| /'");
     &system_failure ($ssconvert, $code) if $code;
 
+    print STDERR "file=$file\n";
+    print STDERR "tmp1=$tmp1\n";
+    system ("ls -lart | tail");
+
     my $tmp2 = "$tmp-new.$ext";
     &junkfile ($tmp2) unless $keep;
     $code = system ("$ssconvert '$file' '$tmp2' 2>&1 | sed -e 's/^/| /'");



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]