[gnumeric] solver: make undo/redo mostly sane.
- From: Morten Welinder <mortenw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnumeric] solver: make undo/redo mostly sane.
- Date: Wed, 4 Nov 2009 20:37:43 +0000 (UTC)
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]