[gnumeric] solver: make undo/redo mostly sane.



commit f32e5efab73604229cc7bb06764799f080d74bb6
Author: Morten Welinder <terra gnome org>
Date:   Wed Nov 4 15:37:23 2009 -0500

    solver: make undo/redo mostly sane.

 src/commands.c              |   96 +++-------------------
 src/commands.h              |    3 +-
 src/dialogs/dialog-solver.c |  184 ++-----------------------------------------
 src/dialogs/solver.glade    |   13 ---
 src/tools/solver/solver.c   |   50 +++++++-----
 5 files changed, 51 insertions(+), 295 deletions(-)
---
diff --git a/src/commands.c b/src/commands.c
index 7aa60f4..26a0ab4 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -6288,57 +6288,25 @@ cmd_text_to_columns (WorkbookControl *wbc,
 typedef struct {
 	GnmCommand cmd;
 
-	GSList	  *cells;
-	GSList	  *ov;
-	GSList	  *nv;
+	GOUndo *undo, *redo;
 } CmdSolver;
 
 MAKE_GNM_COMMAND (CmdSolver, cmd_solver, NULL)
 
 static gboolean
-cmd_solver_impl (GSList *cell_stack, GSList *value_stack)
-{
-	while (cell_stack != NULL &&  value_stack != NULL) {
-		GSList *values = value_stack->data;
-		GSList *cells  = cell_stack->data;
-
-		while (values != NULL) {
-			char const *str = values->data;
-			GnmCell *cell = cells->data;
-
-			if (cell != NULL) {
-				sheet_cell_set_text (cell, str, NULL);
-				cells = cells->next;
-			}
-			values = values->next;
-		}
-		value_stack = value_stack->next;
-		cell_stack = cell_stack->next;
-	}
-	return FALSE;
-}
-
-
-static gboolean
 cmd_solver_undo (GnmCommand *cmd, WorkbookControl *wbc)
 {
 	CmdSolver *me = CMD_SOLVER (cmd);
-
-	return cmd_solver_impl (me->cells, me->ov);;
+	go_undo_undo_with_data (me->undo, GO_CMD_CONTEXT (wbc));
+	return FALSE;
 }
 
 static gboolean
 cmd_solver_redo (GnmCommand *cmd, WorkbookControl *wbc)
 {
 	CmdSolver *me = CMD_SOLVER (cmd);
-
-	return cmd_solver_impl (me->cells, me->nv);;
-}
-
-static void
-cmd_solver_free_values (GSList *v, G_GNUC_UNUSED gpointer user_data)
-{
-	go_slist_free_custom (v, g_free);
+	go_undo_undo_with_data (me->redo, GO_CMD_CONTEXT (wbc));
+	return FALSE;
 }
 
 static void
@@ -6346,66 +6314,28 @@ cmd_solver_finalize (GObject *cmd)
 {
 	CmdSolver *me = CMD_SOLVER (cmd);
 
-	g_slist_free (me->cells);
-	me->cells = NULL;
-	go_slist_free_custom (me->ov, (GFreeFunc)cmd_solver_free_values);
-	me->ov = NULL;
-	go_slist_free_custom (me->nv, (GFreeFunc)cmd_solver_free_values);
-	me->nv = NULL;
+	g_object_unref (me->undo);
+	g_object_unref (me->redo);
 
 	gnm_command_finalize (cmd);
 }
 
-static GSList *
-cmd_solver_get_cell_values (GSList *cell_stack)
-{
-	GSList *value_stack = NULL;
-
-	while (cell_stack != NULL) {
-		GSList *cells  = cell_stack->data;
-		GSList *values = NULL;
-		while (cells != NULL) {
-			GnmCell *the_Cell = (GnmCell *)(cells->data);
-			if (the_Cell != NULL)
-				values = g_slist_append
-					(values,
-					 value_get_as_string
-					 (the_Cell->value));
-			else
-				values = g_slist_append
-					(values, NULL);
-			cells = cells->next;
-		}
-		value_stack = g_slist_append (value_stack,
-					       values);
-		cell_stack = cell_stack->next;
-	}
-
-	return value_stack;
-}
-
 gboolean
-cmd_solver (WorkbookControl *wbc, GSList *cells, GSList *ov, GSList *nv)
+cmd_solver (WorkbookControl *wbc, GOUndo *undo, GOUndo *redo)
 {
 	CmdSolver *me;
 
-	g_return_val_if_fail (cells != NULL, TRUE);
-	g_return_val_if_fail (ov != NULL || nv != NULL, TRUE);
+	g_return_val_if_fail (GO_IS_UNDO (undo), TRUE);
+	g_return_val_if_fail (GO_IS_UNDO (redo), TRUE);
 
 	me = g_object_new (CMD_SOLVER_TYPE, NULL);
 
 	me->cmd.sheet = NULL;
-	me->cmd.size = g_slist_length (cells);
+	me->cmd.size = 1;
 	me->cmd.cmd_descriptor = g_strdup_printf (_("Solver"));
 
-	me->cells = cells;
-	me->ov = ov;
-	me->nv = nv;
-
-	if (me->ov == NULL)
-		me->ov = cmd_solver_get_cell_values (cells);
-	if (me->nv == NULL)
-		me->nv = cmd_solver_get_cell_values (cells);
+	me->undo = undo;
+	me->redo = redo;
 
 	return gnm_command_push_undo (wbc, G_OBJECT (me));
 }
diff --git a/src/commands.h b/src/commands.h
index c6d2ea9..8649365 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -128,8 +128,7 @@ gboolean cmd_text_to_columns (WorkbookControl *wbc,
 			      GnmRange const *target, Sheet *target_sheet,
 			      GnmCellRegion *content);
 
-gboolean cmd_solver (WorkbookControl *wbc,
-		     GSList *cells, GSList *ov, GSList *nv);
+gboolean cmd_solver (WorkbookControl *wbc, GOUndo *undo, GOUndo *redo);
 
 gboolean cmd_goal_seek (WorkbookControl *wbc,
 			GnmCell *cell, GnmValue *ov, GnmValue *nv);
diff --git a/src/dialogs/dialog-solver.c b/src/dialogs/dialog-solver.c
index 37bb658..b74ff40 100644
--- a/src/dialogs/dialog-solver.c
+++ b/src/dialogs/dialog-solver.c
@@ -60,7 +60,6 @@ typedef struct {
 	GtkWidget           *max_iter_entry;
 	GtkWidget           *max_time_entry;
 	GtkWidget           *solve_button;
-	GtkWidget           *cancel_button;
 	GtkWidget           *close_button;
 	GtkWidget           *add_button;
 	GtkWidget           *change_button;
@@ -75,9 +74,6 @@ typedef struct {
 	GtkComboBox         *algorithm_combo;
 	GtkTreeView         *constraint_list;
 	SolverConstraint    *constr;
-	gnm_float            ov_target;
-	GSList              *ov_stack;
-	GSList              *ov_cell_stack;
 	GtkWidget           *warning_dialog;
 
 	gboolean             cancelled;
@@ -336,34 +332,10 @@ cb_dialog_model_type_clicked (G_GNUC_UNUSED GtkWidget *button,
 }
 
 static void
-free_original_values (GSList *ov)
-{
-	go_slist_free_custom (ov, g_free);
-}
-
-static void
 cb_dialog_solver_destroy (SolverState *state)
 {
 	g_return_if_fail (state != NULL);
 
-	if (state->ov_cell_stack != NULL &&
-	    !state->cancelled &&
-	    !cmd_solver (WORKBOOK_CONTROL(state->wbcg), state->ov_cell_stack,
-			 state->ov_stack, NULL))
-	{
-		state->ov_cell_stack = NULL;
-		state->ov_stack = NULL;
-	}
-
-	if (state->ov_stack != NULL) {
-		go_slist_free_custom (state->ov_stack,
-				      (GFreeFunc)free_original_values);
-		state->ov_stack = NULL;
-		go_slist_free_custom (state->ov_cell_stack,
-				      (GFreeFunc)g_slist_free);
-		state->ov_cell_stack = NULL;
-	}
-
 	if (state->gui != NULL) {
 		g_object_unref (G_OBJECT (state->gui));
 		state->gui = NULL;
@@ -376,43 +348,6 @@ cb_dialog_solver_destroy (SolverState *state)
 }
 
 static void
-restore_original_values (GSList *input_cells, GSList *ov)
-{
-        while (ov != NULL) {
-		char const *str = ov->data;
-		GnmCell *cell = input_cells->data;
-
-		sheet_cell_set_text (cell, str, NULL);
-		ov = ov->next;
-		input_cells = input_cells->next;
-	}
-}
-
-static void
-cb_dialog_cancel_clicked (G_GNUC_UNUSED GtkWidget *button, SolverState *state)
-{
-	if (state->ov_stack != NULL) {
-		GSList *cells = state->ov_cell_stack;
-		GSList *ov = state->ov_stack;
-		while (cells != NULL && ov != NULL) {
-			restore_original_values (cells->data,
-						 ov->data);
-			cells = cells->next;
-			ov = ov ->next;
-		}
-		go_slist_free_custom (state->ov_stack,
-				      (GFreeFunc)free_original_values);
-		state->ov_stack = NULL;
-		g_slist_free (state->ov_cell_stack);
-		state->ov_cell_stack = NULL;
-		workbook_recalc (state->sheet->workbook);
-	}
-	state->cancelled = TRUE;
-
-	gtk_widget_destroy (state->dialog);
-}
-
-static void
 cb_dialog_close_clicked (G_GNUC_UNUSED GtkWidget *button,
 			 SolverState *state)
 {
@@ -420,68 +355,6 @@ cb_dialog_close_clicked (G_GNUC_UNUSED GtkWidget *button,
 	gtk_widget_destroy (state->dialog);
 }
 
-static gchar const *
-check_int_constraints (GnmValue *input_range, SolverState *state)
-{
-	GtkTreeModel *store;
-	GtkTreeIter iter;
-
-	store = gtk_tree_view_get_model (state->constraint_list);
-	if (gtk_tree_model_get_iter_first (store, &iter))
-		do {
-			SolverConstraint const *a_constraint;
-			gchar *text;
-
-			gtk_tree_model_get (store, &iter, 0, &text, 1, &a_constraint, -1);
-			if (a_constraint == NULL) {
-				g_free (text);
-				break;
-			}
-
-			if ((a_constraint->type != SolverINT) &&
-			    (a_constraint->type != SolverBOOL)) {
-				g_free (text);
-				continue;
-			}
-
-#if 0
-			if (!global_range_contained (state->sheet,
-						     a_constraint->lhs,
-						     input_range))
-				return text;
-#endif
-
-			g_free (text);
-		} while (gtk_tree_model_iter_next (store, &iter));
-	return NULL;
-}
-
-/**
- * save_original_values:
- * @input_cells:
- *
- *
- *
- **/
-static GSList *
-save_original_values (GSList *input_cells)
-{
-        GSList *ov = NULL;
-
-	while (input_cells != NULL) {
-		GnmCell *cell = input_cells->data;
-		char *str;
-
-		str = value_get_as_string (cell->value);
-		ov = g_slist_append (ov, str);
-
-		input_cells = input_cells->next;
-	}
-
-	return ov;
-}
-
-
 /* Returns FALSE if the reports deleted the current sheet
  * and forced the dialog to die */
 static gboolean
@@ -625,7 +498,6 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 	SolverResults           *res;
 	GnmValue                   *target_range;
 	GnmValue                   *input_range;
-        GSList			*input_cells;
 	gint                    i;
 	gboolean                answer, sensitivity, limits, performance;
 	gboolean                program, dual_program;
@@ -645,33 +517,14 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 	input_range = gnm_expr_entry_parse_as_value (state->change_cell_entry,
 						     state->sheet);
 
-	if (target_range == NULL || input_range == NULL) {
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			  &(state->warning_dialog),
-			  GTK_MESSAGE_ERROR, _("You have not specified "
-					       "a problem to be solved"));
-		return;
-	}
-
 	gnm_solver_param_set_input (param, value_dup (input_range));
 
 	gnm_solver_param_set_target (param,
-				     &target_range->v_range.cell.a);
+				     target_range
+				     ? &target_range->v_range.cell.a
+				     : NULL);
 	target_cell = gnm_solver_param_get_target_cell (param);
 
-	/* Check that the target cell type is number. */
-	if (!target_cell || !gnm_cell_is_number (target_cell)) {
-		go_gtk_notice_nonmodal_dialog
-			((GtkWindow *) state->dialog,
-			 &(state->warning_dialog),
-			 GTK_MESSAGE_ERROR, _("Target cell should contain "
-					      "a formula."));
-		return;
-	}
-
-	input_cells = gnm_solver_param_get_input_cells (param);
-
 	param->problem_type =
 		gnumeric_glade_group_value (state->gui, problem_type_group);
 	param->options.model_type =
@@ -734,27 +587,13 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 	dual_program = FALSE;
 	param->options.dual_program_report = dual_program;
 
-	name = check_int_constraints (input_range, state);
-	if (name != NULL) {
-		char *str;
-
-		str = g_strdup_printf
-			(_("Constraint `%s' is for a cell that "
-			   "is not an input cell."), name);
-		go_gtk_notice_nonmodal_dialog ((GtkWindow *) state->dialog,
-					  &(state->warning_dialog),
-					  GTK_MESSAGE_ERROR, str);
-		g_free (str);
+	if (!gnm_solver_param_valid (param, &err)) {
+		GtkWidget *top = gtk_widget_get_toplevel (state->dialog);
+		go_gtk_notice_dialog (GTK_WINDOW (top), GTK_MESSAGE_ERROR,
+				      "%s", err->message);
 		goto out;
 	}
 
-	state->ov_target     = value_get_as_float (target_cell->value);
-	state->ov_stack      = g_slist_prepend (state->ov_stack,
-						save_original_values (input_cells));
-	state->ov_cell_stack = g_slist_prepend (state->ov_cell_stack,
-						input_cells);
-
-
 	res = solver (WORKBOOK_CONTROL (state->wbcg), state->sheet, &err);
 	workbook_recalc (state->sheet->workbook);
 
@@ -777,7 +616,7 @@ cb_dialog_solve_clicked (G_GNUC_UNUSED GtkWidget *button,
 			 GTK_MESSAGE_ERROR,
 			 err ? err->message : _("Unknown error."));
 
-out:
+ out:
 	value_release (target_range);
 	value_release (input_range);
 	if (err)
@@ -845,11 +684,6 @@ dialog_init (SolverState *state)
 	g_signal_connect (G_OBJECT (state->close_button), "clicked",
 			  G_CALLBACK (cb_dialog_close_clicked), state);
 
-	state->cancel_button  = glade_xml_get_widget (state->gui,
-						      "cancelbutton");
-	g_signal_connect (G_OBJECT (state->cancel_button), "clicked",
-			  G_CALLBACK (cb_dialog_cancel_clicked), state);
-
 	gnumeric_init_help_button (glade_xml_get_widget (state->gui,
 							 "helpbutton"),
 				   GNUMERIC_HELP_LINK_SOLVER);
@@ -1145,8 +979,6 @@ dialog_solver (WBCGtk *wbcg, Sheet *sheet)
 	state                 = g_new (SolverState, 1);
 	state->wbcg           = wbcg;
 	state->sheet          = sheet;
-	state->ov_stack       = NULL;
-	state->ov_cell_stack  = NULL;
 	state->warning_dialog = NULL;
 	state->cancelled      = TRUE;
 
diff --git a/src/dialogs/solver.glade b/src/dialogs/solver.glade
index 0d738dd..9d9de5f 100644
--- a/src/dialogs/solver.glade
+++ b/src/dialogs/solver.glade
@@ -734,19 +734,6 @@ Bool
               </widget>
             </child>
             <child>
-              <widget class="GtkButton" id="cancelbutton">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="can_default">True</property>
-                <property name="label">gtk-cancel</property>
-                <property name="use_stock">True</property>
-                <property name="response_id">0</property>
-              </widget>
-              <packing>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
               <widget class="GtkButton" id="closebutton">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
diff --git a/src/tools/solver/solver.c b/src/tools/solver/solver.c
index 7eda6b0..a5d7992 100644
--- a/src/tools/solver/solver.c
+++ b/src/tools/solver/solver.c
@@ -39,6 +39,8 @@
 #include "value.h"
 #include "ranges.h"
 #include "expr.h"
+#include "clipboard.h"
+#include "commands.h"
 #include "mathfunc.h"
 #include "analysis-tools.h"
 #include "api.h"
@@ -514,6 +516,8 @@ gnm_solver_constraint_valid (SolverConstraint const *c)
 			return FALSE;
 	}
 
+#warning "We need to check that int/bool constraints refer to input cells."
+
 	return TRUE;
 }
 
@@ -796,23 +800,6 @@ save_original_values (SolverResults          *res,
 	res->original_value_of_obj_fn = value_get_as_float (cell->value);
 }
 
-static void
-restore_original_values (SolverResults *res)
-{
-	GSList *input_cells = gnm_solver_param_get_input_cells (res->param);
-	GSList *l;
-	int i;
-
-	for (i = 0, l = input_cells; l; i++, l = l->next) {
-	        GnmCell *cell = l->data;
-		sheet_cell_set_value
-			(cell,
-			 value_new_float (res->original_values[i]));
-	}
-
-	g_slist_free (input_cells);
-}
-
 /************************************************************************
  */
 
@@ -1137,6 +1124,9 @@ solver_run (WorkbookControl *wbc, Sheet *sheet,
 	SolverParameters  *param = sheet->solver_parameters;
 	SolverProgram     program;
 	SolverResults     *res;
+	GnmValue const *  vinput = gnm_solver_param_get_input (param);
+	GnmSheetRange sr;
+	GOUndo *undo;
 	GTimeVal          start, end;
 #if defined(HAVE_TIMES) && defined(HAVE_SYSCONF)
 	struct tms        buf;
@@ -1163,13 +1153,18 @@ solver_run (WorkbookControl *wbc, Sheet *sheet,
 #endif
 	res->time_real   = - (start.tv_sec +
 			      start.tv_usec / (gnm_float) G_USEC_PER_SEC);
+
+	gnm_sheet_range_from_value (&sr, vinput);
+	if (!sr.sheet) sr.sheet = sheet;
+	undo = clipboard_copy_range_undo (sr.sheet, &sr.range);
+
 	save_original_values (res, param, sheet);
 
 	program              = lp_qp_solver_init (sheet, param, res, alg,
 						  -res->time_real, start,
 						  err);
 	if (program == NULL)
-	        return NULL;
+		goto fail;
 
         res->status = alg->solve_fn (program);
 	g_get_current_time (&end);
@@ -1188,16 +1183,29 @@ solver_run (WorkbookControl *wbc, Sheet *sheet,
 
 	solver_prepare_reports (program, res, sheet);
 	if (res->status == SolverOptimal) {
+		GOUndo *redo;
 	        if (solver_prepare_reports_success (program, res, sheet)) {
 		        alg->remove_fn (program);
-			return NULL;
+			goto fail;
 		}
-	} else
-	        restore_original_values (res);
+		redo = clipboard_copy_range_undo (sr.sheet, &sr.range);
+		cmd_solver (wbc, undo, redo);
+	} else {
+		go_undo_undo (undo);
+		g_object_unref (undo);
+		undo = NULL;
+	}
 
 	alg->remove_fn (program);
 
 	return res;
+
+ fail:
+	if (res)
+		solver_results_free (res);
+	if (undo)
+		g_object_unref (undo);
+	return NULL;
 }
 
 SolverResults *



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