1 /*
2 * dialog-analysis-tool-kaplan-meier.c:
3 *
4 * Authors:
5 * Andreas J. Guelzow <aguelzow@taliesin.ca>
6 *
7 * (C) Copyright 2008 by Andreas J. Guelzow <aguelzow@pyrshep.ca>
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
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <dialogs/dialogs.h>
27 #include <tools/analysis-kaplan-meier.h>
28 #include <tools/analysis-tools.h>
29
30 #include <workbook.h>
31 #include <workbook-control.h>
32 #include <wbc-gtk.h>
33 #include <workbook-view.h>
34 #include <gui-util.h>
35 #include <parse-util.h>
36 #include <gnm-format.h>
37 #include <dialogs/tool-dialogs.h>
38 #include <dialogs/dao-gui-utils.h>
39 #include <sheet.h>
40 #include <expr.h>
41 #include <number-match.h>
42 #include <ranges.h>
43 #include <selection.h>
44 #include <value.h>
45 #include <commands.h>
46 #include <dialogs/help.h>
47
48 #include <widgets/gnm-dao.h>
49 #include <widgets/gnm-expr-entry.h>
50
51 #include <string.h>
52
53 #define KAPLAN_MEIER_KEY "analysistools-kaplan-meier-dialog"
54
55 typedef struct {
56 GnmGenericToolState base;
57 GtkWidget *censorship_button;
58 GtkWidget *censor_spin_from;
59 GtkWidget *censor_spin_to;
60 GtkWidget *graph_button;
61 GtkWidget *logrank_button;
62 GtkWidget *tick_button;
63 GtkWidget *add_group_button;
64 GtkWidget *remove_group_button;
65 GtkWidget *std_error_button;
66 GtkWidget *groups_check;
67 GtkWidget *groups_grid;
68 GnmExprEntry *groups_input;
69 GtkTreeView *groups_treeview;
70 GtkListStore *groups_list;
71 } KaplanMeierToolState;
72
73 enum
74 {
75 GROUP_NAME,
76 GROUP_FROM,
77 GROUP_TO,
78 GROUP_ADJUSTMENT_FROM,
79 GROUP_ADJUSTMENT_TO,
80 GROUP_COLUMNS
81 };
82
83
84 /**
85 * kaplan_meier_tool_update_sensitivity_cb:
86 * @dummy:
87 * @state:
88 *
89 * Update the dialog widgets sensitivity
90 **/
91 static void
kaplan_meier_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)92 kaplan_meier_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
93 KaplanMeierToolState *state)
94 {
95 gboolean censorship;
96 gboolean groups;
97 GnmValue *input_range;
98 GnmValue *input_range_2 = NULL;
99 int height, width;
100
101 censorship = gtk_toggle_button_get_active (
102 GTK_TOGGLE_BUTTON (state->censorship_button));
103 groups = gtk_toggle_button_get_active (
104 GTK_TOGGLE_BUTTON (state->groups_check));
105
106 gtk_widget_set_sensitive (state->tick_button, censorship);
107
108 input_range = gnm_expr_entry_parse_as_value
109 (GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
110 if (input_range == NULL) {
111 gtk_label_set_text (GTK_LABEL (state->base.warning),
112 _("The time column is not valid."));
113 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
114 return;
115 }
116
117 height = input_range->v_range.cell.b.row - input_range->v_range.cell.a.row;
118 width = input_range->v_range.cell.b.col - input_range->v_range.cell.a.col;
119
120 value_release (input_range);
121
122 if (width != 0) {
123 gtk_label_set_text (GTK_LABEL (state->base.warning),
124 _("The time column should be part of a single column."));
125 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
126 return;
127 }
128
129 if (censorship) {
130 input_range_2 = gnm_expr_entry_parse_as_value
131 (GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
132 if (input_range_2 == NULL) {
133 gtk_label_set_text (GTK_LABEL (state->base.warning),
134 _("The censorship column is not valid."));
135 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
136 return;
137 }
138
139 if (input_range_2->v_range.cell.b.col != input_range_2->v_range.cell.a.col) {
140 gtk_label_set_text (GTK_LABEL (state->base.warning),
141 _("The censorship column should be part of a single column."));
142 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
143 value_release (input_range_2);
144 return;
145 }
146 if (input_range_2->v_range.cell.b.row - input_range_2->v_range.cell.a.row != height) {
147 gtk_label_set_text (GTK_LABEL (state->base.warning),
148 _("The censorship and time columns should have the same height."));
149 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
150 value_release (input_range_2);
151 return;
152 }
153
154 value_release (input_range_2);
155 }
156
157 if (groups) {
158 input_range_2 = gnm_expr_entry_parse_as_value
159 (GNM_EXPR_ENTRY (state->groups_input), state->base.sheet);
160
161 if (input_range_2 == NULL) {
162 gtk_label_set_text (GTK_LABEL (state->base.warning),
163 _("The groups column is not valid."));
164 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
165 return;
166 }
167 if (input_range_2->v_range.cell.b.col != input_range_2->v_range.cell.a.col) {
168 gtk_label_set_text (GTK_LABEL (state->base.warning),
169 _("The groups column should be part of a single column."));
170 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
171 value_release (input_range_2);
172 return;
173 }
174 if (input_range_2->v_range.cell.b.row - input_range_2->v_range.cell.a.row != height) {
175 gtk_label_set_text (GTK_LABEL (state->base.warning),
176 _("The groups and time columns should have the same height."));
177 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
178 value_release (input_range_2);
179 return;
180 }
181
182 value_release (input_range_2);
183 }
184
185 if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
186 gtk_label_set_text (GTK_LABEL (state->base.warning),
187 _("The output specification "
188 "is invalid."));
189 gtk_widget_set_sensitive (state->base.ok_button, FALSE);
190 return;
191 }
192
193 gtk_label_set_text (GTK_LABEL (state->base.warning), "");
194 gtk_widget_set_sensitive (state->base.ok_button, TRUE);
195
196 return;
197 }
198
199 static gboolean
kaplan_meier_tool_get_groups_cb(GtkTreeModel * model,G_GNUC_UNUSED GtkTreePath * path,GtkTreeIter * iter,gpointer data)200 kaplan_meier_tool_get_groups_cb (GtkTreeModel *model,
201 G_GNUC_UNUSED GtkTreePath *path,
202 GtkTreeIter *iter,
203 gpointer data)
204 {
205 GSList **list = data;
206 analysis_tools_kaplan_meier_group_t *group_item =
207 g_new0 (analysis_tools_kaplan_meier_group_t, 1);
208
209 gtk_tree_model_get (model, iter,
210 GROUP_NAME, &(group_item->name),
211 GROUP_FROM, &(group_item->group_from),
212 GROUP_TO, &(group_item->group_to),
213 -1);
214 *list = g_slist_prepend (*list, group_item);
215
216 return FALSE;
217 }
218
219 static GSList *
kaplan_meier_tool_get_groups(KaplanMeierToolState * state)220 kaplan_meier_tool_get_groups (KaplanMeierToolState *state)
221 {
222 GSList *list = NULL;
223
224 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->groups_check)))
225 return NULL;
226
227 gtk_tree_model_foreach (GTK_TREE_MODEL (state->groups_list),
228 kaplan_meier_tool_get_groups_cb,
229 &list);
230 return g_slist_reverse (list);
231 }
232
233 /**
234 * kaplan_meier_tool_ok_clicked_cb:
235 * @button:
236 * @state:
237 *
238 * Retrieve the information from the dialog and call the kaplan_meier_tool.
239 * Note that we assume that the ok_button is only active if the entry fields
240 * contain sensible data.
241 **/
242 static void
kaplan_meier_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,KaplanMeierToolState * state)243 kaplan_meier_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
244 KaplanMeierToolState *state)
245 {
246 data_analysis_output_t *dao;
247 analysis_tools_data_kaplan_meier_t *data;
248
249 data = g_new0 (analysis_tools_data_kaplan_meier_t, 1);
250 dao = parse_output ((GnmGenericToolState *)state, NULL);
251
252
253 data->base.wbc = GNM_WBC (state->base.wbcg);
254
255 if (state->base.warning_dialog != NULL)
256 gtk_widget_destroy (state->base.warning_dialog);
257
258 data->base.range_1 = gnm_expr_entry_parse_as_value
259 (GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
260
261 data->censored = gtk_toggle_button_get_active (
262 GTK_TOGGLE_BUTTON (state->censorship_button));
263
264 if (data->censored)
265 data->base.range_2 = gnm_expr_entry_parse_as_value
266 (GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
267 else
268 data->base.range_2 = NULL;
269
270 data->censor_mark = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (state->censor_spin_from));
271 data->censor_mark_to = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (state->censor_spin_to));
272
273 data->group_list = kaplan_meier_tool_get_groups (state);
274 if (data->group_list == NULL) {
275 data->range_3 = NULL;
276 data->logrank_test = FALSE;
277 } else {
278 data->range_3 = gnm_expr_entry_parse_as_value
279 (GNM_EXPR_ENTRY (state->groups_input), state->base.sheet);
280 data->logrank_test = gtk_toggle_button_get_active (
281 GTK_TOGGLE_BUTTON (state->logrank_button));
282 }
283
284 data->median = gtk_toggle_button_get_active (
285 GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget
286 (state->base.gui,
287 "median-button")));
288 data->chart = gtk_toggle_button_get_active (
289 GTK_TOGGLE_BUTTON (state->graph_button));
290 data->ticks = gtk_toggle_button_get_active (
291 GTK_TOGGLE_BUTTON (state->tick_button));
292 data->std_err = gtk_toggle_button_get_active (
293 GTK_TOGGLE_BUTTON (state->std_error_button));
294
295 if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg),
296 state->base.sheet,
297 dao, data, analysis_tool_kaplan_meier_engine,
298 TRUE))
299 gtk_widget_destroy (state->base.dialog);
300
301 return;
302 }
303
304 /**
305 * kaplan_meier_tool_set_graph:
306 * @widget:
307 * @focus_widget:
308 * @state:
309 *
310 *
311 **/
312 static gboolean
kaplan_meier_tool_set_graph_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)313 kaplan_meier_tool_set_graph_cb (G_GNUC_UNUSED GtkWidget *dummy,
314 KaplanMeierToolState *state)
315 {
316 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->graph_button), TRUE);
317 kaplan_meier_tool_update_sensitivity_cb (NULL, state);
318 return FALSE;
319 }
320
321 /**
322 * kaplan_meier_tool_set_censorship:
323 * @widget:
324 * @event:
325 * @state:
326 *
327 **/
328 static gboolean
kaplan_meier_tool_set_censorship_cb(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,KaplanMeierToolState * state)329 kaplan_meier_tool_set_censorship_cb (G_GNUC_UNUSED GtkWidget *widget,
330 G_GNUC_UNUSED GdkEventFocus *event,
331 KaplanMeierToolState *state)
332 {
333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->censorship_button), TRUE);
334 return FALSE;
335 }
336
337 static gboolean
kaplan_meier_tool_set_groups_cb(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,KaplanMeierToolState * state)338 kaplan_meier_tool_set_groups_cb (G_GNUC_UNUSED GtkWidget *widget,
339 G_GNUC_UNUSED GdkEventFocus *event,
340 KaplanMeierToolState *state)
341 {
342 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->groups_check), TRUE);
343 return FALSE;
344 }
345
346
347 static gboolean
kaplan_meier_tool_set_censor_from_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)348 kaplan_meier_tool_set_censor_from_cb (G_GNUC_UNUSED GtkWidget *dummy,
349 KaplanMeierToolState *state)
350 {
351 gtk_spin_button_set_range (GTK_SPIN_BUTTON (state->censor_spin_to),
352 gtk_spin_button_get_value (GTK_SPIN_BUTTON (state->censor_spin_from)),G_MAXSHORT);
353 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->censorship_button), TRUE);
354
355 return FALSE;
356 }
357 static gboolean
kaplan_meier_tool_set_censor_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)358 kaplan_meier_tool_set_censor_cb (G_GNUC_UNUSED GtkWidget *dummy,
359 KaplanMeierToolState *state)
360 {
361 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->censorship_button), TRUE);
362
363 return FALSE;
364 }
365
366 static void
cb_group_name_edited(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,KaplanMeierToolState * state)367 cb_group_name_edited (GtkCellRendererText *cell,
368 gchar *path_string,
369 gchar *new_text,
370 KaplanMeierToolState *state)
371 {
372 GtkTreeIter iter;
373 GtkTreePath *path;
374
375 if (cell != NULL) {
376 path = gtk_tree_path_new_from_string (path_string);
377 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list),
378 &iter, path))
379 gtk_list_store_set (state->groups_list, &iter,
380 GROUP_NAME, new_text, -1);
381 else
382 g_warning ("Did not get a valid iterator");
383 gtk_tree_path_free (path);
384 }
385 }
386
387 static void
cb_change_to(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,KaplanMeierToolState * state)388 cb_change_to (GtkCellRendererText *cell,
389 gchar *path_string,
390 gchar *new_text,
391 KaplanMeierToolState *state)
392 {
393 GtkTreeIter iter;
394 GtkTreePath *path;
395 guint val = (guint) (atoi (new_text));
396
397 if (cell != NULL) {
398 path = gtk_tree_path_new_from_string (path_string);
399 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list),
400 &iter, path))
401 gtk_list_store_set (state->groups_list, &iter,
402 GROUP_TO, val, -1);
403 else
404 g_warning ("Did not get a valid iterator");
405 gtk_tree_path_free (path);
406 }
407 }
408
409 static void
cb_change_from(GtkCellRendererText * cell,gchar * path_string,gchar * new_text,KaplanMeierToolState * state)410 cb_change_from (GtkCellRendererText *cell,
411 gchar *path_string,
412 gchar *new_text,
413 KaplanMeierToolState *state)
414 {
415 if (cell != NULL) {
416 GtkTreeIter iter;
417 GtkTreePath *path;
418 guint val = (guint) (atoi (new_text));
419 guint old_to;
420 GObject *adjustment_to;
421
422
423 path = gtk_tree_path_new_from_string (path_string);
424 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (state->groups_list),
425 &iter, path))
426 gtk_list_store_set (state->groups_list, &iter,
427 GROUP_FROM, val,
428 -1);
429 else
430 g_warning ("Did not get a valid iterator");
431 gtk_tree_path_free (path);
432
433 gtk_tree_model_get (GTK_TREE_MODEL (state->groups_list), &iter,
434 GROUP_TO, &old_to,
435 GROUP_ADJUSTMENT_TO, &adjustment_to,
436 -1);
437
438 if (old_to < val)
439 gtk_list_store_set (state->groups_list, &iter,
440 GROUP_TO, val,
441 -1);
442 g_object_set (adjustment_to, "lower", (gdouble) val, NULL);
443
444 }
445 }
446
447 static void
cb_selection_changed(GtkTreeSelection * selection,KaplanMeierToolState * state)448 cb_selection_changed (GtkTreeSelection *selection,
449 KaplanMeierToolState *state)
450 {
451 gtk_widget_set_sensitive (state->remove_group_button,
452 gtk_tree_selection_get_selected (selection, NULL, NULL));
453 }
454
455 static void
kaplan_meier_tool_update_groups_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)456 kaplan_meier_tool_update_groups_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
457 KaplanMeierToolState *state)
458 {
459 gboolean groups = gtk_toggle_button_get_active (
460 GTK_TOGGLE_BUTTON (state->groups_check));
461 GtkTreeSelection *selection = gtk_tree_view_get_selection (state->groups_treeview);
462
463 gtk_widget_set_sensitive (state->add_group_button, groups);
464 gtk_widget_set_sensitive (GTK_WIDGET (state->groups_treeview), groups);
465
466 if (groups) {
467 cb_selection_changed (selection, state);
468 gtk_widget_set_sensitive (state->logrank_button, TRUE);
469 } else {
470 gtk_tree_selection_unselect_all (selection);
471 gtk_widget_set_sensitive (state->remove_group_button, FALSE);
472 gtk_widget_set_sensitive (state->logrank_button, FALSE);
473 }
474 }
475
476 static void
dialog_kaplan_meier_tool_treeview_add_item(KaplanMeierToolState * state,guint i)477 dialog_kaplan_meier_tool_treeview_add_item (KaplanMeierToolState *state, guint i)
478 {
479 GtkTreeIter iter;
480 char * name = g_strdup_printf (_("Group %d"), i);
481 GObject *adjustment_to =
482 G_OBJECT (gtk_adjustment_new (0, 0, G_MAXUSHORT, 1, 1, 1));
483 GObject *adjustment_from =
484 G_OBJECT (gtk_adjustment_new (0, 0, G_MAXUSHORT, 1, 1, 1));
485 gtk_list_store_append (state->groups_list, &iter);
486 gtk_list_store_set (state->groups_list, &iter,
487 GROUP_NAME, name,
488 GROUP_FROM, (guint) i,
489 GROUP_TO, (guint) i,
490 GROUP_ADJUSTMENT_FROM, adjustment_from,
491 GROUP_ADJUSTMENT_TO, adjustment_to,
492 -1);
493 g_free (name);
494 }
495
496 static void
dialog_kaplan_meier_tool_setup_treeview(KaplanMeierToolState * state)497 dialog_kaplan_meier_tool_setup_treeview (KaplanMeierToolState *state)
498 {
499 guint i;
500 GtkCellRenderer *renderer;
501 GtkWidget *scrolled = go_gtk_builder_get_widget (state->base.gui, "groups-scrolled");
502 GtkTreeSelection *selection;
503
504 state->groups_treeview = GTK_TREE_VIEW (go_gtk_builder_get_widget
505 (state->base.gui,
506 "groups-tree"));
507 state->groups_list = gtk_list_store_new (GROUP_COLUMNS,
508 G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_OBJECT);
509 state->groups_treeview = GTK_TREE_VIEW (gtk_tree_view_new_with_model
510 (GTK_TREE_MODEL (state->groups_list)));
511 g_object_unref (state->groups_list);
512 selection = gtk_tree_view_get_selection (state->groups_treeview);
513 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
514
515 for (i = 0; i<2; i++)
516 dialog_kaplan_meier_tool_treeview_add_item (state, i);
517
518 g_signal_connect (selection,
519 "changed",
520 G_CALLBACK (cb_selection_changed), state);
521
522 renderer = gtk_cell_renderer_text_new ();
523 g_object_set (G_OBJECT (renderer),
524 "editable", TRUE,
525 NULL);
526 gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
527 -1, _("Group"),
528 renderer,
529 "text", GROUP_NAME,
530 NULL);
531 g_signal_connect (G_OBJECT (renderer), "edited",
532 G_CALLBACK (cb_group_name_edited), state);
533
534 renderer = gtk_cell_renderer_spin_new ();
535
536 g_object_set (G_OBJECT (renderer), "editable", TRUE, "xalign", 1.0,
537 "digits", 0, NULL);
538 g_signal_connect (G_OBJECT (renderer), "edited",
539 G_CALLBACK (cb_change_from), state);
540 gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
541 -1, _("From"),
542 renderer,
543 "text", GROUP_FROM,
544 "adjustment", GROUP_ADJUSTMENT_FROM,
545 NULL);
546
547 renderer = gtk_cell_renderer_spin_new ();
548 g_object_set (G_OBJECT (renderer), "editable", TRUE, "xalign", 1.0,
549 "digits", 0, NULL);
550 g_signal_connect (G_OBJECT (renderer), "edited",
551 G_CALLBACK (cb_change_to), state);
552 gtk_tree_view_insert_column_with_attributes (state->groups_treeview,
553 -1, _("To"),
554 renderer,
555 "text", GROUP_TO,
556 "adjustment", GROUP_ADJUSTMENT_TO,
557 NULL);
558
559 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (state->groups_treeview));
560
561 cb_selection_changed (selection, state);
562 }
563
564 static gboolean
kaplan_meier_tool_add_group_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)565 kaplan_meier_tool_add_group_cb (G_GNUC_UNUSED GtkWidget *dummy,
566 KaplanMeierToolState *state)
567 {
568 dialog_kaplan_meier_tool_treeview_add_item
569 (state, gtk_tree_model_iter_n_children (GTK_TREE_MODEL (state->groups_list),
570 NULL));
571 return FALSE;
572 }
573
574 static gboolean
kaplan_meier_tool_remove_group_cb(G_GNUC_UNUSED GtkWidget * dummy,KaplanMeierToolState * state)575 kaplan_meier_tool_remove_group_cb (G_GNUC_UNUSED GtkWidget *dummy,
576 KaplanMeierToolState *state)
577 {
578 GtkTreeSelection *selection;
579 GtkTreeIter iter;
580
581 selection = gtk_tree_view_get_selection (state->groups_treeview);
582
583 if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
584 gtk_list_store_remove ( state->groups_list, &iter);
585 }
586
587 return FALSE;
588 }
589
590
591 /**
592 * dialog_kaplan_meier_tool:
593 * @wbcg:
594 * @sheet:
595 *
596 * Show the dialog (guru).
597 *
598 **/
599 int
dialog_kaplan_meier_tool(WBCGtk * wbcg,Sheet * sheet)600 dialog_kaplan_meier_tool (WBCGtk *wbcg, Sheet *sheet)
601 {
602 KaplanMeierToolState *state;
603 GtkWidget *widget;
604 char const * plugins[] = { "Gnumeric_fnstat",
605 "Gnumeric_fnlookup",
606 "Gnumeric_fnmath",
607 "Gnumeric_fninfo",
608 "Gnumeric_fnlogical",
609 NULL};
610
611 if ((wbcg == NULL) ||
612 gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
613 return 1;
614
615 /* Only pop up one copy per workbook */
616 if (gnm_dialog_raise_if_exists (wbcg, KAPLAN_MEIER_KEY))
617 return 0;
618
619 state = g_new0 (KaplanMeierToolState, 1);
620
621 if (dialog_tool_init (&state->base, wbcg, sheet,
622 GNUMERIC_HELP_LINK_KAPLAN_MEIER,
623 "res:ui/kaplan-meier.ui", "KaplanMeier",
624 _("Could not create the Kaplan Meier Tool dialog."),
625 KAPLAN_MEIER_KEY,
626 G_CALLBACK (kaplan_meier_tool_ok_clicked_cb), NULL,
627 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb),
628 0))
629 {
630 g_free(state);
631 return 0;
632 }
633
634
635
636 state->censorship_button = GTK_WIDGET (go_gtk_builder_get_widget
637 (state->base.gui,
638 "censor-button"));
639 state->censor_spin_from = GTK_WIDGET (go_gtk_builder_get_widget
640 (state->base.gui,
641 "censored-spinbutton1"));
642 gtk_spin_button_set_range (GTK_SPIN_BUTTON (state->censor_spin_from), 0.,G_MAXSHORT);
643 state->censor_spin_to = GTK_WIDGET (go_gtk_builder_get_widget
644 (state->base.gui,
645 "censored-spinbutton2"));
646 gtk_spin_button_set_range (GTK_SPIN_BUTTON (state->censor_spin_to), 0.,G_MAXSHORT);
647 state->graph_button = GTK_WIDGET (go_gtk_builder_get_widget
648 (state->base.gui,
649 "graph-button"));
650 state->tick_button = GTK_WIDGET (go_gtk_builder_get_widget
651 (state->base.gui,
652 "tick-button"));
653 state->add_group_button = GTK_WIDGET (go_gtk_builder_get_widget
654 (state->base.gui,
655 "add-button"));
656 state->remove_group_button = GTK_WIDGET (go_gtk_builder_get_widget
657 (state->base.gui,
658 "remove-button"));
659 state->std_error_button = GTK_WIDGET (go_gtk_builder_get_widget
660 (state->base.gui,
661 "std-error-button"));
662 state->logrank_button = GTK_WIDGET (go_gtk_builder_get_widget
663 (state->base.gui,
664 "logrank-button"));
665
666 state->groups_check = GTK_WIDGET (go_gtk_builder_get_widget
667 (state->base.gui,
668 "groups-check"));
669 state->groups_grid = GTK_WIDGET (go_gtk_builder_get_widget
670 (state->base.gui,
671 "groups-grid"));
672 state->groups_input = gnm_expr_entry_new (state->base.wbcg, TRUE);
673 gnm_expr_entry_set_flags (state->groups_input, GNM_EE_FORCE_ABS_REF,
674 GNM_EE_MASK);
675 gtk_grid_attach (GTK_GRID (state->groups_grid),
676 GTK_WIDGET (state->groups_input), 1, 1, 2, 1);
677
678 dialog_kaplan_meier_tool_setup_treeview (state);
679
680 g_signal_connect_after (G_OBJECT (state->groups_check),
681 "toggled",
682 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
683 g_signal_connect_after (G_OBJECT (state->censorship_button),
684 "toggled",
685 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
686 g_signal_connect_after (G_OBJECT (state->graph_button),
687 "toggled",
688 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
689 g_signal_connect_after (G_OBJECT (state->std_error_button),
690 "toggled",
691 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb), state);
692 g_signal_connect_after (G_OBJECT (state->groups_input),
693 "changed",
694 G_CALLBACK (kaplan_meier_tool_update_sensitivity_cb),
695 state);
696
697 g_signal_connect_after (G_OBJECT (state->groups_check),
698 "toggled",
699 G_CALLBACK (kaplan_meier_tool_update_groups_sensitivity_cb), state);
700 g_signal_connect_after (G_OBJECT (state->tick_button),
701 "toggled",
702 G_CALLBACK (kaplan_meier_tool_set_graph_cb), state);
703 g_signal_connect_after (G_OBJECT (state->add_group_button),
704 "clicked",
705 G_CALLBACK (kaplan_meier_tool_add_group_cb), state);
706 g_signal_connect_after (G_OBJECT (state->remove_group_button),
707 "clicked",
708 G_CALLBACK (kaplan_meier_tool_remove_group_cb), state);
709 g_signal_connect_after (G_OBJECT (state->censor_spin_from),
710 "value-changed",
711 G_CALLBACK (kaplan_meier_tool_set_censor_from_cb), state);
712 g_signal_connect_after (G_OBJECT (state->censor_spin_to),
713 "value-changed",
714 G_CALLBACK (kaplan_meier_tool_set_censor_cb), state);
715 g_signal_connect (G_OBJECT
716 (gnm_expr_entry_get_entry (
717 GNM_EXPR_ENTRY (state->base.input_entry_2))),
718 "focus-in-event",
719 G_CALLBACK (kaplan_meier_tool_set_censorship_cb), state);
720 g_signal_connect (G_OBJECT
721 (gnm_expr_entry_get_entry (
722 GNM_EXPR_ENTRY (state->groups_input))),
723 "focus-in-event",
724 G_CALLBACK (kaplan_meier_tool_set_groups_cb), state);
725
726 gnm_editable_enters (GTK_WINDOW (state->base.dialog),
727 GTK_WIDGET (state->groups_input));
728
729 widget = go_gtk_builder_get_widget (state->base.gui, "groups-label");
730 gtk_label_set_mnemonic_widget (GTK_LABEL (widget),
731 GTK_WIDGET (state->groups_input));
732 go_atk_setup_label (widget, GTK_WIDGET (state->groups_input));
733
734 gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
735 kaplan_meier_tool_update_sensitivity_cb (NULL, state);
736 kaplan_meier_tool_update_groups_sensitivity_cb (NULL, state);
737 tool_load_selection ((GnmGenericToolState *)state, TRUE);
738
739 gtk_widget_show_all (GTK_WIDGET (state->base.dialog));
740 /* And to hide the in-place button again */
741 gnm_dao_set_inplace ( GNM_DAO (state->base.gdao), NULL);
742
743 return 0;
744 }
745