[gnumeric] Check whether defined names are in use before deleting them.



commit a49b3b39590c9cb69013d3bf1b0c5a5dedbc168a
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Sun Jun 6 15:01:47 2010 -0600

    Check whether defined names are in use before deleting them.
    
    2010-06-06 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* dialog-define-names.c (name_guru_warn): implement
    
    2010-06-06 Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* src/expr-name.h (expr_name_in_use): new
    	* src/expr-name.c (expr_name_in_use): new
    	(do_expr_name_loop_check): add argument and change all callers
    	(cb_expr_name_check_for_name): new
    	(cb_expr_name_check_for_name_eq): new
    	(expr_name_check_for_name): new

 ChangeLog                         |    9 +++
 NEWS                              |    1 +
 src/dialogs/ChangeLog             |    4 +
 src/dialogs/dialog-define-names.c |   12 +++-
 src/expr-name.c                   |  116 ++++++++++++++++++++++++++++++++++---
 src/expr-name.h                   |    1 +
 6 files changed, 130 insertions(+), 13 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 258951a..2e96f15 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-06-06 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* src/expr-name.h (expr_name_in_use): new
+	* src/expr-name.c (expr_name_in_use): new
+	(do_expr_name_loop_check): add argument and change all callers
+	(cb_expr_name_check_for_name): new
+	(cb_expr_name_check_for_name_eq): new
+	(expr_name_check_for_name): new
+	
 2010-06-04 Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* src/commands.c (cmd_define_name): be clearer with the error 
diff --git a/NEWS b/NEWS
index bfa9414..4b39d19 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Andreas:
 	* Add paste-names dialog. [#613325]
 	* Make changing the scope of a named expression undoable.
 	* Add search tool to paste- and define-names dialogs. [#465840]
+	* Check whether defined names are in use before deleting them.
 
 Jean:
 	* Do not ungrab a not grabbed item. [#620369]
diff --git a/src/dialogs/ChangeLog b/src/dialogs/ChangeLog
index 3abd4b2..9f456fd 100644
--- a/src/dialogs/ChangeLog
+++ b/src/dialogs/ChangeLog
@@ -1,3 +1,7 @@
+2010-06-06 Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* dialog-define-names.c (name_guru_warn): implement
+
 2010-06-04 Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* dialog-define-names.c (name_guru_parse_pos_init): new
diff --git a/src/dialogs/dialog-define-names.c b/src/dialogs/dialog-define-names.c
index 27ed6dd..d03a29e 100644
--- a/src/dialogs/dialog-define-names.c
+++ b/src/dialogs/dialog-define-names.c
@@ -176,11 +176,15 @@ name_guru_expand_at_iter (NameGuruState *state, GtkTreeIter *iter)
  **/
 
 static gboolean
-name_guru_warn (G_GNUC_UNUSED NameGuruState *state,
-		G_GNUC_UNUSED GnmNamedExpr *nexpr)
+name_guru_warn (NameGuruState *state,
+		GnmNamedExpr *nexpr)
 {
-#warning Implement warning on deletion of used names!
-	return TRUE;
+	return (!expr_name_in_use (nexpr) || 
+		 go_gtk_query_yes_no 
+		(GTK_WINDOW (state->dialog), FALSE,
+		 "The defined name '%s' is in use. "
+		 "Do you really want to delete it?",
+		 expr_name_name (nexpr)));
 }
 
 static gboolean
diff --git a/src/expr-name.c b/src/expr-name.c
index 4a2639f..fa98d3e 100644
--- a/src/expr-name.c
+++ b/src/expr-name.c
@@ -412,29 +412,33 @@ expr_name_new (char const *name, gboolean is_placeholder)
  * NB. if we already have a circular reference in addition
  * to this one we are checking we will come to serious grief.
  */
+
+/* Note: for a loopcheck stop_at_name must be FALSE. */
+/*       stop_at_name = TRUE is used when we check all names anyways. */
 static gboolean
-do_expr_name_loop_check (char const *name, GnmExpr const *expr)
+do_expr_name_loop_check (char const *name, GnmExpr const *expr,
+			 gboolean stop_at_name)
 {
 	switch (GNM_EXPR_GET_OPER (expr)) {
 	case GNM_EXPR_OP_RANGE_CTOR:
 	case GNM_EXPR_OP_INTERSECT:
 	case GNM_EXPR_OP_ANY_BINARY:
-		return (do_expr_name_loop_check (name, expr->binary.value_a) ||
-			do_expr_name_loop_check (name, expr->binary.value_b));
+		return (do_expr_name_loop_check (name, expr->binary.value_a, stop_at_name) ||
+			do_expr_name_loop_check (name, expr->binary.value_b, stop_at_name));
 	case GNM_EXPR_OP_ANY_UNARY:
-		return do_expr_name_loop_check (name, expr->unary.value);
+		return do_expr_name_loop_check (name, expr->unary.value, stop_at_name);
 	case GNM_EXPR_OP_NAME: {
 		GnmNamedExpr const *nexpr = expr->name.name;
 		if (!strcmp (nexpr->name->str, name))
 			return TRUE;
-		if (nexpr->texpr != NULL) /* look inside this name tree too */
+		if (!stop_at_name && nexpr->texpr != NULL) /* look inside this name tree too */
 			return expr_name_check_for_loop (name, nexpr->texpr);
 		return FALSE;
 	}
 	case GNM_EXPR_OP_FUNCALL: {
 		int i;
 		for (i = 0; i < expr->func.argc; i++)
-			if (do_expr_name_loop_check (name, expr->func.argv[i]))
+			if (do_expr_name_loop_check (name, expr->func.argv[i], stop_at_name))
 				return TRUE;
 		break;
 	}
@@ -446,7 +450,7 @@ do_expr_name_loop_check (char const *name, GnmExpr const *expr)
 	case GNM_EXPR_OP_SET: {
 		int i;
 		for (i = 0; i < expr->set.argc; i++)
-			if (do_expr_name_loop_check (name, expr->set.argv[i]))
+			if (do_expr_name_loop_check (name, expr->set.argv[i], stop_at_name))
 				return TRUE;
 		break;
 	}
@@ -459,7 +463,7 @@ expr_name_check_for_loop (char const *name, GnmExprTop const *texpr)
 {
 	g_return_val_if_fail (texpr != NULL, TRUE);
 
-	return do_expr_name_loop_check (name, texpr->expr);
+	return do_expr_name_loop_check (name, texpr->expr, FALSE);
 }
 
 static void
@@ -527,7 +531,8 @@ expr_name_add (GnmParsePos const *pp, char const *name,
 			nexpr->is_placeholder = FALSE;
 		} else {
 			nexpr = g_hash_table_lookup (scope->names, name);
-			/* If this is a permanent name, we may be adding it on opening of a file, although */
+			/* If this is a permanent name, we may be adding it */
+			/* on opening of a file, although */
 			/* the name is already in place. */
 			if (nexpr != NULL) {
 				if (nexpr->is_permanent)
@@ -833,6 +838,99 @@ expr_name_is_placeholder (GnmNamedExpr const *nexpr)
 		gnm_expr_top_is_err (nexpr->texpr, GNM_ERROR_NAME));
 }
 
+static gboolean
+cb_expr_name_check_for_name (gpointer key,
+			     gpointer value,
+			     gpointer name)
+{
+	GnmNamedExpr *nexpr = value;
+	char const *this_name = key;
+
+	if (strcmp (this_name, name) == 0)
+		return FALSE;
+
+	return do_expr_name_loop_check (name, nexpr->texpr->expr, TRUE);
+}
+
+static gboolean
+cb_expr_name_check_for_name_eq (gpointer key,
+				G_GNUC_UNUSED gpointer value,
+				gpointer name)
+{
+	char const *this_name = key;
+
+	return (strcmp (this_name, name) == 0);
+}
+
+static gboolean
+expr_name_check_for_name (gchar const *name, GnmNamedExprCollection *scope,
+			  gboolean name_check)
+{
+	if (name_check) {
+		/* Since the name is used at workbook level we must  */
+		/* first check whether a sheet-level name hides the  */
+		/* workbook-level name.                              */
+		if (NULL != g_hash_table_find (scope->names,
+					       cb_expr_name_check_for_name_eq,
+					       (gpointer) name))
+			return FALSE;
+	}
+	return NULL != g_hash_table_find (scope->names,
+					  cb_expr_name_check_for_name,
+					  (gpointer) name);
+}
+
+gboolean
+expr_name_in_use (GnmNamedExpr *nexpr)
+{
+	gchar const *name;
+
+	if (nexpr->dependents != NULL && 
+	    g_hash_table_size (nexpr->dependents) != 0)
+		return TRUE;
+
+	/* We must now check whether one of the other names */
+	/* uses this name. */
+	name = expr_name_name (nexpr);
+
+	if (nexpr->pos.sheet == NULL) {
+		/* The name is of global scope           */
+		/* It could be used by any other name    */
+		/* (unless hidden by a sheet-level name) */
+		gboolean res;
+		GSList  *sheets, *sheets_orig;
+
+		res = expr_name_check_for_name 
+			(name, nexpr->pos.wb->names, FALSE);
+		if (res)
+			return TRUE;
+
+		sheets_orig = workbook_sheets (nexpr->pos.wb);
+		for (sheets = sheets_orig;
+		     sheets != NULL; sheets = sheets->next) {
+			Sheet *this = sheets->data;
+			res = expr_name_check_for_name 
+				(name, this->names, TRUE);
+			if (res) {
+				g_slist_free (sheets_orig);
+				return TRUE;
+			}
+		}
+		g_slist_free (sheets_orig);
+	} else {
+		/* The name is of sheet level scope           */
+		/* It can only be used by another sheet-level */
+		/* name of the same sheet.                    */
+		
+		return expr_name_check_for_name 
+			(name, nexpr->pos.sheet->names, FALSE);
+	}
+	
+
+	return FALSE;
+}
+
+
 int
 expr_name_cmp_by_name (GnmNamedExpr const *a, GnmNamedExpr const *b)
 {
diff --git a/src/expr-name.h b/src/expr-name.h
index 027ea4d..438ca60 100644
--- a/src/expr-name.h
+++ b/src/expr-name.h
@@ -50,6 +50,7 @@ void	 expr_name_add_dep    (GnmNamedExpr *ne, GnmDependent *dep);
 void	 expr_name_remove_dep (GnmNamedExpr *ne, GnmDependent *dep);
 gboolean expr_name_is_placeholder (GnmNamedExpr const *ne);
 void	 expr_name_downgrade_to_placeholder (GnmNamedExpr *nexpr);
+gboolean expr_name_in_use     (GnmNamedExpr *nexpr);
 
 int      expr_name_cmp_by_name    (GnmNamedExpr const *a, GnmNamedExpr const *b);
 gboolean expr_name_check_for_loop (char const *name, GnmExprTop const *texpr);



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