1 /*
2 * dialog-scenarios.c: Create, edit, and view scenarios.
3 *
4 * Author:
5 * Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
6 *
7 * (C) Copyright 2003 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22 #include <gnumeric-config.h>
23 #include <glib/gi18n-lib.h>
24 #include <gnumeric.h>
25 #include <dialogs/dialogs.h>
26 #include <dialogs/help.h>
27
28 #include <gui-util.h>
29 #include <commands.h>
30 #include <workbook-control.h>
31 #include <workbook.h>
32 #include <wbc-gtk.h>
33 #include <sheet.h>
34 #include <dialogs/dao-gui-utils.h>
35 #include <position.h>
36 #include <ranges.h>
37 #include <value.h>
38 #include <cell.h>
39 #include <tools/dao.h>
40 #include <tools/scenarios.h>
41 #include <dialogs/tool-dialogs.h>
42
43 #include <goffice/goffice.h>
44 #include <string.h>
45
46 #define DARK_GRAY GO_COLOR_GREY(51) /* "gray20" */
47 #define LIGHT_GRAY GO_COLOR_GREY(199) /* "gray78" */
48
49 typedef struct {
50 GnmGenericToolState base;
51
52 GtkWidget *show_button;
53 GtkWidget *delete_button;
54 GtkWidget *summary_button;
55 GtkWidget *name_entry;
56
57 GtkWidget *scenarios_treeview;
58 GSList *new_report_sheets;
59
60 GOUndo *undo;
61 GnmScenario *current;
62 } ScenariosState;
63
64 typedef GnmValue * (*ScenarioValueCB) (int col, int row, GnmValue *v, gpointer data);
65
66 static void
scenario_for_each_value(GnmScenario * s,ScenarioValueCB fn,gpointer data)67 scenario_for_each_value (GnmScenario *s, ScenarioValueCB fn, gpointer data)
68 {
69 }
70
71 /* Ok button pressed. */
72 static void
scenario_manager_ok(Sheet * sheet)73 scenario_manager_ok (Sheet *sheet)
74 {
75 GList *l, *scenarios = g_list_copy (sheet->scenarios);
76
77 /* Update scenarios (free the deleted ones). */
78 for (l = scenarios; l; l = l->next) {
79 GnmScenario *sc = l->data;
80 if (g_object_get_data (G_OBJECT (sc), "marked_deleted")) {
81 gnm_sheet_scenario_remove (sc->sheet, sc);
82 }
83 }
84 g_list_free (scenarios);
85
86 sheet_redraw_all (sheet, TRUE);
87 }
88
89 /* Cancel button pressed. */
90 static void
scenario_recover_all(Sheet * sheet)91 scenario_recover_all (Sheet *sheet)
92 {
93 GList *l;
94
95 for (l = sheet->scenarios; l; l = l->next) {
96 GnmScenario *sc = l->data;
97 g_object_set_data (G_OBJECT (sc),
98 "marked_deleted", GUINT_TO_POINTER (FALSE));
99 }
100 }
101
102 /* Scenario: Create summary report ***************************************/
103
104 static void
rm_fun_cb(gpointer key,gpointer value,gpointer user_data)105 rm_fun_cb (gpointer key, gpointer value, gpointer user_data)
106 {
107 g_free (value);
108 }
109
110 typedef struct {
111 data_analysis_output_t dao;
112
113 Sheet *sheet;
114 GHashTable *names; /* A hash table for cell names->row. */
115 int col;
116 int row;
117 GSList *results;
118 } summary_cb_t;
119
120 static GnmValue *
summary_cb(int col,int row,GnmValue * v,summary_cb_t * p)121 summary_cb (int col, int row, GnmValue *v, summary_cb_t *p)
122 {
123 char *tmp = dao_find_name (p->sheet, col, row);
124 int *index;
125
126 /* Check if some of the previous scenarios already included that
127 * cell. If so, it's row will be put into *index. */
128 index = g_hash_table_lookup (p->names, tmp);
129 if (index != NULL) {
130 dao_set_cell_value (&p->dao, 2 + p->col, 3 + *index,
131 value_dup (v));
132
133 /* Set the colors. */
134 dao_set_colors (&p->dao, 2 + p->col, 3 + *index,
135 2 + p->col, 3 + *index,
136 gnm_color_new_go (GO_COLOR_BLACK),
137 gnm_color_new_go (LIGHT_GRAY));
138
139 } else {
140 /* New cell. */
141 GnmCell *cell;
142 int *r;
143
144 /* Changing cell name. */
145 dao_set_cell (&p->dao, 0, 3 + p->row, tmp);
146
147 /* GnmValue of the cell in this scenario. */
148 dao_set_cell_value (&p->dao, 2 + p->col, 3 + p->row,
149 value_dup (v));
150
151 /* Current value of the cell. */
152 cell = sheet_cell_fetch (p->sheet, col, row);
153 dao_set_cell_value (&p->dao, 1, 3 + p->row,
154 value_dup (cell->value));
155
156 /* Set the colors. */
157 dao_set_colors (&p->dao, 2 + p->col, 3 + p->row,
158 2 + p->col, 3 + p->row,
159 gnm_color_new_go (GO_COLOR_BLACK),
160 gnm_color_new_go (LIGHT_GRAY));
161
162 /* Insert row number into the hash table. */
163 r = g_new (int, 1);
164 *r = p->row;
165 g_hash_table_insert (p->names, tmp, r);
166
167 /* Increment the nbr of rows. */
168 p->row++;
169 }
170
171 return v;
172 }
173
174 static void
scenario_summary_res_cells(WorkbookControl * wbc,GSList * results,summary_cb_t * cb)175 scenario_summary_res_cells (WorkbookControl *wbc, GSList *results,
176 summary_cb_t *cb)
177 {
178 }
179
180 static void
scenario_summary(WorkbookControl * wbc,Sheet * sheet,GSList * results,Sheet ** new_sheet)181 scenario_summary (WorkbookControl *wbc,
182 Sheet *sheet,
183 GSList *results,
184 Sheet **new_sheet)
185 {
186 summary_cb_t cb;
187 GList *cur;
188 GList *scenarios = sheet->scenarios;
189
190 /* Initialize: Currently only new sheet output supported. */
191 dao_init_new_sheet (&cb.dao);
192 dao_prepare_output (wbc, &cb.dao, _("Scenario Summary"));
193
194 /* Titles. */
195 dao_set_cell (&cb.dao, 1, 1, _("Current Values"));
196 dao_set_cell (&cb.dao, 0, 2, _("Changing Cells:"));
197
198 /* Go through all scenarios. */
199 cb.row = 0;
200 cb.names = g_hash_table_new (g_str_hash, g_str_equal);
201 cb.sheet = sheet;
202 cb.results = results;
203 for (cb.col = 0, cur = scenarios; cur != NULL; cb.col++,
204 cur = cur->next) {
205 GnmScenario *s = cur->data;
206
207 /* Scenario name. */
208 dao_set_cell (&cb.dao, 2 + cb.col, 1, s->name);
209
210 scenario_for_each_value (s, (ScenarioValueCB) summary_cb, &cb);
211 }
212
213 /* Set the alignment of names of the changing cells to be right. */
214 dao_set_align (&cb.dao, 0, 3, 0, 2 + cb.row, GNM_HALIGN_RIGHT,
215 GNM_VALIGN_BOTTOM);
216
217 /* Result cells. */
218 if (results != NULL)
219 scenario_summary_res_cells (wbc, results, &cb);
220
221 /* Destroy the hash table. */
222 g_hash_table_foreach (cb.names, (GHFunc) rm_fun_cb, NULL);
223 g_hash_table_destroy (cb.names);
224
225 /* Clean up the report output. */
226 dao_set_bold (&cb.dao, 0, 0, 0, 2 + cb.row);
227 dao_autofit_columns (&cb.dao);
228 dao_set_cell (&cb.dao, 0, 0, _("Scenario Summary"));
229
230 dao_set_colors (&cb.dao, 0, 0, cb.col + 1, 1,
231 gnm_color_new_go (GO_COLOR_WHITE),
232 gnm_color_new_go (DARK_GRAY));
233 dao_set_colors (&cb.dao, 0, 2, 0, 2 + cb.row,
234 gnm_color_new_go (GO_COLOR_BLACK),
235 gnm_color_new_go (LIGHT_GRAY));
236
237 dao_set_align (&cb.dao, 1, 1, cb.col + 1, 1, GNM_HALIGN_RIGHT,
238 GNM_VALIGN_BOTTOM);
239
240 *new_sheet = cb.dao.sheet;
241 }
242
243 /********* Scenario Add UI **********************************************/
244
245 static gboolean
scenario_name_used(const GList * scenarios,const gchar * name)246 scenario_name_used (const GList *scenarios, const gchar *name)
247 {
248 while (scenarios != NULL) {
249 const GnmScenario *s = scenarios->data;
250
251 if (strcmp (s->name, name) == 0)
252 return TRUE;
253 scenarios = scenarios->next;
254 }
255 return FALSE;
256 }
257
258 /*
259 * A scenario name should have at least one printable character.
260 */
261 static gboolean
check_name(const gchar * n)262 check_name (const gchar *n)
263 {
264 while (*n && g_unichar_isspace (g_utf8_get_char (n)))
265 n = g_utf8_next_char (n);
266
267 if (*n)
268 return FALSE;
269 else
270 return TRUE;
271 }
272
273 /**
274 * scenario_add_ok_clicked_cb:
275 * @button:
276 * @state:
277 *
278 * Run the scenario manager tool.
279 **/
280 static void
scenario_add_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)281 scenario_add_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
282 ScenariosState *state)
283 {
284 data_analysis_output_t dao;
285 WorkbookControl *wbc;
286 gchar *name;
287 gchar *comment;
288 GnmValue *cell_range;
289 GtkWidget *entry, *comment_view;
290 GtkTextBuffer *buf;
291 GtkTextIter start, end;
292 GnmScenario *sc;
293 GnmSheetRange sr;
294
295 cell_range = gnm_expr_entry_parse_as_value
296 (GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
297
298 if (!cell_range || !gnm_sheet_range_from_value (&sr, cell_range)) {
299 go_gtk_notice_dialog (GTK_WINDOW (state->base.dialog),
300 GTK_MESSAGE_ERROR,
301 _("Invalid changing cells"));
302 gnm_expr_entry_grab_focus (state->base.input_entry, TRUE);
303 return;
304 }
305
306 if (sr.sheet && sr.sheet != state->base.sheet) {
307 go_gtk_notice_dialog (GTK_WINDOW (state->base.dialog),
308 GTK_MESSAGE_ERROR,
309 _("Changing cells should be on the current "
310 "sheet only."));
311 gnm_expr_entry_grab_focus (state->base.input_entry, TRUE);
312 goto out;
313 }
314 entry = go_gtk_builder_get_widget (state->base.gui, "name_entry");
315
316 name = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
317 if (scenario_name_used (state->base.sheet->scenarios, name)) {
318 g_free (name);
319 go_gtk_notice_dialog (GTK_WINDOW (state->base.dialog),
320 GTK_MESSAGE_ERROR,
321 _("Scenario name already used"));
322 goto out;
323 } else if (check_name (name)) {
324 g_free (name);
325 go_gtk_notice_dialog (GTK_WINDOW (state->base.dialog),
326 GTK_MESSAGE_ERROR,
327 _("Invalid scenario name"));
328 goto out;
329 }
330
331 comment_view = go_gtk_builder_get_widget (state->base.gui, "comment_view");
332 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (comment_view));
333 gtk_text_buffer_get_start_iter (buf, &start);
334 gtk_text_buffer_get_end_iter (buf, &end);
335 comment = g_strdup (gtk_text_buffer_get_text (buf, &start, &end,
336 FALSE));
337
338 dao_init_new_sheet (&dao);
339 dao.sheet = state->base.sheet;
340
341 wbc = GNM_WBC (state->base.wbcg);
342
343 sc = gnm_sheet_scenario_new (state->base.sheet, name);
344 if (comment && comment[0])
345 gnm_scenario_set_comment (sc, comment);
346 gnm_scenario_add_area (sc, &sr);
347
348 cmd_scenario_add (wbc, sc, state->base.sheet);
349
350 g_free (name);
351 g_free (comment);
352 gtk_widget_destroy (state->base.dialog);
353 out:
354 value_release (cell_range);
355 return;
356 }
357
358 /**
359 * scenario_add_update_sensitivity_cb:
360 * @dummy:
361 * @state:
362 *
363 * Update the dialog widgets sensitivity
364 **/
365 static void
scenario_add_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,ScenariosState * state)366 scenario_add_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
367 ScenariosState *state)
368 {
369 gtk_widget_set_sensitive (state->base.ok_button, TRUE);
370 }
371
372 void
dialog_scenario_add(WBCGtk * wbcg)373 dialog_scenario_add (WBCGtk *wbcg)
374 {
375 ScenariosState *state;
376 WorkbookControl *wbc;
377 GtkWidget *comment_view;
378 char const *error_str = _("Could not create the Scenario Add dialog.");
379 GString *buf;
380
381 if (wbcg == NULL)
382 return;
383
384 wbc = GNM_WBC (wbcg);
385
386 /* Only pop up one copy per workbook */
387 if (gnm_dialog_raise_if_exists (wbcg, "ScenarioAdd"))
388 return;
389
390 state = g_new (ScenariosState, 1);
391
392 if (dialog_tool_init (&state->base, wbcg, wb_control_cur_sheet (wbc),
393 GNUMERIC_HELP_LINK_SCENARIOS_ADD,
394 "res:ui/scenario-add.ui", "ScenarioAdd",
395 error_str,
396 "ScenarioAdd",
397 G_CALLBACK (scenario_add_ok_clicked_cb), NULL,
398 G_CALLBACK (scenario_add_update_sensitivity_cb),
399 GNM_EE_SHEET_OPTIONAL))
400 {
401 g_free (state);
402 return;
403 }
404
405 state->name_entry = go_gtk_builder_get_widget (state->base.gui, "name_entry");
406 if (state->name_entry == NULL)
407 return;
408
409 comment_view = go_gtk_builder_get_widget (state->base.gui, "comment_view");
410 if (comment_view == NULL)
411 return;
412 buf = g_string_new (NULL);
413 g_string_append_printf (buf, _("Created on "));
414 dao_append_date (buf);
415 gtk_text_buffer_set_text (gtk_text_view_get_buffer
416 (GTK_TEXT_VIEW (comment_view)), buf->str,
417 strlen (buf->str));
418 g_string_free (buf, FALSE);
419
420 state->base.gdao = NULL;
421
422 gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->base.dialog),
423 wbcg,
424 GNM_DIALOG_DESTROY_SHEET_REMOVED);
425
426 gnm_editable_enters (GTK_WINDOW (state->base.dialog),
427 GTK_WIDGET (state->name_entry));
428 scenario_add_update_sensitivity_cb (NULL, state);
429 tool_load_selection ((GnmGenericToolState *)state, TRUE);
430 }
431
432
433 /********* Scenario Manager UI ******************************************/
434
435 static void
update_comment(ScenariosState * state,const gchar * cells,const gchar * comment)436 update_comment (ScenariosState *state, const gchar *cells,
437 const gchar *comment)
438 {
439 GtkWidget *w;
440 GtkTextBuffer *buf;
441
442 /* Update changing cells box */
443 w = go_gtk_builder_get_widget (state->base.gui, "changing_cells_entry");
444 gtk_entry_set_text (GTK_ENTRY (w), cells);
445
446 /* Update comment text view */
447 w = go_gtk_builder_get_widget (state->base.gui, "comment_view");
448 buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w));
449
450 gtk_text_buffer_set_text (buf, comment, strlen (comment));
451 }
452
453 static void
set_selection_state(ScenariosState * state,gboolean f)454 set_selection_state (ScenariosState *state, gboolean f)
455 {
456 /* Set the sensitivies to FALSE since no selections have been made */
457 gtk_widget_set_sensitive (state->show_button, f);
458 gtk_widget_set_sensitive (state->delete_button, f);
459
460 if (f) {
461 GtkTreeSelection *selection;
462 GtkTreeIter iter;
463 GtkTreeModel *model;
464 gchar *name;
465 gchar *cells_txt;
466 GnmScenario *sc;
467
468 selection = gtk_tree_view_get_selection
469 (GTK_TREE_VIEW
470 (state->scenarios_treeview));
471 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
472 return;
473 model = gtk_tree_view_get_model
474 (GTK_TREE_VIEW
475 (state->scenarios_treeview));
476
477 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
478 0, &name, -1);
479
480 sc = gnm_sheet_scenario_find (state->base.sheet, name);
481 if (!sc)
482 return;
483 cells_txt = gnm_scenario_get_range_str (sc);
484 update_comment (state, cells_txt, sc->comment);
485 g_free (cells_txt);
486 } else
487 update_comment (state, "", "");
488 }
489
490 static void
update_scenarios_treeview(GtkWidget * view,GList * scenarios)491 update_scenarios_treeview (GtkWidget *view, GList *scenarios)
492 {
493 GtkTreeIter iter;
494 GtkListStore *store;
495 GtkTreePath *path;
496
497 store = gtk_list_store_new (1, G_TYPE_STRING);
498
499 while (scenarios != NULL) {
500 GnmScenario *s = scenarios->data;
501
502 gtk_list_store_append (store, &iter);
503 gtk_list_store_set (store, &iter, 0, s->name, -1);
504 scenarios = scenarios->next;
505 }
506 path = gtk_tree_path_new_from_string ("0");
507 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store),
508 &iter, path)) {
509 ; /* Do something */
510 } else {
511 /* No scenarios */
512 }
513 gtk_tree_path_free (path);
514
515 gtk_tree_view_set_model (GTK_TREE_VIEW (view),
516 GTK_TREE_MODEL (store));
517 g_object_unref (store);
518 gtk_tree_view_append_column
519 (GTK_TREE_VIEW (view),
520 gtk_tree_view_column_new_with_attributes
521 (_("Name"),
522 gtk_cell_renderer_text_new (), "text", 0, NULL));
523 }
524
525 /**
526 * scenarios_update_sensitivity_cb:
527 * @dummy:
528 * @state:
529 *
530 * Update the dialog widgets sensitivity
531 **/
532 static void
scenarios_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,ScenariosState * state)533 scenarios_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
534 ScenariosState *state)
535 {
536 gtk_widget_set_sensitive (state->base.ok_button, TRUE);
537 }
538
539
540 static void
scenario_manager_free(ScenariosState * state)541 scenario_manager_free (ScenariosState *state)
542 {
543 g_slist_free (state->new_report_sheets);
544 state->new_report_sheets = NULL;
545
546 if (state->undo) {
547 g_object_unref (state->undo);
548 state->undo = NULL;
549 }
550 }
551
552 /**
553 * scenarios_ok_clicked_cb:
554 * @button:
555 * @state:
556 *
557 * Run the scenario manager tool.
558 **/
559 static void
scenarios_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)560 scenarios_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
561 ScenariosState *state)
562 {
563 if (state->current) {
564 WorkbookControl *wbc = GNM_WBC (state->base.wbcg);
565 cmd_scenario_mngr (wbc, state->current, state->undo);
566 }
567
568 scenario_manager_ok (state->base.sheet);
569
570 scenario_manager_free (state);
571 gtk_widget_destroy (state->base.dialog);
572
573 return;
574 }
575
576 static void
restore_old_values(ScenariosState * state)577 restore_old_values (ScenariosState *state)
578 {
579 GOCmdContext *cc;
580
581 if (state->undo == NULL)
582 return;
583
584 cc = GO_CMD_CONTEXT (state->base.wbcg);
585 go_undo_undo_with_data (state->undo, cc);
586 g_object_unref (state->undo);
587 state->undo = NULL;
588 state->current = NULL;
589 }
590
591 /**
592 * scenarios_cancel_clicked_cb:
593 * @button:
594 * @state:
595 *
596 * Cancel clicked on the scenario manager tool.
597 **/
598 static void
scenarios_cancel_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)599 scenarios_cancel_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
600 ScenariosState *state)
601 {
602 GSList *cur;
603 WorkbookControl *wbc;
604
605 restore_old_values (state);
606
607 wbc = GNM_WBC (state->base.wbcg);
608
609 /* Remove report sheets created on this dialog session. */
610 for (cur = state->new_report_sheets; cur != NULL;
611 cur = cur->next) {
612 Sheet *sheet = cur->data;
613
614 /* Check that if the focus is on a deleted sheet. */
615 if (wb_control_cur_sheet (wbc) == sheet)
616 wb_control_sheet_focus (wbc, state->base.sheet);
617
618 /* Delete a report sheet. */
619 workbook_sheet_delete (sheet);
620 }
621
622 /* Recover the deleted scenarios. */
623 scenario_recover_all (state->base.sheet);
624
625 scenario_manager_free (state);
626 gtk_widget_destroy (state->base.dialog);
627 }
628
629 static void
scenarios_show_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)630 scenarios_show_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
631 ScenariosState *state)
632 {
633 GtkTreeSelection *selection;
634 GtkTreeIter iter;
635 GtkTreeModel *model;
636 const gchar *value;
637
638 selection = gtk_tree_view_get_selection
639 (GTK_TREE_VIEW (state->scenarios_treeview));
640 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
641 return;
642 model = gtk_tree_view_get_model
643 (GTK_TREE_VIEW (state->scenarios_treeview));
644
645 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &value, -1);
646
647 restore_old_values (state);
648
649 state->current = gnm_sheet_scenario_find (state->base.sheet, value);
650 state->undo = gnm_scenario_apply (state->current);
651 }
652
653 static void
scenarios_delete_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)654 scenarios_delete_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
655 ScenariosState *state)
656 {
657 data_analysis_output_t dao;
658 GtkTreeSelection *selection;
659 GtkTreeIter iter;
660 GtkTreeModel *model;
661 gchar *value;
662 gboolean all_deleted;
663 GnmScenario *sc;
664 GList *l;
665
666 restore_old_values (state);
667
668 selection = gtk_tree_view_get_selection
669 (GTK_TREE_VIEW (state->scenarios_treeview));
670 dao_init_new_sheet (&dao);
671 dao.sheet = state->base.sheet;
672 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
673 return;
674 model = gtk_tree_view_get_model
675 (GTK_TREE_VIEW (state->scenarios_treeview));
676
677 gtk_tree_model_get (GTK_TREE_MODEL (model), &iter, 0, &value, -1);
678
679 gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
680
681 sc = gnm_sheet_scenario_find (state->base.sheet, value);
682 if (sc)
683 g_object_set_data (G_OBJECT (sc),
684 "marked_deleted", GUINT_TO_POINTER (TRUE));
685
686 set_selection_state (state, FALSE);
687
688 all_deleted = TRUE;
689 for (l = state->base.sheet->scenarios; l && all_deleted; l = l->next) {
690 GnmScenario *sc = l->data;
691 if (!g_object_get_data (G_OBJECT (sc), "marked_deleted"))
692 all_deleted = FALSE;
693 }
694
695 gtk_widget_set_sensitive
696 (state->summary_button, !all_deleted);
697 }
698
699 static void
scenarios_summary_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ScenariosState * state)700 scenarios_summary_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
701 ScenariosState *state)
702 {
703 Sheet *new_sheet;
704 GSList *results;
705
706 restore_old_values (state);
707
708 results = gnm_expr_entry_parse_as_list (
709 GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
710
711 if (results == NULL) {
712 go_gtk_notice_dialog (GTK_WINDOW (state->base.dialog),
713 GTK_MESSAGE_ERROR,
714 _("Results entry did not contain valid "
715 "cell names."));
716 return;
717 }
718
719 scenario_summary (GNM_WBC (state->base.wbcg), state->base.sheet,
720 results, &new_sheet);
721
722 state->new_report_sheets =
723 g_slist_prepend (state->new_report_sheets,
724 new_sheet);
725 if (results)
726 g_slist_free_full (results, (GDestroyNotify)value_release);
727 }
728
729 static void
cb_selection_changed(G_GNUC_UNUSED GtkTreeSelection * selection,ScenariosState * state)730 cb_selection_changed (G_GNUC_UNUSED GtkTreeSelection *selection,
731 ScenariosState *state)
732 {
733 set_selection_state (state, TRUE);
734 }
735
736 static gboolean
init_scenario_buttons(ScenariosState * state)737 init_scenario_buttons (ScenariosState *state)
738 {
739 /* Show button */
740 state->show_button =
741 go_gtk_builder_get_widget (state->base.gui, "show_button");
742 if (state->show_button == NULL)
743 return TRUE;
744 g_signal_connect (G_OBJECT (state->show_button),
745 "clicked",
746 G_CALLBACK (scenarios_show_clicked_cb), state);
747
748 /* Delete button */
749 state->delete_button =
750 go_gtk_builder_get_widget (state->base.gui, "delete_button");
751 if (state->delete_button == NULL)
752 return TRUE;
753 g_signal_connect (G_OBJECT (state->delete_button),
754 "clicked",
755 G_CALLBACK (scenarios_delete_clicked_cb), state);
756
757 /* Summary button */
758 state->summary_button =
759 go_gtk_builder_get_widget (state->base.gui, "summary_button");
760 if (state->summary_button == NULL)
761 return TRUE;
762 g_signal_connect (G_OBJECT (state->summary_button),
763 "clicked",
764 G_CALLBACK (scenarios_summary_clicked_cb),
765 state);
766
767 set_selection_state (state, FALSE);
768
769 return FALSE;
770 }
771
772 void
dialog_scenarios(WBCGtk * wbcg)773 dialog_scenarios (WBCGtk *wbcg)
774 {
775 ScenariosState *state;
776 WorkbookControl *wbc;
777 Sheet *sheet;
778 GtkWidget *w;
779 GtkTreeSelection *select;
780 char const *error_str = _("Could not create the Scenarios dialog.");
781
782 g_return_if_fail (wbcg != NULL);
783
784 wbc = GNM_WBC (wbcg);
785 sheet = wb_control_cur_sheet (wbc);
786
787 state = g_new (ScenariosState, 1);
788 state->new_report_sheets = NULL;
789 state->current = NULL;
790 state->undo = NULL;
791 state->base.wb = wb_control_get_workbook (wbc);
792
793 if (dialog_tool_init (&state->base, wbcg, sheet,
794 GNUMERIC_HELP_LINK_SCENARIOS_VIEW,
795 "res:ui/scenario-manager.ui", "Scenarios",
796 error_str, "Scenarios",
797 G_CALLBACK (scenarios_ok_clicked_cb),
798 G_CALLBACK (scenarios_cancel_clicked_cb),
799 G_CALLBACK (scenarios_update_sensitivity_cb),
800 0))
801 goto error_out;
802
803 if (init_scenario_buttons (state))
804 goto error_out;
805
806 state->scenarios_treeview = go_gtk_builder_get_widget
807 (state->base.gui, "scenarios_treeview");
808 if (state->scenarios_treeview == NULL)
809 goto error_out;
810
811 w = go_gtk_builder_get_widget (state->base.gui, "changing_cells_entry");
812 if (w == NULL)
813 goto error_out;
814 gtk_widget_set_sensitive (w, FALSE);
815 w = go_gtk_builder_get_widget (state->base.gui, "comment_view");
816
817 if (w == NULL)
818 goto error_out;
819 gtk_widget_set_sensitive (w, FALSE);
820
821 if (state->base.sheet->scenarios == NULL)
822 gtk_widget_set_sensitive
823 (state->summary_button, FALSE);
824
825 update_scenarios_treeview (state->scenarios_treeview,
826 sheet->scenarios);
827 select = gtk_tree_view_get_selection
828 (GTK_TREE_VIEW (state->scenarios_treeview));
829 g_signal_connect (select, "changed",
830 G_CALLBACK (cb_selection_changed), state);
831
832 scenarios_update_sensitivity_cb (NULL, state);
833 gtk_widget_show (state->base.dialog);
834
835 return;
836
837 error_out:
838 go_gtk_notice_dialog (wbcg_toplevel (wbcg), GTK_MESSAGE_ERROR,
839 "%s", error_str);
840 g_free (state);
841
842 return;
843 }
844