1 /*
2  * dialog-analysis-tools.c:
3  *
4  * Authors:
5  *  Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
6  *  Andreas J. Guelzow  <aguelzow@taliesin.ca>
7  *
8  * (C) Copyright 2000, 2001 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include <gnumeric-config.h>
25 #include <glib/gi18n-lib.h>
26 #include <gnumeric.h>
27 #include <dialogs/dialogs.h>
28 #include <tools/analysis-tools.h>
29 #include <tools/analysis-anova.h>
30 #include <tools/analysis-histogram.h>
31 #include <tools/analysis-exp-smoothing.h>
32 
33 #include <workbook.h>
34 #include <workbook-control.h>
35 #include <wbc-gtk.h>
36 #include <workbook-view.h>
37 #include <gui-util.h>
38 #include <parse-util.h>
39 #include <gnm-format.h>
40 #include <dialogs/tool-dialogs.h>
41 #include <dialogs/dao-gui-utils.h>
42 #include <sheet.h>
43 #include <expr.h>
44 #include <number-match.h>
45 #include <ranges.h>
46 #include <selection.h>
47 #include <value.h>
48 #include <commands.h>
49 #include <dialogs/help.h>
50 
51 #include <widgets/gnm-dao.h>
52 #include <widgets/gnm-expr-entry.h>
53 
54 #include <string.h>
55 
56 /**********************************************/
57 /*  Generic guru items */
58 /**********************************************/
59 
60 
61 
62 #define CORRELATION_KEY       "analysistools-correlation-dialog"
63 #define COVARIANCE_KEY        "analysistools-covariance-dialog"
64 #define DESCRIPTIVE_STATS_KEY "analysistools-descriptive-stats-dialog"
65 #define RANK_PERCENTILE_KEY   "analysistools-rank-percentile-dialog"
66 #define TTEST_KEY             "analysistools-ttest-dialog"
67 #define FTEST_KEY             "analysistools-ftest-dialog"
68 #define SAMPLING_KEY          "analysistools-sampling-dialog"
69 #define HISTOGRAM_KEY         "analysistools-histogram-dialog"
70 #define FOURIER_KEY           "analysistools-fourier-dialog"
71 #define AVERAGE_KEY           "analysistools-moving-average-dialog"
72 #define EXP_SMOOTHING_KEY     "analysistools-exp-smoothing-dialog"
73 #define REGRESSION_KEY        "analysistools-regression-dialog"
74 #define ANOVA_TWO_FACTOR_KEY  "analysistools-anova-two-factor-dialog"
75 #define ANOVA_SINGLE_KEY      "analysistools-anova-single-factor-dialog"
76 
77 
78 static char const * const grouped_by_group[] = {
79 	"grouped_by_row",
80 	"grouped_by_col",
81 	"grouped_by_area",
82 	NULL
83 };
84 
85 typedef struct {
86 	GnmGenericToolState base;
87 	GtkWidget *predetermined_button;
88 	GtkWidget *calculated_button;
89 	GtkEntry  *n_entry;
90 	GtkEntry  *max_entry;
91 	GtkEntry  *min_entry;
92 } HistogramToolState;
93 
94 static char const * const bin_type_group[] = {
95 	"bintype_no_inf_lower",
96 	"bintype_no_inf_upper",
97 	"bintype_p_inf_lower",
98 	"bintype_p_inf_upper",
99 	"bintype_m_inf_lower",
100 	"bintype_m_inf_upper",
101 	"bintype_pm_inf_lower",
102 	"bintype_pm_inf_upper",
103 	NULL
104 };
105 
106 static char const * const chart_group[] = {
107 	"nochart-button",
108 	"histogram-button",
109 	"barchart-button",
110 	"columnchart-button",
111 	NULL
112 };
113 
114 static char const * const n_group[] = {
115 	"n-button",
116 	"nm1-button",
117 	"nm2-button",
118 	"nm3-button",
119 	NULL
120 };
121 
122 /* Note: the items in this group need to match */
123 /*       moving_average_type_t except that     */
124 /*       moving_average_type_central_sma is a  */
125 /*       subtype of moving_average_type_sma.   */
126 static char const * const moving_average_group[] = {
127 	"sma-button",
128 	"cma-button",
129 	"wma-button",
130 	"spencer-ma-button",
131 	NULL
132 };
133 
134 static char const * const exp_smoothing_group[] = {
135 	"ses-h-button",
136 	"ses-r-button",
137 	"des-button",
138 	"ates-button",
139 	"mtes-button",
140 	NULL
141 };
142 
143 
144 
145 typedef struct {
146 	GnmGenericToolState base;
147 	GtkWidget *summary_stats_button;
148 	GtkWidget *mean_stats_button;
149 	GtkWidget *kth_largest_button;
150 	GtkWidget *kth_smallest_button;
151 	GtkWidget *ss_button;
152 	GtkWidget *c_entry;
153 	GtkWidget *l_entry;
154 	GtkWidget *s_entry;
155 } DescriptiveStatState;
156 
157 typedef struct {
158 	GnmGenericToolState base;
159 	GtkWidget *paired_button;
160 	GtkWidget *unpaired_button;
161 	GtkWidget *known_button;
162 	GtkWidget *unknown_button;
163 	GtkWidget *equal_button;
164 	GtkWidget *unequal_button;
165 	GtkWidget *variablespaired_label;
166 	GtkWidget *varianceknown_label;
167 	GtkWidget *varianceequal_label;
168 	GtkWidget *var1_variance_label;
169 	GtkWidget *var2_variance_label;
170 	GtkWidget *var1_variance;
171 	GtkWidget *var2_variance;
172 	GtkWidget *options_grid;
173 	GtkWidget *mean_diff_entry;
174 	GtkWidget *alpha_entry;
175 	ttest_type invocation;
176 } TTestState;
177 
178 typedef struct {
179 	GnmGenericToolState base;
180 	GtkWidget *options_grid;
181 	GtkWidget *method_label;
182 	GtkWidget *periodic_button;
183 	GtkWidget *random_button;
184 	GtkWidget *period_label;
185 	GtkWidget *random_label;
186 	GtkWidget *period_entry;
187 	GtkWidget *random_entry;
188 	GtkWidget *number_entry;
189 	GtkWidget *offset_label;
190 	GtkWidget *offset_entry;
191 	GtkWidget *major_label;
192 	GtkWidget *row_major_button;
193 	GtkWidget *col_major_button;
194 } SamplingState;
195 
196 typedef struct {
197 	GnmGenericToolState base;
198 	GtkWidget *interval_entry;
199 	GtkWidget *show_std_errors;
200 	GtkWidget *n_button;
201 	GtkWidget *nm1_button;
202 	GtkWidget *nm2_button;
203 	GtkWidget *prior_button;
204 	GtkWidget *central_button;
205 	GtkWidget *offset_button;
206 	GtkWidget *offset_spin;
207 	GtkWidget *graph_button;
208 	GtkWidget *sma_button;
209 	GtkWidget *cma_button;
210 	GtkWidget *wma_button;
211 	GtkWidget *spencer_button;
212 } AverageToolState;
213 
214 typedef struct {
215 	GnmGenericToolState base;
216         GtkWidget *damping_fact_entry;
217         GtkWidget *g_damping_fact_entry;
218         GtkWidget *s_damping_fact_entry;
219         GtkWidget *s_period_entry;
220 	GtkWidget *show_std_errors;
221 	GtkWidget *n_button;
222 	GtkWidget *nm1_button;
223 	GtkWidget *nm2_button;
224 	GtkWidget *nm3_button;
225 	GtkWidget *graph_button;
226 	GtkWidget *ses_h_button;
227 	GtkWidget *ses_r_button;
228 	GtkWidget *des_button;
229 	GtkWidget *ates_button;
230 	GtkWidget *mtes_button;
231 } ExpSmoothToolState;
232 
233 typedef struct {
234 	GnmGenericToolState base;
235 	GtkWidget *confidence_entry;
236 	GtkWidget *simple_linear_regression_radio;
237 	GtkWidget *switch_variables_check;
238 	GtkWidget *residuals_check;
239 } RegressionToolState;
240 
241 typedef struct {
242 	GnmGenericToolState base;
243 	GtkWidget *alpha_entry;
244 } AnovaSingleToolState;
245 
246 typedef struct {
247 	GnmGenericToolState base;
248 	GtkWidget *alpha_entry;
249 	GtkWidget *replication_entry;
250 } AnovaTwoFactorToolState;
251 
252 typedef struct {
253 	GnmGenericToolState base;
254 	GtkWidget *alpha_entry;
255 } FTestToolState;
256 
257 
258 /**********************************************/
259 /*  Generic functions for the analysis tools. */
260 /*  Functions in this section are being used  */
261 /*  by virtually all tools.                   */
262 /**********************************************/
263 
264 
265 /**
266  * error_in_entry:
267  * @state:
268  * @entry:
269  * @err_str:
270  *
271  * Show an error dialog and select corresponding entry
272  */
273 void
error_in_entry(GnmGenericToolState * state,GtkWidget * entry,char const * err_str)274 error_in_entry (GnmGenericToolState *state, GtkWidget *entry, char const *err_str)
275 {
276         go_gtk_notice_nonmodal_dialog ((GtkWindow *) state->dialog,
277 				       &(state->warning_dialog),
278 				       GTK_MESSAGE_ERROR,
279 				       "%s", err_str);
280 
281 	if (GNM_EXPR_ENTRY_IS (entry))
282 		gnm_expr_entry_grab_focus (GNM_EXPR_ENTRY (entry), TRUE);
283 	else
284 		focus_on_entry (GTK_ENTRY (entry));
285 }
286 
287 static void
cb_tool_destroy(GnmGenericToolState * state)288 cb_tool_destroy (GnmGenericToolState  *state)
289 {
290 	if (state->gui != NULL)
291 		g_object_unref (state->gui);
292 	wbcg_edit_finish (state->wbcg, WBC_EDIT_REJECT, NULL);
293 	if (state->state_destroy)
294 		state->state_destroy (state);
295 	g_free (state);
296 }
297 
298 /**
299  * cb_tool_cancel_clicked:
300  * @button:
301  * @state:
302  *
303  * Close (destroy) the dialog
304  **/
305 static void
cb_tool_cancel_clicked(G_GNUC_UNUSED GtkWidget * button,GnmGenericToolState * state)306 cb_tool_cancel_clicked (G_GNUC_UNUSED GtkWidget *button,
307 			GnmGenericToolState *state)
308 {
309 	gtk_widget_destroy (state->dialog);
310 	return;
311 }
312 
313 
314 
315 /**
316  * dialog_tool_init_buttons:
317  * @state:
318  * @ok_function:
319  *
320  * Setup the buttons
321  *
322  **/
323 static void
dialog_tool_init_buttons(GnmGenericToolState * state,GCallback ok_function,GCallback close_function)324 dialog_tool_init_buttons (GnmGenericToolState *state,
325 			  GCallback ok_function,
326 			  GCallback close_function)
327 {
328 	state->ok_button = go_gtk_builder_get_widget (state->gui, "okbutton");
329 	g_signal_connect (G_OBJECT (state->ok_button),
330 		"clicked",
331 		G_CALLBACK (ok_function), state);
332 
333 	state->cancel_button = go_gtk_builder_get_widget (state->gui,
334 						     "cancelbutton");
335 	if (close_function == NULL)
336 		g_signal_connect (G_OBJECT (state->cancel_button),
337 				  "clicked",
338 				  G_CALLBACK (cb_tool_cancel_clicked), state);
339 	else
340 		g_signal_connect (G_OBJECT (state->cancel_button),
341 				  "clicked",
342 				  G_CALLBACK (close_function), state);
343 
344 	state->apply_button = go_gtk_builder_get_widget (state->gui, "applybutton");
345 	if (state->apply_button != NULL )
346 		g_signal_connect (G_OBJECT (state->apply_button),
347 				  "clicked",
348 				  G_CALLBACK (ok_function), state);
349 	state->help_button = go_gtk_builder_get_widget (state->gui, "helpbutton");
350 	if (state->help_button != NULL )
351 		gnm_init_help_button (state->help_button,
352 					   state->help_link);
353 }
354 
355 
356 /**
357  * dialog_tool_init: (skip)
358  * @state:
359  * @gui_name:
360  * @dialog_name:
361  * @ok_function:
362  * @sensitivity_cb:
363  *
364  * Create the dialog (guru).
365  *
366  **/
367 gboolean
dialog_tool_init(GnmGenericToolState * state,WBCGtk * wbcg,Sheet * sheet,char const * help_file,char const * gui_name,char const * dialog_name,char const * error_str,char const * key,GCallback ok_function,GCallback close_function,GCallback sensitivity_cb,GnmExprEntryFlags flags)368 dialog_tool_init (GnmGenericToolState *state,
369 		  WBCGtk *wbcg,
370 		  Sheet *sheet,
371 		  char const *help_file,
372 		  char const *gui_name,
373 		  char const *dialog_name,
374 		  char const *error_str,
375 		  char const *key,
376 		  GCallback ok_function,
377 		  GCallback close_function,
378 		  GCallback sensitivity_cb,
379 		  GnmExprEntryFlags flags)
380 {
381 	GtkGrid  *grid;
382 	GtkWidget *widget;
383 
384 	state->wbcg  = wbcg;
385 	state->wb    = wb_control_get_workbook (GNM_WBC (wbcg));
386 	state->sheet = sheet;
387 	state->sv    = wb_control_cur_sheet_view (GNM_WBC (wbcg));
388 	state->warning_dialog = NULL;
389 	state->help_link      = help_file;
390 	state->state_destroy = NULL;
391 
392 	state->gui = gnm_gtk_builder_load (gui_name, NULL, GO_CMD_CONTEXT (wbcg));
393         if (state->gui == NULL)
394 		goto dialog_tool_init_error;
395 
396 	state->dialog = go_gtk_builder_get_widget (state->gui, dialog_name);
397         if (state->dialog == NULL)
398 		goto dialog_tool_init_error;
399 
400 
401 	dialog_tool_init_buttons (state, ok_function, close_function);
402 
403 	widget = go_gtk_builder_get_widget (state->gui, "var1-label");
404 	if (widget == NULL) {
405 		state->input_entry = NULL;
406 	} else {
407 		guint left_attach, top_attach, width, height;
408 
409 		grid = GTK_GRID (gtk_widget_get_parent (widget));
410 		state->input_entry = gnm_expr_entry_new (state->wbcg, TRUE);
411 		g_object_set (G_OBJECT (state->input_entry), "hexpand", TRUE, NULL);
412 		gnm_expr_entry_disable_tips (state->input_entry);
413 		gnm_expr_entry_set_flags (state->input_entry,
414 					  flags | GNM_EE_FORCE_ABS_REF,
415 					  GNM_EE_MASK);
416 
417 		gtk_container_child_get (GTK_CONTAINER (grid), widget,
418 					 "left-attach", &left_attach,
419 					 "top-attach", &top_attach,
420 		                         "width", &width,
421 		                         "height", &height,
422 					 NULL);
423 
424 		gtk_grid_attach (grid, GTK_WIDGET (state->input_entry),
425 				  left_attach + width, top_attach,
426 				  1, height);
427 		g_signal_connect_after (G_OBJECT (state->input_entry),
428 					"changed",
429 					G_CALLBACK (sensitivity_cb), state);
430 		gnm_editable_enters (GTK_WINDOW (state->dialog),
431 					  GTK_WIDGET (state->input_entry));
432 		gtk_label_set_mnemonic_widget (GTK_LABEL (widget),
433 					       GTK_WIDGET (state->input_entry));
434 		go_atk_setup_label (widget, GTK_WIDGET (state->input_entry));
435 		gtk_widget_show (GTK_WIDGET (state->input_entry));
436 	}
437 
438 
439 /*                                                        */
440 /* If there is a var2-label, we need a second input field */
441 /*                                                        */
442 	widget = go_gtk_builder_get_widget (state->gui, "var2-label");
443 	if (widget == NULL) {
444 		state->input_entry_2 = NULL;
445 	} else {
446 		guint left_attach, top_attach, width, height;
447 
448 		state->input_entry_2 = gnm_expr_entry_new (state->wbcg, TRUE);
449 		g_object_set (G_OBJECT (state->input_entry_2), "hexpand", TRUE, NULL);
450 		gnm_expr_entry_disable_tips (state->input_entry_2);
451 		gnm_expr_entry_set_flags (state->input_entry_2,
452 					  GNM_EE_SINGLE_RANGE | GNM_EE_FORCE_ABS_REF, GNM_EE_MASK);
453 		grid = GTK_GRID (gtk_widget_get_parent (widget));
454 
455 		gtk_container_child_get (GTK_CONTAINER (grid), widget,
456 					 "left-attach", &left_attach,
457 					 "top-attach", &top_attach,
458 		                         "width", &width,
459 		                         "height", &height,
460 					 NULL);
461 
462 		gtk_grid_attach (grid, GTK_WIDGET (state->input_entry_2),
463 				  left_attach + width, top_attach,
464 				  1, height);
465 		g_signal_connect_after (G_OBJECT (state->input_entry_2),
466 					"changed",
467 					G_CALLBACK (sensitivity_cb), state);
468 		gnm_editable_enters (GTK_WINDOW (state->dialog),
469 					  GTK_WIDGET (state->input_entry_2));
470 		gtk_label_set_mnemonic_widget (GTK_LABEL (widget),
471 					       GTK_WIDGET (state->input_entry_2));
472 		go_atk_setup_label (widget, GTK_WIDGET (state->input_entry_2));
473 		gtk_widget_show (GTK_WIDGET (state->input_entry_2));
474 	}
475 
476 	state->warning = go_gtk_builder_get_widget (state->gui, "warnings");
477 	wbc_gtk_attach_guru (state->wbcg, state->dialog);
478 	g_object_set_data_full (G_OBJECT (state->dialog),
479 		"state", state, (GDestroyNotify) cb_tool_destroy);
480 
481 	dialog_tool_init_outputs (state, sensitivity_cb);
482 
483 	gnm_keyed_dialog (wbcg, GTK_WINDOW (state->dialog), key);
484 
485 	gnm_dialog_setup_destroy_handlers (GTK_DIALOG (state->dialog),
486 					   state->wbcg,
487 					   GNM_DIALOG_DESTROY_SHEET_REMOVED |
488 					   GNM_DIALOG_DESTROY_SHEET_RENAMED);
489 
490 	return FALSE;
491 
492  dialog_tool_init_error:
493 	go_gtk_notice_dialog (wbcg_toplevel (wbcg),
494 			      GTK_MESSAGE_ERROR,
495 			      "%s", error_str);
496 	g_free (state);
497 	return TRUE;
498 }
499 
500 /**
501  * tool_load_selection:
502  * @state:
503  *
504  * load the current selection in the output and input entries
505  * show the dialog and focus the input_entry
506  *
507  **/
508 void
tool_load_selection(GnmGenericToolState * state,gboolean allow_multiple)509 tool_load_selection (GnmGenericToolState *state, gboolean allow_multiple)
510 {
511 	GnmRange const *first = selection_first_range (state->sv, NULL, NULL);
512 
513 	if (first != NULL) {
514 		if (allow_multiple) {
515 			char *text = selection_to_string (state->sv, TRUE);
516 			gnm_expr_entry_load_from_text  (state->input_entry,
517 							text);
518 			g_free (text);
519 		} else
520 			gnm_expr_entry_load_from_range (state->input_entry,
521 				state->sheet, first);
522 		if (state->gdao != NULL)
523 			gnm_dao_load_range (GNM_DAO (state->gdao), first);
524 	}
525 
526 	gtk_widget_show (state->dialog);
527 	gnm_expr_entry_grab_focus (GNM_EXPR_ENTRY (state->input_entry),
528 				   TRUE);
529 
530 }
531 
532 /**
533  * tool_setup_update: (skip)
534  */
535 GtkWidget *
tool_setup_update(GnmGenericToolState * state,char const * name,GCallback cb,gpointer closure)536 tool_setup_update (GnmGenericToolState* state, char const *name, GCallback cb,
537 		   gpointer closure)
538 {
539 	GtkWidget *w = go_gtk_builder_get_widget (state->gui, name);
540 	if (GTK_IS_SPIN_BUTTON (w)) {
541 		g_signal_connect_after (w, "value-changed", cb, closure);
542 		gnm_editable_enters (GTK_WINDOW (state->dialog), w);
543 	} else if (GTK_IS_ENTRY (w)) {
544 		g_signal_connect_after (w, "changed", cb, closure);
545 		gnm_editable_enters (GTK_WINDOW (state->dialog), w);
546 	} else if (GTK_IS_TOGGLE_BUTTON (w))
547 		g_signal_connect_after (w, "toggled", cb, closure);
548 	else
549 		g_warning ("tool_setup_update called with unknown type");
550 	return w;
551 }
552 
553 
554 
555 
556 /**********************************************/
557 /*  Generic functions for the analysis tools  */
558 /*  Functions in this section are being used  */
559 /*  some tools                                */
560 /**********************************************/
561 
562 /**
563  * tool_update_sensitivity_cb:
564  * @dummy:
565  * @state:
566  *
567  * Update the dialog widgets sensitivity if the only items of interest
568  * are one or two standard input and one output item, permitting multiple
569  * areas as first input.
570  *
571  * used by:
572  * Correlation
573  * Covariance
574  * RankPercentile
575  * FourierAnalysis
576  *
577  **/
578 static void
tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,GnmGenericToolState * state)579 tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
580 			    GnmGenericToolState *state)
581 {
582         GSList *input_range;
583 
584 	/* Checking Input Range */
585         input_range = gnm_expr_entry_parse_as_list (
586 		GNM_EXPR_ENTRY (state->input_entry), state->sheet);
587 	if (input_range == NULL) {
588 		gtk_label_set_text (GTK_LABEL (state->warning),
589 				    _("The input range is invalid."));
590 		gtk_widget_set_sensitive (state->ok_button, FALSE);
591 		return;
592 	} else
593 		range_list_destroy (input_range);
594 
595 	/* Checking Output Page */
596 	if (!gnm_dao_is_ready (GNM_DAO (state->gdao))) {
597 		gtk_label_set_text (GTK_LABEL (state->warning),
598 				    _("The output specification "
599 				      "is invalid."));
600 		gtk_widget_set_sensitive (state->ok_button, FALSE);
601 		return;
602 	}
603 
604 	gtk_label_set_text (GTK_LABEL (state->warning), "");
605 	gtk_widget_set_sensitive (state->ok_button, TRUE);
606 
607 	return;
608 }
609 
610 /**********************************************/
611 /*  Begin of correlation tool code */
612 /**********************************************/
613 
614 
615 /**
616  * corr_tool_ok_clicked_cb:
617  * @button:
618  * @state:
619  *
620  * Retrieve the information from the dialog and call the correlation_tool.
621  * Note that we assume that the ok_button is only active if the entry fields
622  * contain sensible data.
623  **/
624 static void
corr_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,GnmGenericToolState * state)625 corr_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
626 			 GnmGenericToolState *state)
627 {
628 	data_analysis_output_t  *dao;
629 	analysis_tools_data_generic_t  *data;
630 
631         char   *text;
632 	GtkWidget *w;
633 
634 	if (state->warning_dialog != NULL)
635 		gtk_widget_destroy (state->warning_dialog);
636 
637 	data = g_new0 (analysis_tools_data_generic_t, 1);
638 	dao  = parse_output (state, NULL);
639 
640 	data->input = gnm_expr_entry_parse_as_list (
641 		GNM_EXPR_ENTRY (state->input_entry), state->sheet);
642 	data->group_by = gnm_gui_group_value (state->gui, grouped_by_group);
643 
644 	w = go_gtk_builder_get_widget (state->gui, "labels_button");
645         data->labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
646 
647 	if (cmd_analysis_tool (GNM_WBC (state->wbcg), state->sheet,
648 			       dao, data, analysis_tool_correlation_engine, FALSE)) {
649 
650 		switch (data->err - 1) {
651 		case GROUPED_BY_ROW:
652 			error_in_entry ((GnmGenericToolState *) state,
653 					GTK_WIDGET (state->input_entry),
654 					_("The selected input rows must have equal size!"));
655 			break;
656 		case GROUPED_BY_COL:
657 			error_in_entry ((GnmGenericToolState *) state,
658 					GTK_WIDGET (state->input_entry),
659 					_("The selected input columns must have equal size!"));
660 			break;
661 		case GROUPED_BY_AREA:
662 			error_in_entry ((GnmGenericToolState *) state,
663 					GTK_WIDGET (state->input_entry),
664 					_("The selected input areas must have equal size!"));
665 			break;
666 		default:
667 			text = g_strdup_printf (
668 				_("An unexpected error has occurred: %d."), data->err);
669 			error_in_entry ((GnmGenericToolState *) state,
670 					GTK_WIDGET (state->input_entry), text);
671 			g_free (text);
672 			break;
673 		}
674 		range_list_destroy (data->input);
675 		g_free (dao);
676 		g_free (data);
677 	} else
678 		gtk_widget_destroy (state->dialog);
679 	return;
680 }
681 
682 
683 
684 /**
685  * dialog_correlation_tool:
686  * @wbcg:
687  * @sheet:
688  *
689  * Show the dialog (guru).
690  *
691  **/
692 int
dialog_correlation_tool(WBCGtk * wbcg,Sheet * sheet)693 dialog_correlation_tool (WBCGtk *wbcg, Sheet *sheet)
694 {
695         GnmGenericToolState *state;
696 	char const * plugins[] = { "Gnumeric_fnstat",
697 				   NULL};
698 
699 	if ((wbcg == NULL) ||
700 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
701 		return 1;
702 
703 	/* Only pop up one copy per workbook */
704 	if (gnm_dialog_raise_if_exists (wbcg, CORRELATION_KEY))
705 		return 0;
706 
707 	state = g_new0 (GnmGenericToolState, 1);
708 
709 	if (dialog_tool_init (state, wbcg, sheet,
710 			      GNUMERIC_HELP_LINK_CORRELATION,
711 			      "res:ui/correlation.ui", "Correlation",
712 			      _("Could not create the Correlation Tool dialog."),
713 			      CORRELATION_KEY,
714 			      G_CALLBACK (corr_tool_ok_clicked_cb), NULL,
715 			      G_CALLBACK (tool_update_sensitivity_cb),
716 			      0))
717 		return 0;
718 
719 	gnm_dao_set_put (GNM_DAO (state->gdao), TRUE, TRUE);
720 	tool_update_sensitivity_cb (NULL, state);
721 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
722 
723         return 0;
724 }
725 
726 /**********************************************/
727 /*  End of correlation tool code */
728 /**********************************************/
729 
730 /**********************************************/
731 /*  Begin of covariance tool code */
732 /**********************************************/
733 
734 
735 /**
736  * cov_tool_ok_clicked_cb:
737  * @button:
738  * @state:
739  *
740  * Retrieve the information from the dialog and call the covariance_tool.
741  * Note that we assume that the ok_button is only active if the entry fields
742  * contain sensible data.
743  **/
744 static void
cov_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,GnmGenericToolState * state)745 cov_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
746 			GnmGenericToolState *state)
747 {
748 	data_analysis_output_t  *dao;
749 	analysis_tools_data_generic_t  *data;
750 
751         char   *text;
752 	GtkWidget *w;
753 
754 	if (state->warning_dialog != NULL)
755 		gtk_widget_destroy (state->warning_dialog);
756 
757 	data = g_new0 (analysis_tools_data_generic_t, 1);
758 	dao  = parse_output (state, NULL);
759 
760 	data->input = gnm_expr_entry_parse_as_list (
761 		GNM_EXPR_ENTRY (state->input_entry), state->sheet);
762 	data->group_by = gnm_gui_group_value (state->gui, grouped_by_group);
763 
764 	w = go_gtk_builder_get_widget (state->gui, "labels_button");
765         data->labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
766 
767 	if (cmd_analysis_tool (GNM_WBC (state->wbcg), state->sheet,
768 			       dao, data, analysis_tool_covariance_engine, FALSE)) {
769 
770 		switch (data->err - 1) {
771 		case GROUPED_BY_ROW:
772 			error_in_entry ((GnmGenericToolState *) state,
773 					GTK_WIDGET (state->input_entry),
774 					_("The selected input rows must have equal size!"));
775 			break;
776 		case GROUPED_BY_COL:
777 			error_in_entry ((GnmGenericToolState *) state,
778 					GTK_WIDGET (state->input_entry),
779 					_("The selected input columns must have equal size!"));
780 			break;
781 		case GROUPED_BY_AREA:
782 			error_in_entry ((GnmGenericToolState *) state,
783 					GTK_WIDGET (state->input_entry),
784 					_("The selected input areas must have equal size!"));
785 			break;
786 		default:
787 			text = g_strdup_printf (
788 				_("An unexpected error has occurred: %d."), data->err);
789 			error_in_entry ((GnmGenericToolState *) state,
790 					GTK_WIDGET (state->input_entry), text);
791 			g_free (text);
792 			break;
793 		}
794 		range_list_destroy (data->input);
795 		g_free (dao);
796 		g_free (data);
797 	} else
798 		gtk_widget_destroy (state->dialog);
799 	return;
800 }
801 
802 
803 
804 /**
805  * dialog_covariance_tool:
806  * @wbcg:
807  * @sheet:
808  *
809  * Show the dialog (guru).
810  *
811  **/
812 int
dialog_covariance_tool(WBCGtk * wbcg,Sheet * sheet)813 dialog_covariance_tool (WBCGtk *wbcg, Sheet *sheet)
814 {
815         GnmGenericToolState *state;
816 	char const * plugins[] = { "Gnumeric_fnstat",
817 				   NULL};
818 
819 	if ((wbcg == NULL) ||
820 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
821 		return 1;
822 
823 	/* Only pop up one copy per workbook */
824 	if (gnm_dialog_raise_if_exists (wbcg, COVARIANCE_KEY))
825 		return 0;
826 
827 	state = g_new0 (GnmGenericToolState, 1);
828 
829 	if (dialog_tool_init (state, wbcg, sheet,
830 			      GNUMERIC_HELP_LINK_COVARIANCE,
831 			      "res:ui/covariance.ui", "Covariance",
832 			      _("Could not create the Covariance Tool dialog."),
833 			      COVARIANCE_KEY,
834 			      G_CALLBACK (cov_tool_ok_clicked_cb), NULL,
835 			      G_CALLBACK (tool_update_sensitivity_cb),
836 			      0))
837 		return 0;
838 
839 	gnm_dao_set_put (GNM_DAO (state->gdao), TRUE, TRUE);
840 	tool_update_sensitivity_cb (NULL, state);
841 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
842 
843         return 0;
844 }
845 
846 /**********************************************/
847 /*  End of covariance tool code */
848 /**********************************************/
849 
850 /**********************************************/
851 /*  Begin of rank and percentile tool code */
852 /**********************************************/
853 
854 
855 /**
856  * rank_tool_ok_clicked_cb:
857  * @button:
858  * @state:
859  *
860  * Retrieve the information from the dialog and call the ranking_tool.
861  * Note that we assume that the ok_button is only active if the entry fields
862  * contain sensible data.
863  **/
864 static void
rank_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,GnmGenericToolState * state)865 rank_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
866 			 GnmGenericToolState *state)
867 {
868 	data_analysis_output_t  *dao;
869 	analysis_tools_data_ranking_t  *data;
870 
871 	GtkWidget *w;
872 
873 	data = g_new0 (analysis_tools_data_ranking_t, 1);
874 	dao  = parse_output (state, NULL);
875 
876 	data->base.input = gnm_expr_entry_parse_as_list (
877 		GNM_EXPR_ENTRY (state->input_entry), state->sheet);
878 	data->base.group_by = gnm_gui_group_value (state->gui, grouped_by_group);
879 
880 	w = go_gtk_builder_get_widget (state->gui, "labels_button");
881         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
882 
883 	w = go_gtk_builder_get_widget (state->gui, "rank_button");
884         data->av_ties = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
885 
886 
887 	if (!cmd_analysis_tool (GNM_WBC (state->wbcg), state->sheet,
888 				dao, data, analysis_tool_ranking_engine, TRUE))
889 		gtk_widget_destroy (state->dialog);
890 	return;
891 }
892 
893 
894 
895 /**
896  * dialog_ranking_tool:
897  * @wbcg:
898  * @sheet:
899  *
900  * Show the dialog (guru).
901  *
902  **/
903 int
dialog_ranking_tool(WBCGtk * wbcg,Sheet * sheet)904 dialog_ranking_tool (WBCGtk *wbcg, Sheet *sheet)
905 {
906         GnmGenericToolState *state;
907 	char const * plugins[] = { "Gnumeric_fnstat",
908 				   "Gnumeric_fnlookup",
909 				   NULL};
910 
911 	if ((wbcg == NULL) ||
912 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
913 		return 1;
914 
915 	/* Only pop up one copy per workbook */
916 	if (gnm_dialog_raise_if_exists (wbcg, RANK_PERCENTILE_KEY))
917 		return 0;
918 
919 	state = g_new0 (GnmGenericToolState, 1);
920 
921 	if (dialog_tool_init (state, wbcg, sheet,
922 			      GNUMERIC_HELP_LINK_RANKING,
923 			      "res:ui/rank.ui", "RankPercentile",
924 			      _("Could not create the Rank and Percentile "
925 				"Tools dialog."),
926 			      RANK_PERCENTILE_KEY,
927 			      G_CALLBACK (rank_tool_ok_clicked_cb), NULL,
928 			      G_CALLBACK (tool_update_sensitivity_cb),
929 			      0))
930 		return 0;
931 
932 	gnm_dao_set_put (GNM_DAO (state->gdao), TRUE, TRUE);
933 	tool_update_sensitivity_cb (NULL, state);
934 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
935 
936         return 0;
937 }
938 
939 /**********************************************/
940 /*  End of rank and percentile tool code */
941 /**********************************************/
942 
943 /**********************************************/
944 /*  Begin of Fourier analysis tool code */
945 /**********************************************/
946 
947 /**
948  * fourier_tool_ok_clicked_cb:
949  * @button:
950  * @state:
951  *
952  * Retrieve the information from the dialog and call the fourier_tool.
953  * Note that we assume that the ok_button is only active if the entry fields
954  * contain sensible data.
955  **/
956 static void
fourier_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,GnmGenericToolState * state)957 fourier_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
958 			    GnmGenericToolState *state)
959 {
960 	data_analysis_output_t  *dao;
961 	analysis_tools_data_fourier_t  *data;
962 
963 	GtkWidget               *w;
964 
965 	data = g_new0 (analysis_tools_data_fourier_t, 1);
966 	dao  = parse_output (state, NULL);
967 
968 	data->base.wbc = GNM_WBC (state->wbcg);
969 	data->base.input = gnm_expr_entry_parse_as_list (
970 		GNM_EXPR_ENTRY (state->input_entry), state->sheet);
971 	data->base.group_by = gnm_gui_group_value (state->gui, grouped_by_group);
972 
973 	w = go_gtk_builder_get_widget (state->gui, "labels_button");
974         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
975 
976 	w = go_gtk_builder_get_widget (state->gui, "inverse_button");
977 	data->inverse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)) != 0;
978 
979 	if (!cmd_analysis_tool (GNM_WBC (state->wbcg), state->sheet,
980 				dao, data, analysis_tool_fourier_engine, TRUE))
981 		gtk_widget_destroy (state->dialog);
982 
983 	return;
984 }
985 
986 
987 
988 /**
989  * dialog_fourier_tool:
990  * @wbcg:
991  * @sheet:
992  *
993  * Show the dialog (guru).
994  *
995  **/
996 int
dialog_fourier_tool(WBCGtk * wbcg,Sheet * sheet)997 dialog_fourier_tool (WBCGtk *wbcg, Sheet *sheet)
998 {
999         GnmGenericToolState *state;
1000 	char const * plugins[] = { "Gnumeric_fnTimeSeriesAnalysis",
1001 				   "Gnumeric_fncomplex",
1002 				   NULL};
1003 
1004 	if ((wbcg == NULL) ||
1005 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
1006 		return 1;
1007 
1008 	/* Only pop up one copy per workbook */
1009 	if (gnm_dialog_raise_if_exists (wbcg, FOURIER_KEY))
1010 		return 0;
1011 
1012 	state = g_new0 (GnmGenericToolState, 1);
1013 
1014 	if (dialog_tool_init (state, wbcg, sheet,
1015 			      GNUMERIC_HELP_LINK_FOURIER_ANALYSIS,
1016 			      "res:ui/fourier-analysis.ui", "FourierAnalysis",
1017 			      _("Could not create the Fourier Analysis Tool "
1018 				"dialog."),
1019 			      FOURIER_KEY,
1020 			      G_CALLBACK (fourier_tool_ok_clicked_cb), NULL,
1021 			      G_CALLBACK (tool_update_sensitivity_cb),
1022 			      0))
1023 		return 0;
1024 
1025 	gnm_dao_set_put (GNM_DAO (state->gdao), TRUE, TRUE);
1026 	tool_update_sensitivity_cb (NULL, state);
1027 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
1028 
1029         return 0;
1030 }
1031 
1032 /**********************************************/
1033 /*  End of Fourier analysis tool code */
1034 /**********************************************/
1035 
1036 /**********************************************/
1037 /*  Begin of descriptive statistics tool code */
1038 /**********************************************/
1039 
1040 /**
1041  * cb_desc_stat_tool_ok_clicked:
1042  * @button:
1043  * @state:
1044  *
1045  * Retrieve the information from the dialog and call the descriptive_stat_tool.
1046  * Note that we assume that the ok_button is only active if the entry fields
1047  * contain sensible data.
1048  **/
1049 static void
cb_desc_stat_tool_ok_clicked(G_GNUC_UNUSED GtkWidget * button,DescriptiveStatState * state)1050 cb_desc_stat_tool_ok_clicked (G_GNUC_UNUSED GtkWidget *button,
1051 			      DescriptiveStatState *state)
1052 {
1053 	data_analysis_output_t  *dao;
1054 	analysis_tools_data_descriptive_t  *data;
1055 
1056 	GtkWidget *w;
1057 
1058 	data = g_new0 (analysis_tools_data_descriptive_t, 1);
1059 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
1060 
1061 	data->base.input = gnm_expr_entry_parse_as_list (
1062 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1063 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
1064 
1065 	data->summary_statistics = gtk_toggle_button_get_active (
1066 		GTK_TOGGLE_BUTTON (state->summary_stats_button));
1067 	data->confidence_level = gtk_toggle_button_get_active (
1068 		GTK_TOGGLE_BUTTON (state->mean_stats_button));
1069 	data->kth_largest = gtk_toggle_button_get_active (
1070 		GTK_TOGGLE_BUTTON (state->kth_largest_button));
1071 	data->kth_smallest = gtk_toggle_button_get_active (
1072 		GTK_TOGGLE_BUTTON (state->kth_smallest_button));
1073 	data->use_ssmedian = gtk_toggle_button_get_active (
1074 		GTK_TOGGLE_BUTTON (state->ss_button));
1075 
1076 	if (data->confidence_level == 1)
1077 		data->c_level = gtk_spin_button_get_value
1078 			(GTK_SPIN_BUTTON (state->c_entry));
1079 
1080 	if (data->kth_largest == 1)
1081 		entry_to_int (GTK_ENTRY (state->l_entry), &data->k_largest, TRUE);
1082 	if (data->kth_smallest == 1)
1083 		entry_to_int (GTK_ENTRY (state->s_entry), &data->k_smallest, TRUE);
1084 
1085 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
1086         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
1087 
1088 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1089 				dao, data, analysis_tool_descriptive_engine, TRUE))
1090 		gtk_widget_destroy (state->base.dialog);
1091 	return;
1092 }
1093 
1094 /**
1095  * desc_stat_tool_update_sensitivity_cb:
1096  * @state:
1097  *
1098  * Update the dialog widgets sensitivity.
1099  * We cannot use tool_update_sensitivity_cb
1100  * since we are also considering whether in fact
1101  * a statistic is selected.
1102  **/
1103 static void
desc_stat_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,DescriptiveStatState * state)1104 desc_stat_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
1105 				      DescriptiveStatState *state)
1106 {
1107 	gboolean stats_button, ci_button, largest_button, smallest_button;
1108         GSList *input_range;
1109 
1110 	/* Part 1: set the buttons on the statistics page. */
1111 
1112 	stats_button = gtk_toggle_button_get_active
1113 		(GTK_TOGGLE_BUTTON (state->summary_stats_button));
1114 	gtk_widget_set_sensitive (state->ss_button, stats_button);
1115 
1116 	ci_button = gtk_toggle_button_get_active
1117 		(GTK_TOGGLE_BUTTON (state->mean_stats_button));
1118 	gtk_widget_set_sensitive (state->c_entry, ci_button);
1119 
1120 	largest_button = gtk_toggle_button_get_active
1121 		(GTK_TOGGLE_BUTTON (state->kth_largest_button));
1122 	gtk_widget_set_sensitive (state->l_entry, largest_button);
1123 
1124 	smallest_button = gtk_toggle_button_get_active
1125 		(GTK_TOGGLE_BUTTON (state->kth_smallest_button));
1126 	gtk_widget_set_sensitive (state->s_entry, smallest_button);
1127 
1128 	/* Part 2: set the okay button */
1129 
1130 	/* Checking Input Page */
1131         input_range = gnm_expr_entry_parse_as_list (
1132 		GNM_EXPR_ENTRY (state->base.input_entry),
1133 		state->base.sheet);
1134 	if (input_range == NULL) {
1135 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1136 				    _("The input range is invalid."));
1137 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1138 		return;
1139 	} else
1140 		range_list_destroy (input_range);
1141 
1142 	/* Checking Statistics Page */
1143 	if (!(stats_button || ci_button || largest_button || smallest_button)) {
1144 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1145 				    _("No statistics are selected."));
1146 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1147 		return;
1148 	}
1149 
1150 	if (ci_button) {
1151 		gdouble c_level = gtk_spin_button_get_value
1152 			(GTK_SPIN_BUTTON (state->c_entry));
1153 		if (!(c_level > 0 && c_level <1)) {
1154 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1155 					    _("The confidence level should be "
1156 					      "between 0 and 1."));
1157 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1158 			return;
1159 		}
1160 	}
1161 
1162 	if (largest_button) {
1163 		int k;
1164 		if ((0 != entry_to_int (GTK_ENTRY (state->l_entry), &k, FALSE))
1165 		    || !(k >0)) {
1166 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1167 					    _("K must be a positive integer."));
1168 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1169 		return;
1170 		}
1171 	}
1172 
1173 	if (smallest_button) {
1174 		int k;
1175 		if ((0 != entry_to_int (GTK_ENTRY (state->s_entry), &k, FALSE))
1176 		    || !(k >0)) {
1177 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1178 					    _("K must be a positive integer."));
1179 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1180 		return;
1181 		}
1182 	}
1183 
1184 	/* Checking Output Page */
1185 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
1186 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1187 				    _("The output specification "
1188 				      "is invalid."));
1189 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1190 		return;
1191 	}
1192 
1193 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
1194 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
1195 
1196 	return;
1197 }
1198 
1199 
1200 /**
1201  * dialog_descriptive_stat_tool:
1202  * @wbcg:
1203  * @sheet:
1204  *
1205  * Show the dialog (guru).
1206  *
1207  **/
1208 int
dialog_descriptive_stat_tool(WBCGtk * wbcg,Sheet * sheet)1209 dialog_descriptive_stat_tool (WBCGtk *wbcg, Sheet *sheet)
1210 {
1211         DescriptiveStatState *state;
1212 	char const * plugins[] = {"Gnumeric_fnstat",
1213 				  "Gnumeric_fnmath",
1214 				  NULL};
1215 
1216 	if ((wbcg == NULL) ||
1217 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
1218 		return 1;
1219 
1220 	/* Only pop up one copy per workbook */
1221 	if (gnm_dialog_raise_if_exists (wbcg, DESCRIPTIVE_STATS_KEY))
1222 		return 0;
1223 
1224 	state = g_new0 (DescriptiveStatState, 1);
1225 
1226 	if (dialog_tool_init (&state->base, wbcg, sheet,
1227 			      GNUMERIC_HELP_LINK_DESCRIPTIVE_STATS,
1228 			      "res:ui/descriptive-stats.ui", "DescStats",
1229 			      _("Could not create the Descriptive Statistics "
1230 				"Tool dialog."),
1231 			      DESCRIPTIVE_STATS_KEY,
1232 			      G_CALLBACK (cb_desc_stat_tool_ok_clicked), NULL,
1233 			      G_CALLBACK (desc_stat_tool_update_sensitivity_cb),
1234 			      0))
1235 	{
1236 		g_free(state);
1237 		return 0;
1238 	}
1239 
1240 	state->summary_stats_button  = go_gtk_builder_get_widget
1241 		(state->base.gui, "summary_stats_button");
1242 	state->ss_button  = go_gtk_builder_get_widget
1243 		(state->base.gui, "ss_button");
1244 	state->mean_stats_button  = go_gtk_builder_get_widget
1245 		(state->base.gui, "mean_stats_button");
1246 	state->kth_largest_button  = go_gtk_builder_get_widget
1247 		(state->base.gui, "kth_largest_button");
1248 	state->kth_smallest_button  = go_gtk_builder_get_widget
1249 		(state->base.gui, "kth_smallest_button");
1250 	state->c_entry  = go_gtk_builder_get_widget (state->base.gui, "c_entry");
1251 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->c_entry), 0.95);
1252 	state->l_entry  = go_gtk_builder_get_widget (state->base.gui, "l_entry");
1253 	int_to_entry (GTK_ENTRY (state->l_entry), 1);
1254 	state->s_entry  = go_gtk_builder_get_widget (state->base.gui, "s_entry");
1255 	int_to_entry (GTK_ENTRY (state->s_entry), 1);
1256 
1257 
1258 	g_signal_connect_after (G_OBJECT (state->summary_stats_button),
1259 		"toggled",
1260 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1261 	g_signal_connect_after (G_OBJECT (state->mean_stats_button),
1262 		"toggled",
1263 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1264 	g_signal_connect_after (G_OBJECT (state->kth_largest_button),
1265 		"toggled",
1266 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1267 	g_signal_connect_after (G_OBJECT (state->kth_smallest_button),
1268 		"toggled",
1269 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1270 	g_signal_connect_after (G_OBJECT (state->c_entry),
1271 		"changed",
1272 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1273 	g_signal_connect_after (G_OBJECT (state->l_entry),
1274 		"changed",
1275 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1276 	g_signal_connect_after (G_OBJECT (state->s_entry),
1277 		"changed",
1278 		G_CALLBACK (desc_stat_tool_update_sensitivity_cb), state);
1279 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1280 				  GTK_WIDGET (state->c_entry));
1281 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1282 				  GTK_WIDGET (state->l_entry));
1283 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1284 				  GTK_WIDGET (state->s_entry));
1285 
1286 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
1287 	desc_stat_tool_update_sensitivity_cb (NULL, state);
1288 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
1289 
1290         return 0;
1291 }
1292 
1293 
1294 /**********************************************/
1295 /*  End of descriptive statistics tool code */
1296 /**********************************************/
1297 
1298 
1299 /**********************************************/
1300 /*  Begin of ttest tool code */
1301 /**********************************************/
1302 
1303 /**
1304  * ttest_tool_ok_clicked_cb:
1305  * @button:
1306  * @state:
1307  *
1308  * Retrieve the information from the dialog and call the appropriate tool.
1309  * Note that we assume that the ok_button is only active if the entry fields
1310  * contain sensible data.
1311  **/
1312 static void
ttest_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,TTestState * state)1313 ttest_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
1314 			  TTestState *state)
1315 {
1316 	data_analysis_output_t  *dao;
1317 	analysis_tools_data_ttests_t  *data;
1318 
1319 	GtkWidget *w;
1320 	int    err = 0;
1321 
1322 	data = g_new0 (analysis_tools_data_ttests_t, 1);
1323 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
1324 
1325 	data->base.wbc = GNM_WBC (state->base.wbcg);
1326 
1327 	if (state->base.warning_dialog != NULL)
1328 		gtk_widget_destroy (state->base.warning_dialog);
1329 
1330 	data->base.range_1 = gnm_expr_entry_parse_as_value
1331 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1332 
1333 	data->base.range_2 = gnm_expr_entry_parse_as_value
1334 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
1335 
1336 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
1337         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
1338 
1339 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->paired_button)) == 1) {
1340 		state->invocation = TTEST_PAIRED;
1341 	} else {
1342 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->known_button)) == 1) {
1343 			state->invocation = TTEST_ZTEST;
1344 		} else {
1345 			if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
1346 							  (state->equal_button)) == 1) {
1347 				state->invocation = TTEST_UNPAIRED_EQUALVARIANCES;
1348 			} else {
1349 				state->invocation = TTEST_UNPAIRED_UNEQUALVARIANCES;
1350 			}
1351 		}
1352 	}
1353 
1354 	err = entry_to_float (GTK_ENTRY (state->mean_diff_entry), &data->mean_diff, TRUE);
1355 	err = entry_to_float (GTK_ENTRY (state->alpha_entry), &data->base.alpha, TRUE);
1356 
1357 	switch (state->invocation) {
1358 	case TTEST_PAIRED:
1359 		if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg),
1360 					state->base.sheet,
1361 					dao, data, analysis_tool_ttest_paired_engine,
1362 					TRUE))
1363 			gtk_widget_destroy (state->base.dialog);
1364 		break;
1365 	case TTEST_UNPAIRED_EQUALVARIANCES:
1366 		if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1367 					dao, data, analysis_tool_ttest_eqvar_engine, TRUE))
1368 			gtk_widget_destroy (state->base.dialog);
1369 		break;
1370 	case TTEST_UNPAIRED_UNEQUALVARIANCES:
1371 		if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1372 					dao, data, analysis_tool_ttest_neqvar_engine, TRUE))
1373 			gtk_widget_destroy (state->base.dialog);
1374 		break;
1375 	case TTEST_ZTEST:
1376 		err = entry_to_float (GTK_ENTRY (state->var1_variance), &data->var1, TRUE);
1377 		if (err != 0 || data->var1 <= 0.0) {
1378 			error_in_entry ((GnmGenericToolState *) state, GTK_WIDGET (state->var1_variance),
1379 					_("Please enter a valid\n"
1380 					  "population variance for variable 1."));
1381 			g_free (data);
1382 			g_free (dao);
1383 			return;
1384 		}
1385 		err = entry_to_float (GTK_ENTRY (state->var2_variance), &data->var2, TRUE);
1386 		if (err != 0 || data->var2 <= 0.0) {
1387 			error_in_entry ((GnmGenericToolState *) state, GTK_WIDGET (state->var2_variance),
1388 					_("Please enter a valid\n"
1389 					  "population variance for variable 2."));
1390 			g_free (data);
1391 			g_free (dao);
1392 			return;
1393 		}
1394 
1395 		if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1396 					dao, data, analysis_tool_ztest_engine, TRUE))
1397 			gtk_widget_destroy (state->base.dialog);
1398 		break;
1399 	}
1400 
1401 	return;
1402 }
1403 
1404 /**
1405  * ttest_update_sensitivity_cb:
1406  * @dummy:
1407  * @state:
1408  *
1409  * Update the dialog widgets sensitivity if the only items of interest
1410  * are the standard input (one or two ranges) and output items.
1411  **/
1412 static void
ttest_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,TTestState * state)1413 ttest_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
1414 			     TTestState *state)
1415 {
1416 	gboolean ready  = FALSE;
1417 	gboolean input_1_ready  = FALSE;
1418 	gboolean input_2_ready  = FALSE;
1419 	gboolean output_ready  = FALSE;
1420 	gboolean mean_diff_ready = FALSE;
1421 	gboolean alpha_ready = FALSE;
1422 	int err;
1423 	gnm_float mean_diff, alpha;
1424         GnmValue *input_range;
1425         GnmValue *input_range_2;
1426 
1427         input_range = gnm_expr_entry_parse_as_value
1428 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1429 	input_range_2 = gnm_expr_entry_parse_as_value
1430 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
1431 
1432 	err = entry_to_float (GTK_ENTRY (state->mean_diff_entry), &mean_diff, FALSE);
1433 	mean_diff_ready = (err == 0);
1434 	err = entry_to_float (GTK_ENTRY (state->alpha_entry), &alpha, FALSE);
1435 	alpha_ready = (err == 0 && alpha > 0.0 && alpha < 1.0);
1436 	input_1_ready = (input_range != NULL);
1437 	input_2_ready = ((state->base.input_entry_2 == NULL) || (input_range_2 != NULL));
1438 	output_ready =  gnm_dao_is_ready (GNM_DAO (state->base.gdao));
1439 
1440         value_release (input_range);
1441 	value_release (input_range_2);
1442 
1443 	ready = input_1_ready && input_2_ready && output_ready && alpha_ready && mean_diff_ready;
1444 	gtk_widget_set_sensitive (state->base.ok_button, ready);
1445 
1446 	return;
1447 }
1448 
1449 /**
1450  * ttest_known_toggled_cb:
1451  * @button:
1452  * @state:
1453  *
1454  * The paired/unpaired variables status has changed.
1455  *
1456  **/
1457 static void
ttest_known_toggled_cb(GtkWidget * button,TTestState * state)1458 ttest_known_toggled_cb (GtkWidget *button, TTestState *state)
1459 {
1460 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) == 1) {
1461 		gtk_widget_hide (state->equal_button);
1462 		gtk_widget_hide (state->unequal_button);
1463 		gtk_widget_hide (state->varianceequal_label);
1464 		gtk_widget_show (state->var2_variance_label);
1465 		gtk_widget_show (state->var2_variance);
1466 		gtk_widget_show (state->var1_variance_label);
1467 		gtk_widget_show (state->var1_variance);
1468 	} else {
1469 		gtk_widget_hide (state->var2_variance_label);
1470 		gtk_widget_hide (state->var2_variance);
1471 		gtk_widget_hide (state->var1_variance_label);
1472 		gtk_widget_hide (state->var1_variance);
1473 		gtk_widget_show (state->equal_button);
1474 		gtk_widget_show (state->unequal_button);
1475 		gtk_widget_show (state->varianceequal_label);
1476 	}
1477 }
1478 /**
1479  * ttest_paired_toggled_cb:
1480  * @button:
1481  * @state:
1482  *
1483  * The paired/unpaired variables status has changed.
1484  *
1485  **/
1486 static void
ttest_paired_toggled_cb(GtkWidget * button,TTestState * state)1487 ttest_paired_toggled_cb (GtkWidget *button, TTestState *state)
1488 {
1489 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) == 1) {
1490 		gtk_widget_hide (state->var2_variance_label);
1491 		gtk_widget_hide (state->var2_variance);
1492 		gtk_widget_hide (state->var1_variance_label);
1493 		gtk_widget_hide (state->var1_variance);
1494 		gtk_widget_hide (state->equal_button);
1495 		gtk_widget_hide (state->unequal_button);
1496 		gtk_widget_hide (state->varianceequal_label);
1497 		gtk_widget_hide (state->known_button);
1498 		gtk_widget_hide (state->unknown_button);
1499 		gtk_widget_hide (state->varianceknown_label);
1500 	} else {
1501 		gtk_widget_show (state->known_button);
1502 		gtk_widget_show (state->unknown_button);
1503 		gtk_widget_show (state->varianceknown_label);
1504 		ttest_known_toggled_cb (GTK_WIDGET (state->known_button), state);
1505 	}
1506 }
1507 
1508 /**
1509  * dialog_ttest_adjust_to_invocation:
1510  * @state:
1511  *
1512  * Set the options to match the invocation.
1513  *
1514  **/
1515 static void
dialog_ttest_adjust_to_invocation(TTestState * state)1516 dialog_ttest_adjust_to_invocation (TTestState *state)
1517 {
1518 	switch (state->invocation) {
1519 	case TTEST_PAIRED:
1520 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->paired_button), TRUE);
1521 		break;
1522 	case TTEST_UNPAIRED_EQUALVARIANCES:
1523 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->equal_button), TRUE);
1524 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unknown_button), TRUE);
1525 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unpaired_button), TRUE);
1526 		break;
1527 	case TTEST_UNPAIRED_UNEQUALVARIANCES:
1528 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unequal_button), TRUE);
1529 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unknown_button), TRUE);
1530 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unpaired_button), TRUE);
1531 		break;
1532 	case TTEST_ZTEST:
1533 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->known_button), TRUE);
1534 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->unpaired_button), TRUE);
1535 		break;
1536 	default:
1537 		break;
1538 	}
1539 }
1540 
1541 
1542 /**
1543  * dialog_ttest_realized:
1544  * @widget
1545  * @state:
1546  *
1547  * Fix the size of the options table.
1548  *
1549  **/
1550 static void
dialog_ttest_realized(G_GNUC_UNUSED GtkWidget * widget,TTestState * state)1551 dialog_ttest_realized (G_GNUC_UNUSED GtkWidget *widget,
1552 		       TTestState *state)
1553 {
1554 	GtkAllocation alloc;
1555 
1556 	gtk_widget_get_allocation (state->options_grid, &alloc);
1557 	gtk_widget_set_size_request (state->options_grid,
1558 				     alloc.width, alloc.height);
1559 
1560 	gtk_widget_get_allocation (state->paired_button, &alloc);
1561 	gtk_widget_set_size_request (state->paired_button,
1562 				     alloc.width, alloc.height);
1563 
1564 	gtk_widget_get_allocation (state->unpaired_button, &alloc);
1565 	gtk_widget_set_size_request (state->unpaired_button,
1566 				     alloc.width, alloc.height);
1567 
1568 	gtk_widget_get_allocation (state->variablespaired_label, &alloc);
1569 	gtk_widget_set_size_request (state->variablespaired_label,
1570 				     alloc.width, alloc.height);
1571 
1572 	ttest_paired_toggled_cb (state->paired_button, state);
1573 	dialog_ttest_adjust_to_invocation (state);
1574 }
1575 
1576 /**
1577  * dialog_ttest_tool:
1578  * @wbcg:
1579  * @sheet:
1580  * @test:
1581  *
1582  * Show the dialog (guru).
1583  *
1584  **/
1585 int
dialog_ttest_tool(WBCGtk * wbcg,Sheet * sheet,ttest_type test)1586 dialog_ttest_tool (WBCGtk *wbcg, Sheet *sheet, ttest_type test)
1587 {
1588         TTestState *state;
1589 	GtkDialog *dialog;
1590 	char const * plugins[] = {"Gnumeric_fnstat",
1591 				  "Gnumeric_fnmath",
1592 				  "Gnumeric_fninfo",
1593 				  "Gnumeric_fnlogical",
1594 				  NULL};
1595 
1596 	if ((wbcg == NULL) ||
1597 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
1598 		return 1;
1599 
1600 	/* Only pop up one copy per workbook */
1601 	dialog = gnm_dialog_raise_if_exists (wbcg, TTEST_KEY);
1602 	if (dialog) {
1603 		state = g_object_get_data (G_OBJECT (dialog), "state");
1604                 state->invocation = test;
1605 		dialog_ttest_adjust_to_invocation (state);
1606 		return 0;
1607 	}
1608 
1609 	state = g_new0 (TTestState, 1);
1610 	state->invocation = test;
1611 
1612 	if (dialog_tool_init (&state->base, wbcg, sheet,
1613 			      GNUMERIC_HELP_LINK_MEAN_TESTS,
1614 			      "res:ui/mean-tests.ui", "MeanTests",
1615 			      _("Could not create the Mean Tests Tool dialog."),
1616 			      TTEST_KEY,
1617 			      G_CALLBACK (ttest_tool_ok_clicked_cb), NULL,
1618 			      G_CALLBACK (ttest_update_sensitivity_cb),
1619 			      GNM_EE_SINGLE_RANGE))
1620 	{
1621 		g_free(state);
1622 		return 0;
1623 	}
1624 
1625 	state->paired_button  = go_gtk_builder_get_widget (state->base.gui, "paired-button");
1626 	state->unpaired_button  = go_gtk_builder_get_widget (state->base.gui, "unpaired-button");
1627 	state->variablespaired_label = go_gtk_builder_get_widget (state->base.gui, "variablespaired-label");
1628 	state->known_button  = go_gtk_builder_get_widget (state->base.gui, "known-button");
1629 	state->unknown_button  = go_gtk_builder_get_widget (state->base.gui, "unknown-button");
1630 	state->varianceknown_label = go_gtk_builder_get_widget (state->base.gui, "varianceknown-label");
1631 	state->equal_button  = go_gtk_builder_get_widget (state->base.gui, "equal-button");
1632 	state->unequal_button  = go_gtk_builder_get_widget (state->base.gui, "unequal-button");
1633 	state->varianceequal_label = go_gtk_builder_get_widget (state->base.gui, "varianceequal-label");
1634 	state->options_grid = go_gtk_builder_get_widget (state->base.gui, "options-grid");
1635 	state->var1_variance_label = go_gtk_builder_get_widget (state->base.gui, "var1_variance-label");
1636 	state->var1_variance = go_gtk_builder_get_widget (state->base.gui, "var1-variance");
1637 	state->var2_variance_label = go_gtk_builder_get_widget (state->base.gui, "var2_variance-label");
1638 	state->var2_variance = go_gtk_builder_get_widget (state->base.gui, "var2-variance");
1639 	state->mean_diff_entry = go_gtk_builder_get_widget (state->base.gui, "meandiff");
1640 	float_to_entry (GTK_ENTRY (state->mean_diff_entry), 0);
1641 	state->alpha_entry = go_gtk_builder_get_widget (state->base.gui, "one_alpha");
1642 	float_to_entry (GTK_ENTRY (state->alpha_entry), 0.05);
1643 
1644 	g_signal_connect_after (G_OBJECT (state->paired_button),
1645 		"toggled",
1646 		G_CALLBACK (ttest_update_sensitivity_cb), state);
1647 	g_signal_connect (G_OBJECT (state->paired_button),
1648 		"toggled",
1649 		G_CALLBACK (ttest_paired_toggled_cb), state);
1650 	g_signal_connect_after (G_OBJECT (state->known_button),
1651 		"toggled",
1652 		G_CALLBACK (ttest_update_sensitivity_cb), state);
1653 	g_signal_connect_after (G_OBJECT (state->mean_diff_entry),
1654 		"changed",
1655 		G_CALLBACK (ttest_update_sensitivity_cb), state);
1656 	g_signal_connect_after (G_OBJECT (state->alpha_entry),
1657 		"changed",
1658 		G_CALLBACK (ttest_update_sensitivity_cb), state);
1659 	g_signal_connect (G_OBJECT (state->known_button),
1660 		"toggled",
1661 		G_CALLBACK (ttest_known_toggled_cb), state);
1662 	g_signal_connect (G_OBJECT (state->base.dialog),
1663 		"realize",
1664 		G_CALLBACK (dialog_ttest_realized), state);
1665 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1666 				  GTK_WIDGET (state->var1_variance));
1667 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1668 				  GTK_WIDGET (state->var2_variance));
1669 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1670 				  GTK_WIDGET (state->mean_diff_entry));
1671 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1672 				  GTK_WIDGET (state->alpha_entry));
1673 
1674 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
1675 	ttest_update_sensitivity_cb (NULL, state);
1676 	tool_load_selection ((GnmGenericToolState *)state, FALSE);
1677 
1678         return 0;
1679 }
1680 
1681 /**********************************************/
1682 /*  End of ttest tool code */
1683 /**********************************************/
1684 
1685 
1686 /**********************************************/
1687 /*  Begin of ftest tool code */
1688 /**********************************************/
1689 
1690 
1691 /**
1692  * ftest_tool_ok_clicked_cb:
1693  * @button:
1694  * @state:
1695  *
1696  * Retrieve the information from the dialog and call the correlation_tool.
1697  * Note that we assume that the ok_button is only active if the entry fields
1698  * contain sensible data.
1699  **/
1700 static void
ftest_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,FTestToolState * state)1701 ftest_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
1702 			  FTestToolState *state)
1703 {
1704 	data_analysis_output_t  *dao;
1705 	analysis_tools_data_generic_b_t  *data;
1706 
1707 	GtkWidget *w;
1708 
1709 	data = g_new0 (analysis_tools_data_generic_b_t, 1);
1710 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
1711 
1712 	data->wbc = GNM_WBC (state->base.wbcg);
1713 
1714 	if (state->base.warning_dialog != NULL)
1715 		gtk_widget_destroy (state->base.warning_dialog);
1716 
1717 	data->range_1 = gnm_expr_entry_parse_as_value
1718 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1719 
1720 	data->range_2 =  gnm_expr_entry_parse_as_value
1721 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
1722 
1723 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
1724         data->labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
1725 
1726 	entry_to_float (GTK_ENTRY (state->alpha_entry), &data->alpha, TRUE);
1727 
1728 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1729 				dao, data, analysis_tool_ftest_engine, TRUE))
1730 		gtk_widget_destroy (state->base.dialog);
1731 
1732 	return;
1733 }
1734 
1735 /**
1736  * ftest_update_sensitivity_cb:
1737  * @dummy:
1738  * @state:
1739  *
1740  * Update the dialog widgets sensitivity if the only items of interest
1741  * are the standard input (one or two ranges) and output items.
1742  **/
1743 static void
ftest_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,FTestToolState * state)1744 ftest_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
1745 			     FTestToolState *state)
1746 {
1747 	gboolean ready  = FALSE;
1748 	gboolean input_1_ready  = FALSE;
1749 	gboolean input_2_ready  = FALSE;
1750 	gboolean output_ready  = FALSE;
1751 	gboolean alpha_ready = FALSE;
1752 	int err;
1753 	gnm_float  alpha;
1754         GnmValue *input_range;
1755         GnmValue *input_range_2;
1756 
1757         input_range = gnm_expr_entry_parse_as_value
1758 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1759 	input_range_2 = gnm_expr_entry_parse_as_value
1760 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
1761 
1762 	err = entry_to_float (GTK_ENTRY (state->alpha_entry), &alpha, FALSE);
1763 	alpha_ready = (err == 0 && alpha > 0.0 && alpha < 1.0);
1764 	input_1_ready = (input_range != NULL);
1765 	input_2_ready = ((state->base.input_entry_2 == NULL) || (input_range_2 != NULL));
1766 	output_ready = gnm_dao_is_ready (GNM_DAO (state->base.gdao));
1767 
1768         value_release (input_range);
1769         value_release (input_range_2);
1770 
1771 	ready = input_1_ready && input_2_ready && output_ready && alpha_ready;
1772 	gtk_widget_set_sensitive (state->base.ok_button, ready);
1773 
1774 	return;
1775 }
1776 
1777 /**
1778  * dialog_ftest_tool:
1779  * @wbcg:
1780  * @sheet:
1781  *
1782  * Show the dialog (guru).
1783  *
1784  **/
1785 int
dialog_ftest_tool(WBCGtk * wbcg,Sheet * sheet)1786 dialog_ftest_tool (WBCGtk *wbcg, Sheet *sheet)
1787 {
1788         FTestToolState *state;
1789 	char const * plugins[] = { "Gnumeric_fnstat",
1790 				   NULL};
1791 
1792 	if ((wbcg == NULL) ||
1793 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
1794 		return 1;
1795 
1796 	/* Only pop up one copy per workbook */
1797 	if (gnm_dialog_raise_if_exists (wbcg, FTEST_KEY))
1798 		return 0;
1799 
1800 	state = g_new0 (FTestToolState, 1);
1801 
1802 	if (dialog_tool_init (&state->base, wbcg, sheet,
1803 			      GNUMERIC_HELP_LINK_F_TEST_TWO_SAMPLE,
1804 			      "res:ui/variance-tests.ui", "VarianceTests",
1805 			      _("Could not create the FTest Tool dialog."),
1806 			      FTEST_KEY,
1807 			      G_CALLBACK (ftest_tool_ok_clicked_cb), NULL,
1808 			      G_CALLBACK (ftest_update_sensitivity_cb),
1809 			      GNM_EE_SINGLE_RANGE))
1810 	{
1811 		g_free(state);
1812 		return 0;
1813 	}
1814 
1815 	state->alpha_entry = go_gtk_builder_get_widget (state->base.gui, "one_alpha");
1816 	float_to_entry (GTK_ENTRY (state->alpha_entry), 0.05);
1817 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
1818 				  GTK_WIDGET (state->alpha_entry));
1819 	g_signal_connect_after (G_OBJECT (state->alpha_entry),
1820 		"changed",
1821 		G_CALLBACK (ftest_update_sensitivity_cb), state);
1822 
1823 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
1824 	ftest_update_sensitivity_cb (NULL, state);
1825 	tool_load_selection ((GnmGenericToolState *)state, FALSE);
1826 
1827         return 0;
1828 }
1829 
1830 /**********************************************/
1831 /*  End of ftest tool code */
1832 /**********************************************/
1833 
1834 /**********************************************/
1835 /*  Begin of sampling tool code */
1836 /**********************************************/
1837 
1838 /**
1839  * sampling_tool_update_sensitivity:
1840  * @dummy:
1841  * @state:
1842  *
1843  * Update the dialog widgets sensitivity if the only items of interest
1844  * are the standard input (one range) and output items.
1845  **/
1846 static void
sampling_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,SamplingState * state)1847 sampling_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
1848 				     SamplingState *state)
1849 {
1850 	int periodic, size, number, err;
1851         GSList *input_range;
1852 
1853         input_range = gnm_expr_entry_parse_as_list (
1854 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1855 
1856 	if (input_range == NULL) {
1857 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1858 				    _("The input range is invalid."));
1859 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1860 		return;
1861 	} else
1862 		range_list_destroy (input_range);
1863 
1864 	err = entry_to_int (GTK_ENTRY (state->number_entry), &number, FALSE);
1865 
1866 	if (err != 0 || number < 1) {
1867 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1868 				    _("The requested number of samples is invalid."));
1869 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1870 		return;
1871 	}
1872 
1873         periodic = gtk_toggle_button_get_active
1874 		(GTK_TOGGLE_BUTTON (state->periodic_button));
1875 
1876 	if (periodic) {
1877 		err = entry_to_int
1878 			(GTK_ENTRY (state->period_entry), &size, FALSE);
1879 		if (err != 0 || size < 1) {
1880 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1881 					    _("The requested period is invalid."));
1882 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1883 			return;
1884 		}
1885 		err = entry_to_int
1886 			(GTK_ENTRY (state->offset_entry), &number, FALSE);
1887 		if (err != 0 || number < 0) {
1888 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1889 					    _("The requested offset is invalid."));
1890 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1891 			return;
1892 		}
1893 	} else {
1894 		err = entry_to_int
1895 			(GTK_ENTRY (state->random_entry), &size, FALSE);
1896 		if (err != 0 || size < 1) {
1897 			gtk_label_set_text (GTK_LABEL (state->base.warning),
1898 					    _("The requested sample size is invalid."));
1899 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1900 			return;
1901 		}
1902 	}
1903 
1904        if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
1905 		gtk_label_set_text (GTK_LABEL (state->base.warning),
1906 				    _("The output specification "
1907 				      "is invalid."));
1908 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
1909 		return;
1910 	}
1911 
1912        gtk_label_set_text (GTK_LABEL (state->base.warning), "");
1913        gtk_widget_set_sensitive (state->base.ok_button, TRUE);
1914 }
1915 
1916 /**
1917  * sampling_tool_ok_clicked_cb:
1918  * @button:
1919  * @state:
1920  *
1921  * Retrieve the information from the dialog and call the appropriate tool.
1922  * Note that we assume that the ok_button is only active if the entry fields
1923  * contain sensible data.
1924  **/
1925 static void
sampling_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,SamplingState * state)1926 sampling_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
1927 			     SamplingState *state)
1928 {
1929 	data_analysis_output_t  *dao;
1930 	analysis_tools_data_sampling_t  *data;
1931 
1932 	GtkWidget *w;
1933 
1934 	data = g_new0 (analysis_tools_data_sampling_t, 1);
1935 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
1936 
1937 	data->base.wbc = GNM_WBC (state->base.wbcg);
1938 
1939 	data->base.input = gnm_expr_entry_parse_as_list (
1940 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
1941 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
1942 
1943 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
1944         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
1945 
1946         data->periodic = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->periodic_button));
1947 
1948 	if (data->periodic) {
1949 		entry_to_int (GTK_ENTRY (state->period_entry), &data->period, TRUE);
1950 		entry_to_int (GTK_ENTRY (state->offset_entry), &data->offset, TRUE);
1951 		data->row_major = gtk_toggle_button_get_active
1952 			(GTK_TOGGLE_BUTTON (state->row_major_button));
1953 	} else
1954 		entry_to_int (GTK_ENTRY (state->random_entry), &data->size, TRUE);
1955 
1956 	entry_to_int (GTK_ENTRY (state->number_entry), &data->number, TRUE);
1957 
1958 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
1959 				dao, data, analysis_tool_sampling_engine, TRUE))
1960 		gtk_widget_destroy (state->base.dialog);
1961 	return;
1962 }
1963 
1964 /**
1965  * sampling_method_toggled_cb:
1966  * @button:
1967  * @state:
1968  *
1969  * The method status has changed.
1970  *
1971  **/
1972 static void
sampling_method_toggled_cb(GtkWidget * button,SamplingState * state)1973 sampling_method_toggled_cb (GtkWidget *button, SamplingState *state)
1974 {
1975 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) == 1) {
1976 		gtk_widget_hide (state->random_label);
1977 		gtk_widget_hide (state->random_entry);
1978 		gtk_widget_show (state->period_label);
1979 		gtk_widget_show (state->period_entry);
1980 		gtk_widget_show (state->offset_label);
1981 		gtk_widget_show (state->offset_entry);
1982 		gtk_widget_show (state->major_label);
1983 		gtk_widget_show (state->row_major_button);
1984 		gtk_widget_show (state->col_major_button);
1985 	} else {
1986 		gtk_widget_hide (state->period_label);
1987 		gtk_widget_hide (state->period_entry);
1988 		gtk_widget_hide (state->period_entry);
1989 		gtk_widget_hide (state->offset_label);
1990 		gtk_widget_hide (state->offset_entry);
1991 		gtk_widget_hide (state->major_label);
1992 		gtk_widget_hide (state->row_major_button);
1993 		gtk_widget_hide (state->col_major_button);
1994 		gtk_widget_show (state->random_label);
1995 		gtk_widget_show (state->random_entry);
1996 	}
1997 }
1998 
1999 
2000 /**
2001  * dialog_sampling_realized:
2002  * @widget
2003  * @state:
2004  *
2005  * Fix the size of the options table.
2006  *
2007  **/
2008 static void
dialog_sampling_realized(G_GNUC_UNUSED GtkWidget * widget,SamplingState * state)2009 dialog_sampling_realized (G_GNUC_UNUSED GtkWidget *widget,
2010 			  SamplingState *state)
2011 {
2012 	GtkAllocation alloc;
2013 
2014 	gtk_widget_get_allocation (state->options_grid, &alloc);
2015 	gtk_widget_set_size_request (state->options_grid,
2016 				     alloc.width, alloc.height);
2017 
2018 	gtk_widget_get_allocation (state->random_button, &alloc);
2019 	gtk_widget_set_size_request (state->random_button,
2020 				     alloc.width, alloc.height);
2021 
2022 	gtk_widget_get_allocation (state->periodic_button, &alloc);
2023 	gtk_widget_set_size_request (state->periodic_button,
2024 				     alloc.width, alloc.height);
2025 
2026 	gtk_widget_get_allocation (state->method_label, &alloc);
2027 	gtk_widget_set_size_request (state->method_label,
2028 				     alloc.width, alloc.height);
2029 
2030 	sampling_method_toggled_cb (state->periodic_button, state);
2031 }
2032 
2033 /**
2034  * dialog_sampling_tool:
2035  * @wbcg:
2036  * @sheet:
2037  *
2038  * Show the dialog (guru).
2039  *
2040  **/
2041 int
dialog_sampling_tool(WBCGtk * wbcg,Sheet * sheet)2042 dialog_sampling_tool (WBCGtk *wbcg, Sheet *sheet)
2043 {
2044         SamplingState *state;
2045 	char const * plugins[] = { "Gnumeric_fnlookup",
2046 				   "Gnumeric_fnrandom",
2047 				   NULL};
2048 
2049 	if ((wbcg == NULL) ||
2050 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
2051 		return 1;
2052 
2053 	/* Only pop up one copy per workbook */
2054 	if (gnm_dialog_raise_if_exists (wbcg, SAMPLING_KEY)) {
2055 		return 0;
2056 	}
2057 
2058 	state = g_new0 (SamplingState, 1);
2059 
2060 	if (dialog_tool_init (&state->base, wbcg, sheet,
2061 			      GNUMERIC_HELP_LINK_SAMPLING,
2062 			      "res:ui/sampling.ui", "Sampling",
2063 			      _("Could not create the Sampling Tool dialog."),
2064 			      SAMPLING_KEY,
2065 			      G_CALLBACK (sampling_tool_ok_clicked_cb), NULL,
2066 			      G_CALLBACK (sampling_tool_update_sensitivity_cb),
2067 			      0))
2068 	{
2069 		g_free(state);
2070 		return 0;
2071 	}
2072 
2073 	state->periodic_button  = go_gtk_builder_get_widget (state->base.gui, "periodic-button");
2074 	state->random_button  = go_gtk_builder_get_widget (state->base.gui, "random-button");
2075 	state->method_label = go_gtk_builder_get_widget (state->base.gui, "method-label");
2076 	state->options_grid = go_gtk_builder_get_widget (state->base.gui, "options-grid");
2077 	state->period_label = go_gtk_builder_get_widget (state->base.gui, "period-label");
2078 	state->random_label = go_gtk_builder_get_widget (state->base.gui, "random-label");
2079 	state->period_entry = go_gtk_builder_get_widget (state->base.gui, "period-entry");
2080 	state->random_entry = go_gtk_builder_get_widget (state->base.gui, "random-entry");
2081 	state->number_entry = go_gtk_builder_get_widget (state->base.gui, "number-entry");
2082 	state->offset_label = go_gtk_builder_get_widget (state->base.gui, "offset-label");
2083 	state->offset_entry = go_gtk_builder_get_widget (state->base.gui, "offset-entry");
2084 	state->major_label = go_gtk_builder_get_widget (state->base.gui, "pdir-label");
2085 	state->row_major_button = go_gtk_builder_get_widget (state->base.gui, "row-major-button");
2086 	state->col_major_button = go_gtk_builder_get_widget (state->base.gui, "col-major-button");
2087 
2088 	int_to_entry (GTK_ENTRY (state->number_entry), 1);
2089 	int_to_entry (GTK_ENTRY (state->offset_entry), 0);
2090 
2091 	g_signal_connect_after (G_OBJECT (state->periodic_button),
2092 		"toggled",
2093 		G_CALLBACK (sampling_tool_update_sensitivity_cb), state);
2094 	g_signal_connect (G_OBJECT (state->periodic_button),
2095 		"toggled",
2096 		G_CALLBACK (sampling_method_toggled_cb), state);
2097 	g_signal_connect (G_OBJECT (state->base.dialog),
2098 		"realize",
2099 		G_CALLBACK (dialog_sampling_realized), state);
2100 	g_signal_connect_after (G_OBJECT (state->period_entry),
2101 		"changed",
2102 		G_CALLBACK (sampling_tool_update_sensitivity_cb), state);
2103 	g_signal_connect_after (G_OBJECT (state->random_entry),
2104 		"changed",
2105 		G_CALLBACK (sampling_tool_update_sensitivity_cb), state);
2106 	g_signal_connect_after (G_OBJECT (state->number_entry),
2107 		"changed",
2108 		G_CALLBACK (sampling_tool_update_sensitivity_cb), state);
2109 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2110 				  GTK_WIDGET (state->period_entry));
2111 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2112 				  GTK_WIDGET (state->random_entry));
2113 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2114 				  GTK_WIDGET (state->number_entry));
2115 
2116 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
2117 	sampling_tool_update_sensitivity_cb (NULL, state);
2118 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
2119 
2120         return 0;
2121 }
2122 /**********************************************/
2123 /*  End of sampling tool code */
2124 /**********************************************/
2125 
2126 /**********************************************/
2127 /*  Begin of Regression tool code */
2128 /**********************************************/
2129 
2130 static gint
regression_tool_calc_height(GnmValue * val)2131 regression_tool_calc_height (GnmValue *val)
2132 {
2133 		GnmRange r;
2134 
2135 		if (NULL == range_init_value (&r, val))
2136 			return 0;
2137 		return range_height (&r);
2138 }
2139 
2140 static gint
regression_tool_calc_width(GnmValue * val)2141 regression_tool_calc_width (GnmValue *val)
2142 {
2143 		GnmRange r;
2144 
2145 		if (NULL == range_init_value (&r, val))
2146 			return 0;
2147 		return range_width (&r);
2148 }
2149 
2150 
2151 /**
2152  * regression_tool_ok_clicked_cb:
2153  * @button:
2154  * @state:
2155  *
2156  * Retrieve the information from the dialog and call the regression_tool.
2157  * Note that we assume that the ok_button is only active if the entry fields
2158  * contain sensible data.
2159  **/
2160 static void
regression_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,RegressionToolState * state)2161 regression_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
2162 			       RegressionToolState *state)
2163 {
2164 	data_analysis_output_t  *dao;
2165 	analysis_tools_data_regression_t  *data;
2166 
2167 	GtkWidget *w;
2168 	gnm_float confidence;
2169 	gint y_h;
2170 
2171 	if (state->base.warning_dialog != NULL)
2172 		gtk_widget_destroy (state->base.warning_dialog);
2173 
2174 	data = g_new0 (analysis_tools_data_regression_t, 1);
2175 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
2176 
2177 	data->base.wbc = GNM_WBC (state->base.wbcg);
2178 
2179 	data->base.range_1 = gnm_expr_entry_parse_as_value (
2180 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2181 	data->base.range_2 = gnm_expr_entry_parse_as_value
2182 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
2183 
2184 	y_h = regression_tool_calc_height(data->base.range_2);
2185 
2186 	data->group_by = (y_h == 1) ? GROUPED_BY_ROW : GROUPED_BY_COL;
2187 
2188 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
2189         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
2190 
2191 	entry_to_float (GTK_ENTRY (state->confidence_entry), &confidence, TRUE);
2192 	data->base.alpha = 1 - confidence;
2193 
2194 	w = go_gtk_builder_get_widget (state->base.gui, "intercept-button");
2195 	data->intercept = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
2196 
2197 	data->residual = gtk_toggle_button_get_active
2198 		(GTK_TOGGLE_BUTTON (state->residuals_check));
2199 
2200 	data->multiple_regression
2201 		= !gtk_toggle_button_get_active
2202 		(GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio));
2203 
2204 	data->multiple_y = gtk_toggle_button_get_active
2205 		(GTK_TOGGLE_BUTTON (state->switch_variables_check));
2206 
2207 	if (cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
2208 			       dao, data, analysis_tool_regression_engine, FALSE)) {
2209 		char *text;
2210 
2211 		text = g_strdup_printf (
2212 			_("An unexpected error has occurred: %d."), data->base.err);
2213 		error_in_entry ((GnmGenericToolState *) state,
2214 				GTK_WIDGET (state->base.input_entry), text);
2215 		g_free (text);
2216 
2217 		value_release (data->base.range_1);
2218 		value_release (data->base.range_2);
2219 		g_free (dao);
2220 		g_free (data);
2221 	} else
2222 		gtk_widget_destroy (state->base.dialog);
2223 
2224 }
2225 
2226 /**
2227  * regression_tool_update_sensitivity_cb:
2228  * @state:
2229  *
2230  * Update the dialog widgets sensitivity.
2231  * We cannot use tool_update_sensitivity_cb
2232  * since we are also considering whether in fact
2233  * an interval is given.
2234  **/
2235 static void
regression_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,RegressionToolState * state)2236 regression_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
2237 				       RegressionToolState *state)
2238 {
2239 	int err;
2240 	gnm_float confidence;
2241         GnmValue *input_range;
2242         GnmValue *input_range_2;
2243 	gint y_h, y_w;
2244 	gint x_h, x_w;
2245 	gboolean switch_v;
2246 
2247 	switch_v = gtk_toggle_button_get_active
2248 		(GTK_TOGGLE_BUTTON (state->switch_variables_check));
2249 
2250 	/* Checking Input Range */
2251         input_range_2 = gnm_expr_entry_parse_as_value (
2252 		GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
2253 	if (input_range_2 == NULL) {
2254 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2255 				    switch_v ?
2256 				    _("The x variable range is invalid.") :
2257 				    _("The y variable range is invalid.") );
2258 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2259 		return;
2260 	}
2261 
2262 	y_h = regression_tool_calc_height(input_range_2);
2263 	y_w = regression_tool_calc_width (input_range_2);
2264 	value_release (input_range_2);
2265 
2266 	if (y_h == 0 || y_w == 0) {
2267 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2268 				    switch_v ?
2269 				    _("The x variable range is invalid.") :
2270 				    _("The y variable range is invalid."));
2271 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2272 		return;
2273 	}
2274 	if (y_h != 1 && y_w != 1) {
2275 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2276 				    switch_v ?
2277 				    _("The x variable range must be a vector (n by 1 or 1 by n).") :
2278 				    _("The y variable range must be a vector (n by 1 or 1 by n)."));
2279 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2280 		return;
2281 	}
2282 	if (y_h <= 2 && y_w <= 2) {
2283 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2284 				    switch_v ?
2285 				    _("The x variable range is too small") :
2286 				    _("The y variable range is too small"));
2287 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2288 		return;
2289 	}
2290 
2291 	input_range = gnm_expr_entry_parse_as_value
2292 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2293 	if (input_range == NULL) {
2294 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2295 				    switch_v ?
2296 				    _("The y variables range is invalid.") :
2297 				    _("The x variables range is invalid."));
2298 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2299 		return;
2300 	}
2301 
2302 	x_h = regression_tool_calc_height(input_range);
2303 	x_w = regression_tool_calc_width (input_range);
2304 	value_release (input_range);
2305 
2306 	if (x_h == 0 || x_w == 0) {
2307 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2308 				    switch_v ?
2309 				    _("The y variables range is invalid.") :
2310 				    _("The x variables range is invalid."));
2311 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2312 		return;
2313 	}
2314 
2315 	if ((y_h == 1 && y_w != x_w) || (y_w == 1 && y_h != x_h)) {
2316 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2317 				    switch_v ?
2318 				    _("The sizes of the y variable and x variables ranges do not match.") :
2319 				    _("The sizes of the x variable and y variables ranges do not match."));
2320 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2321 		return;
2322 	}
2323 
2324 	err = entry_to_float (GTK_ENTRY (state->confidence_entry), &confidence, FALSE);
2325 
2326 	if (err != 0 || (1 < confidence || confidence < 0)) {
2327 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2328 				    _("The confidence level is invalid."));
2329 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2330 		return;
2331 	}
2332 
2333         if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
2334 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2335 				    _("The output specification "
2336 				      "is invalid."));
2337 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2338 		return;
2339 	}
2340 
2341 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
2342 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
2343 }
2344 
2345 static void
regression_tool_regression_radio_toggled_cb(G_GNUC_UNUSED GtkToggleButton * togglebutton,RegressionToolState * state)2346 regression_tool_regression_radio_toggled_cb (G_GNUC_UNUSED
2347 					     GtkToggleButton *togglebutton,
2348 					     RegressionToolState *state)
2349 {
2350 	gboolean simple = gtk_toggle_button_get_active
2351 		(GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio));
2352 	if (!simple)
2353 		gtk_toggle_button_set_active
2354 			(GTK_TOGGLE_BUTTON (state->switch_variables_check),
2355 			 FALSE);
2356 
2357 	gtk_toggle_button_set_active
2358 		(GTK_TOGGLE_BUTTON (state->residuals_check), !simple);
2359 	gtk_widget_set_sensitive (state->residuals_check, !simple);
2360 
2361 }
2362 
2363 static void
regression_tool_regression_check_toggled_cb(G_GNUC_UNUSED GtkToggleButton * togglebutton,RegressionToolState * state)2364 regression_tool_regression_check_toggled_cb (G_GNUC_UNUSED
2365 					     GtkToggleButton *togglebutton,
2366 					     RegressionToolState *state)
2367 {
2368 	GtkWidget *w1, *w2;
2369 
2370 	w1 = go_gtk_builder_get_widget (state->base.gui, "var1-label");
2371 	w2 = go_gtk_builder_get_widget (state->base.gui, "var2-label");
2372 
2373 	if (gtk_toggle_button_get_active
2374 	    (GTK_TOGGLE_BUTTON (state->switch_variables_check))) {
2375  		gtk_toggle_button_set_active
2376 			(GTK_TOGGLE_BUTTON
2377 			 (state->simple_linear_regression_radio),
2378 			 TRUE);
2379 		gtk_label_set_markup_with_mnemonic  (GTK_LABEL (w1),
2380 						     _("_Y variables:"));
2381 		gtk_label_set_markup_with_mnemonic  (GTK_LABEL (w2),
2382 						     _("_X variable:"));
2383 	} else {
2384 		gtk_label_set_markup_with_mnemonic  (GTK_LABEL (w1),
2385 						     _("_X variables:"));
2386 		gtk_label_set_markup_with_mnemonic  (GTK_LABEL (w2),
2387 						     _("_Y variable:"));
2388 	}
2389 	regression_tool_update_sensitivity_cb (NULL, state);
2390 }
2391 
2392 
2393 /**
2394  * dialog_regression_tool:
2395  * @wbcg:
2396  * @sheet:
2397  *
2398  * Show the dialog (guru).
2399  *
2400  **/
2401 int
dialog_regression_tool(WBCGtk * wbcg,Sheet * sheet)2402 dialog_regression_tool (WBCGtk *wbcg, Sheet *sheet)
2403 {
2404         RegressionToolState *state;
2405 	char const * plugins[] = { "Gnumeric_fnstat",
2406 				   "Gnumeric_fnlookup",
2407 				   "Gnumeric_fnmath",
2408 				   "Gnumeric_fninfo",
2409 				   "Gnumeric_fnstring",
2410 				   NULL};
2411 
2412 	if ((wbcg == NULL) ||
2413 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
2414 		return 1;
2415 
2416 	/* Only pop up one copy per workbook */
2417 	if (gnm_dialog_raise_if_exists (wbcg, REGRESSION_KEY))
2418 		return 0;
2419 
2420 	state = g_new0 (RegressionToolState, 1);
2421 
2422 	if (dialog_tool_init (&state->base, wbcg, sheet,
2423 			      GNUMERIC_HELP_LINK_REGRESSION,
2424 			      "res:ui/regression.ui", "Regression",
2425 			      _("Could not create the Regression Tool dialog."),
2426 			      REGRESSION_KEY,
2427 			      G_CALLBACK (regression_tool_ok_clicked_cb), NULL,
2428 			      G_CALLBACK (regression_tool_update_sensitivity_cb),
2429 			      GNM_EE_SINGLE_RANGE))
2430 	{
2431 		g_free(state);
2432 		return 0;
2433 	}
2434 
2435 	state->confidence_entry = go_gtk_builder_get_widget (state->base.gui, "confidence-entry");
2436 	float_to_entry (GTK_ENTRY (state->confidence_entry), 0.95);
2437 	g_signal_connect_after (G_OBJECT (state->confidence_entry),
2438 		"changed",
2439 		G_CALLBACK (regression_tool_update_sensitivity_cb), state);
2440 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2441 				  GTK_WIDGET (state->confidence_entry));
2442 
2443 	state->simple_linear_regression_radio
2444 		= go_gtk_builder_get_widget
2445 		(state->base.gui, "simple-regression-button");
2446 	state->switch_variables_check
2447 		= go_gtk_builder_get_widget
2448 		(state->base.gui, "multiple-independent-check");
2449 	state->residuals_check
2450 		= go_gtk_builder_get_widget
2451 		(state->base.gui, "residuals-button");
2452 	gtk_toggle_button_set_active
2453 		(GTK_TOGGLE_BUTTON (state->simple_linear_regression_radio),
2454 		 FALSE);
2455 	gtk_toggle_button_set_active
2456 		(GTK_TOGGLE_BUTTON (state->switch_variables_check),
2457 		 FALSE);
2458 	gtk_toggle_button_set_active
2459 		(GTK_TOGGLE_BUTTON (state->residuals_check),
2460 		 TRUE);
2461 	g_signal_connect
2462 		(G_OBJECT (state->simple_linear_regression_radio),
2463 		 "toggled",
2464 		 G_CALLBACK (regression_tool_regression_radio_toggled_cb),
2465 		 state);
2466 	g_signal_connect
2467 		(G_OBJECT (state->switch_variables_check),
2468 		 "toggled",
2469 		 G_CALLBACK (regression_tool_regression_check_toggled_cb),
2470 		 state);
2471 
2472 
2473 
2474 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
2475 	regression_tool_update_sensitivity_cb (NULL, state);
2476 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
2477 
2478         return 0;
2479 }
2480 
2481 /**********************************************/
2482 /*  End of Regression tool code */
2483 /**********************************************/
2484 
2485 /**********************************************/
2486 /*  Begin of Exponential smoothing tool code */
2487 /**********************************************/
2488 
2489 
2490 /**
2491  * exp_smoothing_tool_ok_clicked_cb:
2492  * @button:
2493  * @state:
2494  *
2495  **/
2496 static void
exp_smoothing_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,ExpSmoothToolState * state)2497 exp_smoothing_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
2498 				  ExpSmoothToolState *state)
2499 {
2500 	data_analysis_output_t  *dao;
2501 	analysis_tools_data_exponential_smoothing_t  *data;
2502 
2503 	GtkWidget               *w;
2504 
2505 	data = g_new0 (analysis_tools_data_exponential_smoothing_t, 1);
2506 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
2507 
2508 	data->base.input = gnm_expr_entry_parse_as_list (
2509 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2510 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
2511 
2512 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
2513         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
2514 
2515 	entry_to_float (GTK_ENTRY (state->damping_fact_entry),
2516 			&data->damp_fact, TRUE);
2517 	entry_to_float (GTK_ENTRY (state->g_damping_fact_entry),
2518 			&data->g_damp_fact, TRUE);
2519 	entry_to_float (GTK_ENTRY (state->s_damping_fact_entry),
2520 			&data->s_damp_fact, TRUE);
2521 	entry_to_int (GTK_ENTRY (state->s_period_entry),
2522 		      &data->s_period, TRUE);
2523 
2524 	data->std_error_flag = gtk_toggle_button_get_active
2525 		(GTK_TOGGLE_BUTTON (state->show_std_errors));
2526 	data->show_graph = gtk_toggle_button_get_active
2527 		(GTK_TOGGLE_BUTTON (state->graph_button));
2528 	data->df = gnm_gui_group_value (state->base.gui, n_group);
2529 
2530 	data->es_type = gnm_gui_group_value (state->base.gui, exp_smoothing_group);
2531 
2532 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
2533 				dao, data, analysis_tool_exponential_smoothing_engine,
2534 				TRUE))
2535 		gtk_widget_destroy (state->base.dialog);
2536 
2537 	return;
2538 }
2539 
2540 /**
2541  * exp_smoothing_tool_update_sensitivity_cb:
2542  * @state:
2543  *
2544  * Update the dialog widgets sensitivity.
2545  * We cannot use tool_update_sensitivity_cb
2546  * since we are also considering whether in fact
2547  * a damping factor is given.
2548  **/
2549 static void
exp_smoothing_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,ExpSmoothToolState * state)2550 exp_smoothing_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
2551 					  ExpSmoothToolState *state)
2552 {
2553 	int err, period;
2554 	gnm_float damp_fact;
2555         GSList *input_range;
2556 
2557         input_range = gnm_expr_entry_parse_as_list (
2558 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2559 	if (input_range == NULL) {
2560 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2561 				    _("The input range is invalid."));
2562 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2563 		return;
2564 	} else
2565 		range_list_destroy (input_range);
2566 
2567 	switch (gnm_gui_group_value (state->base.gui, exp_smoothing_group)) {
2568 	case exp_smoothing_type_mtes:
2569 	case exp_smoothing_type_ates:
2570 		err = entry_to_float (GTK_ENTRY (state->s_damping_fact_entry),
2571 				      &damp_fact, FALSE);
2572 		if (err!= 0 || damp_fact < 0 || damp_fact > 1)  {
2573 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2574 					    _("The given seasonal damping "
2575 					      "factor is invalid."));
2576 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2577 			return;
2578 		}
2579 		err = entry_to_int (GTK_ENTRY (state->s_period_entry),
2580 				      &period, FALSE);
2581 		if (err!= 0 || period < 2)  {
2582 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2583 					    _("The given seasonal period "
2584 					      "is invalid."));
2585 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2586 			return;
2587 		}
2588 		/* no break */
2589 	case exp_smoothing_type_des:
2590 		err = entry_to_float (GTK_ENTRY (state->g_damping_fact_entry),
2591 				      &damp_fact, FALSE);
2592 		if (err!= 0 || damp_fact < 0 || damp_fact > 1)  {
2593 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2594 					    _("The given growth "
2595 					      "damping factor is invalid."));
2596 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2597 			return;
2598 		}
2599 		/* no break */
2600 	case exp_smoothing_type_ses_r:
2601 	case exp_smoothing_type_ses_h:
2602 		err = entry_to_float (GTK_ENTRY (state->damping_fact_entry),
2603 				      &damp_fact, FALSE);
2604 		if (err!= 0 || damp_fact < 0 || damp_fact > 1)  {
2605 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2606 					    _("The given damping factor is invalid."));
2607 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2608 		return;
2609 		}
2610 		break;
2611 	}
2612 
2613 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
2614 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2615 				    _("The output specification "
2616 				      "is invalid."));
2617 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2618 		return;
2619 	}
2620 
2621 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
2622 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
2623 }
2624 
2625 static void
exp_smoothing_tool_check_error_cb(G_GNUC_UNUSED GtkToggleButton * togglebutton,gpointer user_data)2626 exp_smoothing_tool_check_error_cb (G_GNUC_UNUSED GtkToggleButton *togglebutton, gpointer user_data)
2627 {
2628 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user_data), TRUE);
2629 }
2630 
2631 
2632 static void
exp_smoothing_ses_h_cb(GtkToggleButton * togglebutton,gpointer user_data)2633 exp_smoothing_ses_h_cb (GtkToggleButton *togglebutton, gpointer user_data)
2634 {
2635 	ExpSmoothToolState *state = (ExpSmoothToolState *)user_data;
2636 	gboolean std_error;
2637 
2638 	if (!gtk_toggle_button_get_active (togglebutton))
2639 		return;
2640 
2641 	gtk_widget_set_sensitive (state->g_damping_fact_entry, FALSE);
2642 	gtk_widget_set_sensitive (state->s_damping_fact_entry, FALSE);
2643 	gtk_widget_set_sensitive (state->s_period_entry, FALSE);
2644 
2645 	std_error = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->show_std_errors));
2646 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->n_button), TRUE);
2647 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->show_std_errors), std_error);
2648 }
2649 
2650 static void
exp_smoothing_ses_r_cb(GtkToggleButton * togglebutton,gpointer user_data)2651 exp_smoothing_ses_r_cb (GtkToggleButton *togglebutton, gpointer user_data)
2652 {
2653 	ExpSmoothToolState *state = (ExpSmoothToolState *)user_data;
2654 	gboolean std_error;
2655 
2656 	if (!gtk_toggle_button_get_active (togglebutton))
2657 		return;
2658 
2659 	gtk_widget_set_sensitive (state->g_damping_fact_entry, FALSE);
2660 	gtk_widget_set_sensitive (state->s_damping_fact_entry, FALSE);
2661 	gtk_widget_set_sensitive (state->s_period_entry, FALSE);
2662 
2663 	std_error = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->show_std_errors));
2664 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->nm1_button), TRUE);
2665 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->show_std_errors), std_error);
2666 }
2667 
2668 static void
exp_smoothing_des_cb(GtkToggleButton * togglebutton,gpointer user_data)2669 exp_smoothing_des_cb (GtkToggleButton *togglebutton, gpointer user_data)
2670 {
2671 	ExpSmoothToolState *state = (ExpSmoothToolState *)user_data;
2672 	gboolean std_error;
2673 
2674 	if (!gtk_toggle_button_get_active (togglebutton))
2675 		return;
2676 
2677 	gtk_widget_set_sensitive (state->g_damping_fact_entry, TRUE);
2678 	gtk_widget_set_sensitive (state->s_damping_fact_entry, FALSE);
2679 	gtk_widget_set_sensitive (state->s_period_entry, FALSE);
2680 
2681 	std_error = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->show_std_errors));
2682 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->nm2_button), TRUE);
2683 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->show_std_errors), std_error);
2684 }
2685 
2686 static void
exp_smoothing_tes_cb(GtkToggleButton * togglebutton,gpointer user_data)2687 exp_smoothing_tes_cb (GtkToggleButton *togglebutton, gpointer user_data)
2688 {
2689 	ExpSmoothToolState *state = (ExpSmoothToolState *)user_data;
2690 	gboolean std_error;
2691 
2692 	if (!gtk_toggle_button_get_active (togglebutton))
2693 		return;
2694 
2695 	gtk_widget_set_sensitive (state->g_damping_fact_entry, TRUE);
2696 	gtk_widget_set_sensitive (state->s_damping_fact_entry, TRUE);
2697 	gtk_widget_set_sensitive (state->s_period_entry, TRUE);
2698 
2699 	std_error = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->show_std_errors));
2700 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->nm3_button), TRUE);
2701 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->show_std_errors), std_error);
2702 }
2703 
2704 /**
2705  * dialog_exp_smoothing_tool:
2706  * @wbcg:
2707  * @sheet:
2708  *
2709  * Show the dialog (guru).
2710  *
2711  **/
2712 int
dialog_exp_smoothing_tool(WBCGtk * wbcg,Sheet * sheet)2713 dialog_exp_smoothing_tool (WBCGtk *wbcg, Sheet *sheet)
2714 {
2715         ExpSmoothToolState *state;
2716 	char const * plugins[] = { "Gnumeric_fnstat",
2717 				   "Gnumeric_fnlookup",
2718 				   "Gnumeric_fnmath",
2719 				   "Gnumeric_fnlogical",
2720 				   NULL};
2721 
2722 	if ((wbcg == NULL) ||
2723 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
2724 		return 1;
2725 
2726 	/* Only pop up one copy per workbook */
2727 	if (gnm_dialog_raise_if_exists (wbcg, EXP_SMOOTHING_KEY))
2728 		return 0;
2729 
2730 	state = g_new0 (ExpSmoothToolState, 1);
2731 
2732 	if (dialog_tool_init (&state->base, wbcg, sheet,
2733 			      GNUMERIC_HELP_LINK_EXP_SMOOTHING,
2734 			      "res:ui/exp-smoothing.ui",
2735 			      "ExpSmoothing",
2736 			      _("Could not create the Exponential Smoothing "
2737 				"Tool dialog."),
2738 			      EXP_SMOOTHING_KEY,
2739 			      G_CALLBACK (exp_smoothing_tool_ok_clicked_cb),
2740 			      NULL,
2741 			      G_CALLBACK (exp_smoothing_tool_update_sensitivity_cb),
2742 			      0))
2743 	{
2744 		g_free(state);
2745 		return 0;
2746 	}
2747 
2748 	state->damping_fact_entry = go_gtk_builder_get_widget (state->base.gui,
2749 							  "damping-fact-spin");
2750 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->damping_fact_entry), 0.2);
2751 	float_to_entry (GTK_ENTRY (state->damping_fact_entry), 0.2);
2752 	state->g_damping_fact_entry = go_gtk_builder_get_widget (state->base.gui,
2753 							  "g-damping-fact-spin");
2754 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->g_damping_fact_entry), 0.25);
2755 	state->s_damping_fact_entry = go_gtk_builder_get_widget (state->base.gui,
2756 							  "s-damping-fact-spin");
2757 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->s_damping_fact_entry), 0.3);
2758 	state->s_period_entry = go_gtk_builder_get_widget (state->base.gui,
2759 							  "s-period-spin");
2760 	gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->s_period_entry), 12.);
2761 
2762 
2763 	state->n_button = go_gtk_builder_get_widget (state->base.gui, "n-button");
2764 	state->nm1_button = go_gtk_builder_get_widget (state->base.gui, "nm1-button");
2765 	state->nm2_button = go_gtk_builder_get_widget (state->base.gui, "nm2-button");
2766 	state->nm3_button = go_gtk_builder_get_widget (state->base.gui, "nm3-button");
2767 
2768 	state->show_std_errors = go_gtk_builder_get_widget (state->base.gui, "std-errors-button");
2769 	state->graph_button = go_gtk_builder_get_widget (state->base.gui, "graph-check");
2770 
2771 	state->ses_h_button = go_gtk_builder_get_widget (state->base.gui, "ses-h-button");
2772 	state->ses_r_button = go_gtk_builder_get_widget (state->base.gui, "ses-r-button");
2773 	state->des_button = go_gtk_builder_get_widget (state->base.gui, "des-button");
2774 	state->ates_button = go_gtk_builder_get_widget (state->base.gui, "ates-button");
2775 	state->mtes_button = go_gtk_builder_get_widget (state->base.gui, "mtes-button");
2776 
2777 	g_signal_connect_after (G_OBJECT (state->n_button),
2778 		"toggled",
2779 		G_CALLBACK (exp_smoothing_tool_check_error_cb), state->show_std_errors);
2780 	g_signal_connect_after (G_OBJECT (state->nm1_button),
2781 		"toggled",
2782 		G_CALLBACK (exp_smoothing_tool_check_error_cb), state->show_std_errors);
2783 	g_signal_connect_after (G_OBJECT (state->nm2_button),
2784 		"toggled",
2785 		G_CALLBACK (exp_smoothing_tool_check_error_cb), state->show_std_errors);
2786 	g_signal_connect_after (G_OBJECT (state->nm3_button),
2787 		"toggled",
2788 		G_CALLBACK (exp_smoothing_tool_check_error_cb), state->show_std_errors);
2789 	g_signal_connect_after (G_OBJECT (state->damping_fact_entry),
2790 		"changed",
2791 		G_CALLBACK (exp_smoothing_tool_update_sensitivity_cb), state);
2792 
2793 	g_signal_connect_after (G_OBJECT (state->ses_h_button),
2794 				"toggled",
2795 				G_CALLBACK (exp_smoothing_ses_h_cb), state);
2796 	g_signal_connect_after (G_OBJECT (state->ses_r_button),
2797 				"toggled",
2798 				G_CALLBACK (exp_smoothing_ses_r_cb), state);
2799 	g_signal_connect_after (G_OBJECT (state->des_button),
2800 				"toggled",
2801 				G_CALLBACK (exp_smoothing_des_cb), state);
2802 	g_signal_connect_after (G_OBJECT (state->ates_button),
2803 				"toggled",
2804 				G_CALLBACK (exp_smoothing_tes_cb), state);
2805 	g_signal_connect_after (G_OBJECT (state->mtes_button),
2806 				"toggled",
2807 				G_CALLBACK (exp_smoothing_tes_cb), state);
2808 
2809 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2810 				  GTK_WIDGET (state->damping_fact_entry));
2811 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2812 				  GTK_WIDGET (state->g_damping_fact_entry));
2813 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
2814 				  GTK_WIDGET (state->s_damping_fact_entry));
2815 
2816 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
2817 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->ses_h_button), TRUE);
2818 	exp_smoothing_ses_h_cb (GTK_TOGGLE_BUTTON (state->ses_h_button), state);
2819 	exp_smoothing_tool_update_sensitivity_cb (NULL, state);
2820 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
2821 
2822         return 0;
2823 }
2824 
2825 /**********************************************/
2826 /*  End of Exponential Smoothing tool code */
2827 /**********************************************/
2828 
2829 /**********************************************/
2830 /*  Begin of Moving Averages tool code */
2831 /**********************************************/
2832 
2833 
2834 /**
2835  * average_tool_ok_clicked_cb:
2836  * @button:
2837  * @state:
2838  *
2839  * Retrieve the information from the dialog and call the average_tool.
2840  * Note that we assume that the ok_button is only active if the entry fields
2841  * contain sensible data.
2842  **/
2843 static void
average_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,AverageToolState * state)2844 average_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
2845 			    AverageToolState *state)
2846 {
2847 	data_analysis_output_t  *dao;
2848 	analysis_tools_data_moving_average_t  *data;
2849 
2850 	GtkWidget               *w;
2851 
2852 	data = g_new0 (analysis_tools_data_moving_average_t, 1);
2853 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
2854 
2855 	data->base.input = gnm_expr_entry_parse_as_list (
2856 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2857 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
2858 
2859 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
2860         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
2861 
2862 	entry_to_int (GTK_ENTRY (state->interval_entry), &data->interval, TRUE);
2863 	entry_to_int (GTK_ENTRY (state->offset_spin), &data->offset, TRUE);
2864 
2865 	data->std_error_flag = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->show_std_errors));
2866 	data->show_graph = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->graph_button));
2867 
2868 	data->df = gnm_gui_group_value (state->base.gui, n_group);
2869 
2870 	data->ma_type = gnm_gui_group_value (state->base.gui, moving_average_group);
2871 
2872 	switch (data->ma_type) {
2873 	case moving_average_type_sma:
2874 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->central_button))
2875 		    && (data->interval % 2 == 0))
2876 			data->ma_type = moving_average_type_central_sma;
2877 		break;
2878 	case moving_average_type_cma:
2879 		data->interval = 0;
2880 		data->offset = 0;
2881 		break;
2882 	case moving_average_type_spencer_ma:
2883 		data->interval = 15;
2884 		data->offset = 7;
2885 		break;
2886 	case moving_average_type_wma:
2887 		data->offset = 0;
2888 		break;
2889 	default:
2890 		break;
2891 	}
2892 
2893 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
2894 				dao, data, analysis_tool_moving_average_engine, TRUE))
2895 		gtk_widget_destroy (state->base.dialog);
2896 
2897 	return;
2898 }
2899 
2900 /**
2901  * average_tool_update_sensitivity_cb:
2902  * @state:
2903  *
2904  * Update the dialog widgets sensitivity.
2905  * We cannot use tool_update_sensitivity_cb
2906  * since we are also considering whether in fact
2907  * an interval is given.
2908  **/
2909 static void
average_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,AverageToolState * state)2910 average_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
2911 				    AverageToolState *state)
2912 {
2913 	int interval, err, offset;
2914         GSList *input_range;
2915 	moving_average_type_t type;
2916 
2917 
2918         input_range = gnm_expr_entry_parse_as_list (
2919 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
2920 	if (input_range == NULL) {
2921 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2922 				    _("The input range is invalid."));
2923 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2924 		return;
2925 	} else
2926 		range_list_destroy (input_range);
2927 
2928 	type = gnm_gui_group_value (state->base.gui, moving_average_group);
2929 
2930 	if ((type == moving_average_type_sma) || (type == moving_average_type_wma)) {
2931 		err = entry_to_int (GTK_ENTRY (state->interval_entry),
2932 				    &interval, FALSE);
2933 		if (err!= 0 || interval <= 0)  {
2934 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2935 					    _("The given interval is invalid."));
2936 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2937 			return;
2938 		}
2939 	}
2940 
2941 	if (type == moving_average_type_sma) {
2942 		err = entry_to_int (GTK_ENTRY (state->offset_spin), &offset, FALSE);
2943 		if (err!= 0 || offset < 0 || offset > interval)  {
2944 			gtk_label_set_text (GTK_LABEL (state->base.warning),
2945 					    _("The given offset is invalid."));
2946 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2947 			return;
2948 		}
2949 	}
2950 
2951 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
2952 		gtk_label_set_text (GTK_LABEL (state->base.warning),
2953 				    _("The output specification "
2954 				      "is invalid."));
2955 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
2956 		return;
2957 	}
2958 
2959 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
2960 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
2961 }
2962 
2963 static void
average_tool_check_error_cb(G_GNUC_UNUSED GtkToggleButton * togglebutton,gpointer user_data)2964 average_tool_check_error_cb (G_GNUC_UNUSED GtkToggleButton *togglebutton, gpointer user_data)
2965 {
2966 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user_data), TRUE);
2967 }
2968 
2969 static void
average_tool_central_cb(GtkToggleButton * togglebutton,gpointer user_data)2970 average_tool_central_cb (GtkToggleButton *togglebutton, gpointer user_data)
2971 {
2972 	AverageToolState *state = (AverageToolState *)user_data;
2973 	int interval;
2974 	int err;
2975 
2976 	if (gtk_toggle_button_get_active (togglebutton)) {
2977 		err = entry_to_int (GTK_ENTRY (state->interval_entry), &interval, TRUE);
2978 		if (err == 0)
2979 			gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->offset_spin), (interval/2));
2980 	}
2981 }
2982 
2983 static void
average_tool_prior_cb(GtkToggleButton * togglebutton,gpointer user_data)2984 average_tool_prior_cb (GtkToggleButton *togglebutton, gpointer user_data)
2985 {
2986 	AverageToolState *state = (AverageToolState *)user_data;
2987 
2988 	if (gtk_toggle_button_get_active (togglebutton))
2989 		gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->offset_spin), 0.0);
2990 }
2991 
2992 static void
average_tool_interval_cb(G_GNUC_UNUSED GtkWidget * dummy,AverageToolState * state)2993 average_tool_interval_cb (G_GNUC_UNUSED GtkWidget *dummy, AverageToolState *state)
2994 {
2995 	int interval;
2996 	int err;
2997 
2998 	err = entry_to_int (GTK_ENTRY (state->interval_entry), &interval, TRUE);
2999 
3000 	if (err == 0)
3001 		gtk_spin_button_set_range (GTK_SPIN_BUTTON (state->offset_spin),
3002 					   0, interval - 1);
3003 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (state->central_button)))
3004 		gtk_spin_button_set_value (GTK_SPIN_BUTTON (state->offset_spin), interval/2);
3005 }
3006 
3007 static void
average_tool_offset_cb(GtkToggleButton * togglebutton,gpointer user_data)3008 average_tool_offset_cb (GtkToggleButton *togglebutton, gpointer user_data)
3009 {
3010 	AverageToolState *state = (AverageToolState *)user_data;
3011 
3012 	gtk_widget_set_sensitive (state->offset_spin, gtk_toggle_button_get_active (togglebutton));
3013 }
3014 
3015 
3016 static void
average_tool_sma_cb(GtkToggleButton * togglebutton,gpointer user_data)3017 average_tool_sma_cb (GtkToggleButton *togglebutton, gpointer user_data)
3018 {
3019 	AverageToolState *state = (AverageToolState *)user_data;
3020 
3021 	if (!gtk_toggle_button_get_active (togglebutton))
3022 		return;
3023 
3024 	gtk_widget_set_sensitive (state->prior_button, TRUE);
3025 	gtk_widget_set_sensitive (state->central_button, TRUE);
3026 	gtk_widget_set_sensitive (state->offset_button, TRUE);
3027 	gtk_widget_set_sensitive (state->interval_entry, TRUE);
3028 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->prior_button), TRUE);
3029 	average_tool_update_sensitivity_cb (NULL, state);
3030 }
3031 
3032 static void
average_tool_cma_cb(GtkToggleButton * togglebutton,gpointer user_data)3033 average_tool_cma_cb (GtkToggleButton *togglebutton, gpointer user_data)
3034 {
3035 	AverageToolState *state = (AverageToolState *)user_data;
3036 
3037 	if (!gtk_toggle_button_get_active (togglebutton))
3038 		return;
3039 
3040 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->prior_button), TRUE);
3041 	gtk_widget_set_sensitive (state->prior_button, FALSE);
3042 	gtk_widget_set_sensitive (state->central_button, FALSE);
3043 	gtk_widget_set_sensitive (state->offset_button, FALSE);
3044 	gtk_widget_set_sensitive (state->interval_entry, FALSE);
3045 	average_tool_update_sensitivity_cb (NULL, state);
3046 }
3047 
3048 static void
average_tool_wma_cb(GtkToggleButton * togglebutton,gpointer user_data)3049 average_tool_wma_cb (GtkToggleButton *togglebutton, gpointer user_data)
3050 {
3051 	AverageToolState *state = (AverageToolState *)user_data;
3052 
3053 	if (!gtk_toggle_button_get_active (togglebutton))
3054 		return;
3055 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->prior_button), TRUE);
3056 	gtk_widget_set_sensitive (state->prior_button, FALSE);
3057 	gtk_widget_set_sensitive (state->central_button, FALSE);
3058 	gtk_widget_set_sensitive (state->offset_button, FALSE);
3059 	gtk_widget_set_sensitive (state->interval_entry, TRUE);
3060 	average_tool_update_sensitivity_cb (NULL, state);
3061 }
3062 
3063 static void
average_tool_spencer_cb(GtkToggleButton * togglebutton,gpointer user_data)3064 average_tool_spencer_cb (GtkToggleButton *togglebutton, gpointer user_data)
3065 {
3066 	AverageToolState *state = (AverageToolState *)user_data;
3067 
3068 	if (!gtk_toggle_button_get_active (togglebutton))
3069 		return;
3070 	int_to_entry (GTK_ENTRY (state->interval_entry), 15);
3071 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->central_button), TRUE);
3072 	gtk_widget_set_sensitive (state->prior_button, FALSE);
3073 	gtk_widget_set_sensitive (state->central_button, FALSE);
3074 	gtk_widget_set_sensitive (state->offset_button, FALSE);
3075 	gtk_widget_set_sensitive (state->interval_entry, FALSE);
3076 	average_tool_update_sensitivity_cb (NULL, state);
3077 }
3078 
3079 /**
3080  * dialog_average_tool:
3081  * @wbcg:
3082  * @sheet:
3083  *
3084  * Show the dialog (guru).
3085  *
3086  **/
3087 int
dialog_average_tool(WBCGtk * wbcg,Sheet * sheet)3088 dialog_average_tool (WBCGtk *wbcg, Sheet *sheet)
3089 {
3090         AverageToolState *state;
3091 	char const * plugins[] = { "Gnumeric_fnstat",
3092 				   "Gnumeric_fnlookup",
3093 				   "Gnumeric_fnmath",
3094 				   NULL};
3095 
3096 	if ((wbcg == NULL) ||
3097 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
3098 		return 1;
3099 
3100 	/* Only pop up one copy per workbook */
3101 	if (gnm_dialog_raise_if_exists (wbcg, AVERAGE_KEY))
3102 		return 0;
3103 
3104 	state = g_new0 (AverageToolState, 1);
3105 
3106 	if (dialog_tool_init (&state->base, wbcg, sheet,
3107 			      GNUMERIC_HELP_LINK_MOVING_AVERAGES,
3108 			      "res:ui/moving-averages.ui",
3109 			      "MovAverages",
3110 			      _("Could not create the Moving Average Tool "
3111 				"dialog."),
3112 			      AVERAGE_KEY,
3113 			      G_CALLBACK (average_tool_ok_clicked_cb), NULL,
3114 			      G_CALLBACK (average_tool_update_sensitivity_cb),
3115 			      0))
3116 	{
3117 		g_free(state);
3118 		return 0;
3119 	}
3120 
3121 	state->interval_entry = go_gtk_builder_get_widget (state->base.gui, "interval-entry");
3122 	int_to_entry (GTK_ENTRY (state->interval_entry), 3);
3123 	state->n_button = go_gtk_builder_get_widget (state->base.gui, "n-button");
3124 	state->nm1_button = go_gtk_builder_get_widget (state->base.gui, "nm1-button");
3125 	state->nm2_button = go_gtk_builder_get_widget (state->base.gui, "nm2-button");
3126 	state->prior_button = go_gtk_builder_get_widget (state->base.gui, "prior-button");
3127 	state->central_button = go_gtk_builder_get_widget (state->base.gui, "central-button");
3128 	state->offset_button = go_gtk_builder_get_widget (state->base.gui, "offset-button");
3129 	state->offset_spin = go_gtk_builder_get_widget (state->base.gui, "offset-spinbutton");
3130 	state->show_std_errors = go_gtk_builder_get_widget (state->base.gui, "std-errors-button");
3131 	state->graph_button = go_gtk_builder_get_widget (state->base.gui, "graph-check");
3132 	state->sma_button = go_gtk_builder_get_widget (state->base.gui, "sma-button");
3133 	state->cma_button = go_gtk_builder_get_widget (state->base.gui, "cma-button");
3134 	state->wma_button = go_gtk_builder_get_widget (state->base.gui, "wma-button");
3135 	state->spencer_button = go_gtk_builder_get_widget (state->base.gui, "spencer-ma-button");
3136 
3137 
3138 	g_signal_connect_after (G_OBJECT (state->n_button),
3139 		"toggled",
3140 		G_CALLBACK (average_tool_check_error_cb), state->show_std_errors);
3141 	g_signal_connect_after (G_OBJECT (state->nm1_button),
3142 		"toggled",
3143 		G_CALLBACK (average_tool_check_error_cb), state->show_std_errors);
3144 	g_signal_connect_after (G_OBJECT (state->nm2_button),
3145 		"toggled",
3146 		G_CALLBACK (average_tool_check_error_cb), state->show_std_errors);
3147 
3148 	g_signal_connect_after (G_OBJECT (state->prior_button),
3149 		"toggled",
3150 		G_CALLBACK (average_tool_prior_cb), state);
3151 	g_signal_connect_after (G_OBJECT (state->central_button),
3152 		"toggled",
3153 		G_CALLBACK (average_tool_central_cb), state);
3154 	g_signal_connect_after (G_OBJECT (state->offset_button),
3155 		"toggled",
3156 		G_CALLBACK (average_tool_offset_cb), state);
3157 
3158 	g_signal_connect_after (G_OBJECT (state->sma_button),
3159 		"toggled",
3160 		G_CALLBACK (average_tool_sma_cb), state);
3161 	g_signal_connect_after (G_OBJECT (state->cma_button),
3162 		"toggled",
3163 		G_CALLBACK (average_tool_cma_cb), state);
3164 	g_signal_connect_after (G_OBJECT (state->wma_button),
3165 		"toggled",
3166 		G_CALLBACK (average_tool_wma_cb), state);
3167 	g_signal_connect_after (G_OBJECT (state->spencer_button),
3168 		"toggled",
3169 		G_CALLBACK (average_tool_spencer_cb), state);
3170 
3171 
3172 	g_signal_connect_after (G_OBJECT (state->interval_entry),
3173 		"changed",
3174 		G_CALLBACK (average_tool_update_sensitivity_cb), state);
3175 	g_signal_connect_after (G_OBJECT (state->interval_entry),
3176 		"changed",
3177 		G_CALLBACK (average_tool_interval_cb), state);
3178 
3179 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
3180 				  GTK_WIDGET (state->interval_entry));
3181 
3182 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
3183 	average_tool_update_sensitivity_cb (NULL, state);
3184 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
3185 
3186         return 0;
3187 }
3188 
3189 /**********************************************/
3190 /*  End of Moving Averages tool code */
3191 /**********************************************/
3192 
3193 /**********************************************/
3194 /*  Begin of histogram tool code */
3195 /**********************************************/
3196 
3197 /**
3198  * histogram_tool_update_sensitivity_cb:
3199  * @dummy:
3200  * @state:
3201  *
3202  * Update the dialog widgets sensitivity
3203  **/
3204 static void
histogram_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,HistogramToolState * state)3205 histogram_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
3206 				      HistogramToolState *state)
3207 {
3208 	int the_n;
3209 	gboolean predetermined_bins;
3210         GSList *input_range;
3211         GnmValue *input_range_2 = NULL;
3212 
3213 	input_range = gnm_expr_entry_parse_as_list
3214 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
3215 	if (input_range == NULL) {
3216 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3217 				    _("The input range is invalid."));
3218 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3219 		return;
3220 	}
3221 
3222 	range_list_destroy (input_range);
3223 
3224 	predetermined_bins = gtk_toggle_button_get_active (
3225 		GTK_TOGGLE_BUTTON (state->predetermined_button));
3226 	if (predetermined_bins) {
3227 		input_range_2 =  gnm_expr_entry_parse_as_value
3228 			(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
3229 		if (input_range_2 == NULL) {
3230 			gtk_label_set_text (GTK_LABEL (state->base.warning),
3231 					    _("The cutoff range is not valid."));
3232 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3233 			return;
3234 		}
3235 		value_release (input_range_2);
3236 	} else if (entry_to_int(state->n_entry, &the_n,FALSE) != 0 || the_n <= 0) {
3237 			gtk_label_set_text (GTK_LABEL (state->base.warning),
3238 					    _("The number of to be calculated cutoffs is invalid."));
3239 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3240 			return;
3241 	}
3242 
3243         if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
3244 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3245 				    _("The output specification "
3246 				      "is invalid."));
3247 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3248 		return;
3249 	}
3250 
3251 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
3252 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
3253 
3254 	return;
3255 }
3256 
3257 /**
3258  * histogram_tool_ok_clicked_cb:
3259  * @button:
3260  * @state:
3261  *
3262  * Retrieve the information from the dialog and call the histogram_tool.
3263  * Note that we assume that the ok_button is only active if the entry fields
3264  * contain sensible data.
3265  **/
3266 static void
histogram_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,HistogramToolState * state)3267 histogram_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
3268 			      HistogramToolState *state)
3269 {
3270 	data_analysis_output_t  *dao;
3271 	analysis_tools_data_histogram_t  *data;
3272 
3273 	GtkWidget *w;
3274 
3275 	data = g_new0 (analysis_tools_data_histogram_t, 1);
3276 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
3277 
3278 	data->base.input = gnm_expr_entry_parse_as_list (
3279 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
3280 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
3281 
3282 	data->predetermined = gtk_toggle_button_get_active (
3283 		GTK_TOGGLE_BUTTON (state->predetermined_button));
3284 	if (data->predetermined) {
3285 		w = go_gtk_builder_get_widget (state->base.gui, "labels_2_button");
3286 		data->bin = gnm_expr_entry_parse_as_value
3287 			(GNM_EXPR_ENTRY (state->base.input_entry_2),
3288 			 state->base.sheet);
3289 	} else {
3290 		entry_to_int(state->n_entry, &data->n,TRUE);
3291 		data->max_given = (0 == entry_to_float (state->max_entry,
3292 							    &data->max , TRUE));
3293 		data->min_given = (0 == entry_to_float (state->min_entry,
3294 							    &data->min , TRUE));
3295 		data->bin = NULL;
3296 	}
3297 
3298 	data->bin_type = gnm_gui_group_value (state->base.gui, bin_type_group);
3299 	data->chart = gnm_gui_group_value (state->base.gui, chart_group);
3300 
3301 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
3302 	data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3303 	w = go_gtk_builder_get_widget (state->base.gui, "percentage-button");
3304 	data->percentage = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3305 	w = go_gtk_builder_get_widget (state->base.gui, "cum-button");
3306 	data->cumulative = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3307 	w = go_gtk_builder_get_widget (state->base.gui, "only-num-button");
3308 	data->only_numbers = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3309 
3310 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
3311 				dao, data, analysis_tool_histogram_engine, TRUE))
3312 		gtk_widget_destroy (state->base.dialog);
3313 
3314 	return;
3315 }
3316 
3317 /**
3318  * histogram_tool_set_predetermined:
3319  * @widget:
3320  * @focus_widget:
3321  * @state:
3322  *
3323  * Output range entry was focused. Switch to output range.
3324  *
3325  **/
3326 static gboolean
histogram_tool_set_predetermined(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,HistogramToolState * state)3327 histogram_tool_set_predetermined (G_GNUC_UNUSED GtkWidget *widget,
3328 				  G_GNUC_UNUSED GdkEventFocus *event,
3329 				  HistogramToolState *state)
3330 {
3331 	    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->predetermined_button), TRUE);
3332 	    return FALSE;
3333 }
3334 
3335 /**
3336  * histogram_tool_set_calculated:
3337  * @widget:
3338  * @event:
3339  * @state:
3340  *
3341  **/
3342 static gboolean
histogram_tool_set_calculated(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventFocus * event,HistogramToolState * state)3343 histogram_tool_set_calculated (G_GNUC_UNUSED GtkWidget *widget,
3344 			       G_GNUC_UNUSED GdkEventFocus *event,
3345 			       HistogramToolState *state)
3346 {
3347 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->calculated_button), TRUE);
3348 	return FALSE;
3349 }
3350 
3351 /**
3352  * dialog_histogram_tool:
3353  * @wbcg:
3354  * @sheet:
3355  *
3356  * Show the dialog (guru).
3357  *
3358  **/
3359 int
dialog_histogram_tool(WBCGtk * wbcg,Sheet * sheet)3360 dialog_histogram_tool (WBCGtk *wbcg, Sheet *sheet)
3361 {
3362         HistogramToolState *state;
3363 	char const * plugins[] = {"Gnumeric_fnlogical",
3364 				  "Gnumeric_fnstat",
3365 				  "Gnumeric_fnlookup",
3366 				  NULL};
3367 
3368 	if ((wbcg == NULL) ||
3369 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
3370 		return 1;
3371 
3372 	/* Only pop up one copy per workbook */
3373 	if (gnm_dialog_raise_if_exists (wbcg, HISTOGRAM_KEY))
3374 		return 0;
3375 
3376 	state = g_new0 (HistogramToolState, 1);
3377 
3378 	if (dialog_tool_init (&state->base, wbcg, sheet,
3379 			      GNUMERIC_HELP_LINK_HISTOGRAM,
3380 			      "res:ui/histogram.ui", "Histogram",
3381 			      _("Could not create the Histogram Tool dialog."),
3382 			      HISTOGRAM_KEY,
3383 			      G_CALLBACK (histogram_tool_ok_clicked_cb), NULL,
3384 			      G_CALLBACK (histogram_tool_update_sensitivity_cb),
3385 			      0))
3386 	{
3387 		g_free(state);
3388 		return 0;
3389 	}
3390 
3391 	state->predetermined_button = GTK_WIDGET (go_gtk_builder_get_widget
3392 						  (state->base.gui,
3393 						   "pre_determined_button"));
3394 	state->calculated_button = GTK_WIDGET (go_gtk_builder_get_widget
3395 					       (state->base.gui,
3396 						"calculated_button"));
3397 	state->n_entry = GTK_ENTRY(go_gtk_builder_get_widget (state->base.gui,
3398 							  "n_entry"));
3399 	state->max_entry = GTK_ENTRY(go_gtk_builder_get_widget (state->base.gui,
3400 							    "max_entry"));
3401 	state->min_entry = GTK_ENTRY(go_gtk_builder_get_widget (state->base.gui,
3402 							    "min_entry"));
3403 
3404 	g_signal_connect_after (G_OBJECT (state->predetermined_button),
3405 		"toggled",
3406 		G_CALLBACK (histogram_tool_update_sensitivity_cb), state);
3407 	g_signal_connect_after (G_OBJECT (state->calculated_button),
3408 		"toggled",
3409 		G_CALLBACK (histogram_tool_update_sensitivity_cb), state);
3410 	g_signal_connect_after (G_OBJECT (state->n_entry),
3411 		"changed",
3412 		G_CALLBACK (histogram_tool_update_sensitivity_cb), state);
3413 	g_signal_connect (G_OBJECT (state->n_entry),
3414 		"key-press-event",
3415 		G_CALLBACK (histogram_tool_set_calculated), state);
3416 	g_signal_connect (G_OBJECT (state->min_entry),
3417 		"key-press-event",
3418 		G_CALLBACK (histogram_tool_set_calculated), state);
3419 	g_signal_connect (G_OBJECT (state->max_entry),
3420 		"key-press-event",
3421 		G_CALLBACK (histogram_tool_set_calculated), state);
3422 	g_signal_connect (G_OBJECT
3423 			  (gnm_expr_entry_get_entry (
3424 				  GNM_EXPR_ENTRY (state->base.input_entry_2))),
3425 		"focus-in-event",
3426 		G_CALLBACK (histogram_tool_set_predetermined), state);
3427 
3428 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
3429 	histogram_tool_update_sensitivity_cb (NULL, state);
3430 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
3431 
3432 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (state->calculated_button), TRUE);
3433 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (go_gtk_builder_get_widget (state->base.gui,"histogram-button")), TRUE);
3434 	gtk_entry_set_text (GTK_ENTRY (state->n_entry), "12");
3435 
3436         return 0;
3437 }
3438 
3439 /**********************************************/
3440 /*  End of histogram tool code */
3441 /**********************************************/
3442 
3443 /**********************************************/
3444 /*  Begin of ANOVA (single factor) tool code */
3445 /**********************************************/
3446 
3447 
3448 /**
3449  * anova_single_tool_ok_clicked_cb:
3450  * @button:
3451  * @state:
3452  *
3453  * Retrieve the information from the dialog and call the fourier_tool.
3454  * Note that we assume that the ok_button is only active if the entry fields
3455  * contain sensible data.
3456  **/
3457 static void
anova_single_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,AnovaSingleToolState * state)3458 anova_single_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
3459 				 AnovaSingleToolState *state)
3460 {
3461 	data_analysis_output_t  *dao;
3462 	GtkWidget *w;
3463 	analysis_tools_data_anova_single_t *data;
3464 
3465 	data = g_new0 (analysis_tools_data_anova_single_t, 1);
3466 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
3467 
3468 	data->base.input = gnm_expr_entry_parse_as_list (
3469 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
3470 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
3471 
3472 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
3473         data->base.labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3474 	data->alpha = gtk_spin_button_get_value
3475 		(GTK_SPIN_BUTTON (state->alpha_entry));
3476 
3477 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg), state->base.sheet,
3478 				dao, data, analysis_tool_anova_single_engine, TRUE))
3479 		gtk_widget_destroy (state->base.dialog);
3480 
3481 	return;
3482 }
3483 
3484 /**
3485  * anova_single_tool_update_sensitivity_cb:
3486  * @state:
3487  *
3488  * Update the dialog widgets sensitivity.
3489  * We cannot use tool_update_sensitivity_cb
3490  * since we are also considering whether in fact
3491  * an alpha is given.
3492  **/
3493 static void
anova_single_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,AnovaSingleToolState * state)3494 anova_single_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
3495 					 AnovaSingleToolState *state)
3496 {
3497 	gnm_float alpha;
3498         GSList *input_range;
3499 
3500         input_range = gnm_expr_entry_parse_as_list (
3501 		GNM_EXPR_ENTRY (state->base.input_entry),
3502 		state->base.sheet);
3503 	if (input_range == NULL) {
3504 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3505 				    _("The input range is invalid."));
3506 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3507 		return;
3508 	} else
3509 		range_list_destroy (input_range);
3510 
3511 	/* Checking Alpha*/
3512 	alpha = gtk_spin_button_get_value
3513 		(GTK_SPIN_BUTTON (state->alpha_entry));
3514 	if (!(alpha > 0 && alpha < 1)) {
3515 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3516 				    _("The alpha value should "
3517 				      "be a number between 0 and 1."));
3518 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3519 		return;
3520 	}
3521 
3522 	/* Checking Output Page */
3523 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
3524 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3525 				    _("The output specification "
3526 				      "is invalid."));
3527 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3528 		return;
3529 	}
3530 
3531 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
3532 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
3533 
3534 }
3535 
3536 
3537 /**
3538  * dialog_anova_single_tool:
3539  * @wbcg:
3540  * @sheet:
3541  *
3542  * Show the dialog (guru).
3543  *
3544  **/
3545 int
dialog_anova_single_factor_tool(WBCGtk * wbcg,Sheet * sheet)3546 dialog_anova_single_factor_tool (WBCGtk *wbcg, Sheet *sheet)
3547 {
3548         AnovaSingleToolState *state;
3549 	char const * plugins[] = { "Gnumeric_fnstat",
3550 				   NULL};
3551 
3552 	if ((wbcg == NULL) ||
3553 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
3554 		return 1;
3555 
3556 	/* Only pop up one copy per workbook */
3557 	if (gnm_dialog_raise_if_exists (wbcg, ANOVA_SINGLE_KEY))
3558 		return 0;
3559 
3560 	state = g_new0 (AnovaSingleToolState, 1);
3561 
3562 	if (dialog_tool_init (&state->base, wbcg, sheet,
3563 			      GNUMERIC_HELP_LINK_ANOVA_SINGLE_FACTOR,
3564 			      "res:ui/anova-one.ui", "ANOVA",
3565 			      _("Could not create the ANOVA (single factor) "
3566 				"tool dialog."),
3567 			      ANOVA_SINGLE_KEY,
3568 			      G_CALLBACK (anova_single_tool_ok_clicked_cb),
3569 			      NULL,
3570 			      G_CALLBACK (anova_single_tool_update_sensitivity_cb),
3571 			      0))
3572 	{
3573 		g_free(state);
3574 		return 0;
3575 	}
3576 
3577 	state->alpha_entry = go_gtk_builder_get_widget (state->base.gui,
3578 						   "alpha-entry");
3579 	float_to_entry (GTK_ENTRY (state->alpha_entry), 0.05);
3580 	g_signal_connect_after (G_OBJECT (state->alpha_entry),
3581 		"changed",
3582 		G_CALLBACK (anova_single_tool_update_sensitivity_cb), state);
3583 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
3584 				  GTK_WIDGET (state->alpha_entry));
3585 
3586 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
3587 	anova_single_tool_update_sensitivity_cb (NULL, state);
3588 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
3589 
3590         return 0;
3591 }
3592 
3593 /**********************************************/
3594 /*  End of ANOVA (Single Factor) tool code */
3595 /**********************************************/
3596 
3597 /**********************************************/
3598 /*  Begin of ANOVA (two factor) tool code */
3599 /**********************************************/
3600 
3601 
3602 /**
3603  * anova_two_factor_tool_ok_clicked_cb:
3604  * @button:
3605  * @state:
3606  *
3607  * Retrieve the information from the dialog and call the fourier_tool.
3608  * Note that we assume that the ok_button is only active if the entry fields
3609  * contain sensible data.
3610  **/
3611 static void
anova_two_factor_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,AnovaTwoFactorToolState * state)3612 anova_two_factor_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
3613 				     AnovaTwoFactorToolState *state)
3614 {
3615 	data_analysis_output_t  *dao;
3616 	GtkWidget *w;
3617 	analysis_tools_data_anova_two_factor_t *data;
3618 	char *text;
3619 
3620 	if (state->base.warning_dialog != NULL)
3621 		gtk_widget_destroy (state->base.warning_dialog);
3622 
3623 	data = g_new0 (analysis_tools_data_anova_two_factor_t, 1);
3624 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
3625 
3626 	data->input = gnm_expr_entry_parse_as_value
3627 		(GNM_EXPR_ENTRY (state->base.input_entry),
3628 		 state->base.sheet);
3629 	data->err = analysis_tools_noerr;
3630 	data->wbc = GNM_WBC (state->base.wbcg);
3631 
3632 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
3633         data->labels = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
3634 
3635 	data->alpha = gtk_spin_button_get_value
3636 		(GTK_SPIN_BUTTON (state->alpha_entry));
3637 	entry_to_int (GTK_ENTRY (state->replication_entry),
3638 			    &data->replication, TRUE);
3639 
3640 	if (cmd_analysis_tool (GNM_WBC (state->base.wbcg),
3641 			       state->base.sheet,
3642 			       dao, data, analysis_tool_anova_two_factor_engine, FALSE)) {
3643 		switch (data->err) {
3644 		case analysis_tools_missing_data:
3645 			error_in_entry ((GnmGenericToolState *) state,
3646 					GTK_WIDGET (state->base.input_entry),
3647 					data->labels ? _("The given input range should contain at "
3648 					  "least two columns and two rows of data and the "
3649 					  "labels.") :
3650 					_("The given input range should contain at "
3651 					  "least two columns and two rows of data."));
3652 			break;
3653 		case analysis_tools_too_few_cols:
3654 			error_in_entry ((GnmGenericToolState *) state,
3655 					GTK_WIDGET (state->base.input_entry),
3656 					data->labels ? _("The given input range should contain at "
3657 					  "least two columns of data and the "
3658 					  "labels.") :
3659 					_("The given input range should contain at "
3660 					  "least two columns of data."));
3661 			break;
3662 		case analysis_tools_too_few_rows:
3663 			error_in_entry ((GnmGenericToolState *) state,
3664 					GTK_WIDGET (state->base.input_entry),
3665 					data->labels ? _("The given input range should contain at "
3666 					  "least two rows of data and the "
3667 					  "labels.") :
3668 					_("The given input range should "
3669 					  "contain at least two rows of "
3670 					  "data."));
3671 			break;
3672 		case analysis_tools_replication_invalid:
3673 			error_in_entry ((GnmGenericToolState *) state,
3674 					GTK_WIDGET (state->base.input_entry),
3675 					_("The number of data rows must be a "
3676 					  "multiple of the replication "
3677 					  "number."));
3678 			break;
3679 		default:
3680 			text = g_strdup_printf (
3681 				_("An unexpected error has occurred: %d."),
3682 				data->err);
3683 			error_in_entry ((GnmGenericToolState *) state,
3684 					GTK_WIDGET (state->base.input_entry),
3685 					text);
3686 			g_free (text);
3687 			break;
3688 		}
3689 		value_release (data->input);
3690 		g_free (dao);
3691 		g_free (data);
3692 	} else
3693 		gtk_widget_destroy (state->base.dialog);
3694 
3695 	return;
3696 }
3697 
3698 /**
3699  * anova_two_factor_tool_update_sensitivity_cb:
3700  * @state:
3701  *
3702  * Update the dialog widgets sensitivity.
3703  * We cannot use tool_update_sensitivity_cb
3704  * since we are also considering whether in fact
3705  * an alpha and a replication is given.
3706  **/
3707 static void
anova_two_factor_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,AnovaTwoFactorToolState * state)3708 anova_two_factor_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
3709 					     AnovaTwoFactorToolState *state)
3710 {
3711 	int replication, err_replication;
3712 	gnm_float alpha;
3713         GnmValue *input_range;
3714 
3715 	/* Checking Input Range */
3716         input_range = gnm_expr_entry_parse_as_value
3717 		(GNM_EXPR_ENTRY (state->base.input_entry),
3718 		 state->base.sheet);
3719 	if (input_range == NULL) {
3720 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3721 				    _("The input range is invalid."));
3722 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3723 		return;
3724 	} else
3725 		value_release (input_range);
3726 
3727 	/* Checking Alpha*/
3728 	alpha = gtk_spin_button_get_value
3729 		(GTK_SPIN_BUTTON (state->alpha_entry));
3730 	if (!(alpha > 0 && alpha < 1)) {
3731 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3732 				    _("The alpha value should "
3733 				      "be a number between 0 and 1."));
3734 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3735 		return;
3736 	}
3737 
3738 
3739 	/* Checking Replication*/
3740 	err_replication = entry_to_int (GTK_ENTRY (state->replication_entry),
3741 					&replication, FALSE);
3742 	if (!(err_replication == 0 && replication > 0)) {
3743 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3744 				    _("The number of rows per sample "
3745 				      "should be a positive integer."));
3746 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3747 		return;
3748 	}
3749 
3750 	/* Checking Output Page */
3751 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
3752 		gtk_label_set_text (GTK_LABEL (state->base.warning),
3753 				    _("The output specification "
3754 				      "is invalid."));
3755 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
3756 		return;
3757 	}
3758 
3759 	gtk_label_set_text (GTK_LABEL (state->base.warning), "");
3760 	gtk_widget_set_sensitive (state->base.ok_button, TRUE);
3761 
3762 	return;
3763 }
3764 
3765 /**
3766  * dialog_anova_two_factor_tool:
3767  * @wbcg:
3768  * @sheet:
3769  *
3770  * Show the dialog (guru).
3771  *
3772  **/
3773 int
dialog_anova_two_factor_tool(WBCGtk * wbcg,Sheet * sheet)3774 dialog_anova_two_factor_tool (WBCGtk *wbcg, Sheet *sheet)
3775 {
3776         AnovaTwoFactorToolState *state;
3777 	char const * plugins[] = { "Gnumeric_fnstat",
3778 				   "Gnumeric_fnlookup",
3779 				   "Gnumeric_fnmath",
3780 				   "Gnumeric_fninfo",
3781 				   "Gnumeric_fnlogical",
3782 				   NULL};
3783 
3784 	if ((wbcg == NULL) ||
3785 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
3786 		return 1;
3787 
3788 	/* Only pop up one copy per workbook */
3789 	if (gnm_dialog_raise_if_exists (wbcg, ANOVA_TWO_FACTOR_KEY))
3790 		return 0;
3791 
3792 	state = g_new0 (AnovaTwoFactorToolState, 1);
3793 
3794 	if (dialog_tool_init (&state->base, wbcg, sheet,
3795 			      GNUMERIC_HELP_LINK_ANOVA_TWO_FACTOR,
3796 			      "res:ui/anova-two.ui", "ANOVA",
3797 			      _("Could not create the ANOVA (two factor) "
3798 				"tool dialog."),
3799 			      ANOVA_TWO_FACTOR_KEY,
3800 			      G_CALLBACK (anova_two_factor_tool_ok_clicked_cb),
3801 			      NULL,
3802 			      G_CALLBACK (anova_two_factor_tool_update_sensitivity_cb),
3803 			      GNM_EE_SINGLE_RANGE))
3804 	{
3805 		g_free(state);
3806 		return 0;
3807 	}
3808 
3809 	state->alpha_entry = go_gtk_builder_get_widget (state->base.gui,
3810 						   "alpha-entry");
3811 	float_to_entry (GTK_ENTRY(state->alpha_entry), 0.05);
3812 	state->replication_entry = go_gtk_builder_get_widget (state->base.gui,
3813 							 "replication-entry");
3814 	int_to_entry (GTK_ENTRY(state->replication_entry), 1);
3815 
3816 	g_signal_connect_after (G_OBJECT (state->alpha_entry),
3817 		"changed",
3818 		G_CALLBACK (anova_two_factor_tool_update_sensitivity_cb),
3819 				state);
3820 	g_signal_connect_after (G_OBJECT (state->replication_entry),
3821 		"changed",
3822 		G_CALLBACK (anova_two_factor_tool_update_sensitivity_cb),
3823 				state);
3824 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
3825 				  GTK_WIDGET (state->alpha_entry));
3826 	gnm_editable_enters (GTK_WINDOW (state->base.dialog),
3827 				  GTK_WIDGET (state->replication_entry));
3828 
3829 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
3830 	anova_two_factor_tool_update_sensitivity_cb (NULL, state);
3831 	tool_load_selection ((GnmGenericToolState *)state, FALSE);
3832 
3833         return 0;
3834 }
3835 
3836 /**********************************************/
3837 /*  End of ANOVA (Two Factor) tool code */
3838 /**********************************************/
3839