1 /*
2  * dialog-analysis-tool-sign-test.c:
3  *
4  * Authors:
5   *  Andreas J. Guelzow  <aguelzow@pyrshep.ca>
6  *
7  * (C) Copyright 2009-2010 by Andreas J. Guelzow  <aguelzow@pyrshep.ca>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <https://www.gnu.org/licenses/>.
21  */
22 
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <dialogs/dialogs.h>
27 #include <tools/analysis-sign-test.h>
28 #include <tools/analysis-signed-rank-test.h>
29 #include <tools/analysis-tools.h>
30 
31 #include <workbook.h>
32 #include <workbook-control.h>
33 #include <wbc-gtk.h>
34 #include <workbook-view.h>
35 #include <gui-util.h>
36 #include <parse-util.h>
37 #include <gnm-format.h>
38 #include <dialogs/tool-dialogs.h>
39 #include <dialogs/dao-gui-utils.h>
40 #include <sheet.h>
41 #include <expr.h>
42 #include <number-match.h>
43 #include <ranges.h>
44 #include <selection.h>
45 #include <value.h>
46 #include <commands.h>
47 #include <dialogs/help.h>
48 
49 #include <widgets/gnm-dao.h>
50 #include <widgets/gnm-expr-entry.h>
51 
52 #include <string.h>
53 
54 #define SIGN_TEST_KEY_ONE      "analysistools-sign-test-one-dialog"
55 #define SIGN_TEST_KEY_TWO      "analysistools-sign-test-two-dialog"
56 
57 static char const * const grouped_by_group[] = {
58 	"grouped_by_row",
59 	"grouped_by_col",
60 	"grouped_by_area",
61 	NULL
62 };
63 
64 typedef struct {
65 	GnmGenericToolState base;
66 	GtkWidget *alpha_entry;
67 	GtkWidget *median_entry;
68 } SignTestToolState;
69 
70 /**
71  * sign_test_tool_update_common_sensitivity_cb:
72  * @dummy:
73  * @state:
74  *
75  * Update the dialog widgets sensitivity
76  **/
77 static gboolean
sign_test_tool_update_common_sensitivity_cb(SignTestToolState * state)78 sign_test_tool_update_common_sensitivity_cb (SignTestToolState *state)
79 {
80 	gnm_float alpha;
81 	gnm_float median;
82 	gboolean err;
83 
84 	/* Checking Median*/
85 	err = entry_to_float
86 		(GTK_ENTRY (state->median_entry), &median, FALSE);
87 	if (err) {
88 		gtk_label_set_text (GTK_LABEL (state->base.warning),
89 				    _("The predicted median should be a number."));
90 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
91 		return FALSE;
92 	}
93 
94 	/* Checking Alpha*/
95 	alpha = gtk_spin_button_get_value
96 		(GTK_SPIN_BUTTON (state->alpha_entry));
97 	if (!(alpha > 0 && alpha < 1)) {
98 		gtk_label_set_text (GTK_LABEL (state->base.warning),
99 				    _("The alpha value should "
100 				      "be a number between 0 and 1."));
101 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
102 		return FALSE;
103 	}
104 
105 	/* Checking Output Page */
106 	if (!gnm_dao_is_ready (GNM_DAO (state->base.gdao))) {
107 		gtk_label_set_text (GTK_LABEL (state->base.warning),
108 				    _("The output specification "
109 				      "is invalid."));
110 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
111 		return FALSE;
112 	}
113 
114 	return TRUE;
115 }
116 
117 
118 /**
119  * sign_test_two_tool_update_sensitivity_cb:
120  * @dummy:
121  * @state:
122  *
123  * Update the dialog widgets sensitivity
124  **/
125 static void
sign_test_two_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,SignTestToolState * state)126 sign_test_two_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
127 					  SignTestToolState *state)
128 {
129         GnmValue *input_range;
130  	gint w, h;
131 
132 	/* Checking first input range*/
133         input_range = gnm_expr_entry_parse_as_value
134 		(GNM_EXPR_ENTRY (state->base.input_entry),
135 		 state->base.sheet);
136 	if (input_range == NULL || !VALUE_IS_CELLRANGE (input_range)) {
137 		gtk_label_set_text (GTK_LABEL (state->base.warning),
138 				    (state->base.input_entry_2 == NULL)
139 				    ? _("The input range is invalid.")
140 				    : _("The first input range is invalid."));
141 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
142 		value_release (input_range);
143 		return;
144 	} else {
145 		GnmRange r;
146 		range_init_rangeref (&r, &(input_range->v_range.cell));
147 		w = range_width (&r);
148 		h = range_height (&r);
149 		value_release (input_range);
150 	}
151 
152 	/* Checking second input range*/
153 	if (state->base.input_entry_2 != NULL) {
154 		input_range = gnm_expr_entry_parse_as_value
155 			(GNM_EXPR_ENTRY (state->base.input_entry_2),
156 			 state->base.sheet);
157 		if (input_range == NULL || !VALUE_IS_CELLRANGE (input_range)) {
158 			gtk_label_set_text (GTK_LABEL (state->base.warning),
159 					    _("The second input range is invalid."));
160 			gtk_widget_set_sensitive (state->base.ok_button, FALSE);
161 			value_release (input_range);
162 			return;
163 		} else {
164 			GnmRange r;
165 			range_init_rangeref (&r, &(input_range->v_range.cell));
166 			value_release (input_range);
167 			if (w != range_width (&r) ||
168 			    h != range_height (&r)) {
169 				gtk_label_set_text
170 					(GTK_LABEL (state->base.warning),
171 					 _("The input ranges do not have the same shape."));
172 				gtk_widget_set_sensitive
173 					(state->base.ok_button, FALSE);
174 			return;
175 
176 			}
177 		}
178 	}
179 
180 	if (sign_test_tool_update_common_sensitivity_cb (state)) {
181 		gtk_label_set_text (GTK_LABEL (state->base.warning), "");
182 		gtk_widget_set_sensitive (state->base.ok_button, TRUE);
183 	}
184 }
185 
186 static void
sign_test_two_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,SignTestToolState * state)187 sign_test_two_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
188 			      SignTestToolState *state)
189 {
190 	data_analysis_output_t  *dao;
191 	GtkWidget *w;
192 	analysis_tools_data_sign_test_two_t *data;
193 	analysis_tool_engine engine;
194 
195 	data = g_new0 (analysis_tools_data_sign_test_two_t, 1);
196 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
197 
198 	data->base.range_1 = gnm_expr_entry_parse_as_value
199 		(GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
200 
201 	data->base.range_2 = gnm_expr_entry_parse_as_value
202 		(GNM_EXPR_ENTRY (state->base.input_entry_2), state->base.sheet);
203 
204 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
205         data->base.labels = gtk_toggle_button_get_active
206 		(GTK_TOGGLE_BUTTON (w));
207 
208 	entry_to_float
209 		(GTK_ENTRY (state->median_entry), &data->median, FALSE);
210 
211 	data->base.alpha = gtk_spin_button_get_value
212 		(GTK_SPIN_BUTTON (state->alpha_entry));
213 
214 	w =  go_gtk_builder_get_widget (state->base.gui, "signtest");
215 	engine =  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))
216 		? analysis_tool_sign_test_two_engine
217 		: analysis_tool_signed_rank_test_two_engine;
218 
219 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg),
220 				state->base.sheet,
221 				dao, data, engine, TRUE))
222 		gtk_widget_destroy (state->base.dialog);
223 
224 	return;
225 }
226 
227 /**
228  * dialog_sign_test_two_tool:
229  *
230  **/
231 int
dialog_sign_test_two_tool(WBCGtk * wbcg,Sheet * sheet,signtest_type type)232 dialog_sign_test_two_tool (WBCGtk *wbcg, Sheet *sheet, signtest_type type)
233 {
234 	char const * plugins[] = { "Gnumeric_fnstat",
235 				   "Gnumeric_fnlogical",
236 				   "Gnumeric_fnmath",
237 				   "Gnumeric_fninfo",
238 				   NULL};
239         SignTestToolState *state;
240 	GtkWidget *w;
241 
242 	if ((wbcg == NULL) ||
243 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
244 		return 1;
245 
246 	/* Only pop up one copy per workbook */
247 	if (gnm_dialog_raise_if_exists (wbcg, SIGN_TEST_KEY_TWO))
248 		return 0;
249 
250 	state = g_new0 (SignTestToolState, 1);
251 
252 	if (dialog_tool_init (&state->base, wbcg, sheet,
253 			      GNUMERIC_HELP_LINK_SIGN_TEST_TWO,
254 			      "res:ui/sign-test-two.ui", "Sign-Test",
255 			      _("Could not create the Sign Test Tool dialog."),
256 			      SIGN_TEST_KEY_TWO,
257 			      G_CALLBACK (sign_test_two_tool_ok_clicked_cb),
258 			      NULL,
259 			      G_CALLBACK (sign_test_two_tool_update_sensitivity_cb),
260 			      GNM_EE_SINGLE_RANGE))
261 	{
262 		g_free(state);
263 		return 0;
264 	}
265 
266 
267 	state->alpha_entry = tool_setup_update
268 		(&state->base, "alpha-entry",
269 		 G_CALLBACK (sign_test_two_tool_update_sensitivity_cb),
270 		 state);
271 	float_to_entry (GTK_ENTRY (state->alpha_entry), 0.05);
272 
273 	state->median_entry = tool_setup_update
274 		(&state->base, "median-entry",
275 		 G_CALLBACK (sign_test_two_tool_update_sensitivity_cb),
276 		 state);
277 	int_to_entry (GTK_ENTRY (state->median_entry), 0);
278 
279 	w =  go_gtk_builder_get_widget (state->base.gui,
280 				   (type == SIGNTEST) ? "signtest"
281 				   : "signedranktest");
282 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE);
283 
284 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
285 	sign_test_two_tool_update_sensitivity_cb (NULL, state);
286 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
287 
288 	return 0;
289 
290 }
291 
292 /************************************************************************************/
293 
294 /**
295  * sign_test_tool_ok_clicked_cb:
296  * @button:
297  * @state:
298  *
299  * Retrieve the information from the dialog and call the sign_test_tool.
300  * Note that we assume that the ok_button is only active if the entry fields
301  * contain sensible data.
302  **/
303 static void
sign_test_tool_ok_clicked_cb(G_GNUC_UNUSED GtkWidget * button,SignTestToolState * state)304 sign_test_tool_ok_clicked_cb (G_GNUC_UNUSED GtkWidget *button,
305 			      SignTestToolState *state)
306 {
307 	data_analysis_output_t  *dao;
308 	GtkWidget *w;
309 	analysis_tools_data_sign_test_t *data;
310 	analysis_tool_engine engine;
311 
312 	data = g_new0 (analysis_tools_data_sign_test_t, 1);
313 	dao  = parse_output ((GnmGenericToolState *)state, NULL);
314 
315 	data->base.input = gnm_expr_entry_parse_as_list (
316 		GNM_EXPR_ENTRY (state->base.input_entry), state->base.sheet);
317 	data->base.group_by = gnm_gui_group_value (state->base.gui, grouped_by_group);
318 
319 	w = go_gtk_builder_get_widget (state->base.gui, "labels_button");
320         data->base.labels = gtk_toggle_button_get_active
321 		(GTK_TOGGLE_BUTTON (w));
322 
323 	entry_to_float
324 		(GTK_ENTRY (state->median_entry), &data->median, FALSE);
325 	data->alpha = gtk_spin_button_get_value
326 		(GTK_SPIN_BUTTON (state->alpha_entry));
327 
328 	w =  go_gtk_builder_get_widget (state->base.gui, "signtest");
329 	engine =  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w))
330 		? analysis_tool_sign_test_engine
331 		: analysis_tool_signed_rank_test_engine;
332 
333 	if (!cmd_analysis_tool (GNM_WBC (state->base.wbcg),
334 				state->base.sheet,
335 				dao, data, engine, TRUE))
336 		gtk_widget_destroy (state->base.dialog);
337 
338 	return;
339 }
340 
341 /**
342  * sign_test_tool_update_sensitivity_cb:
343  * @dummy:
344  * @state:
345  *
346  * Update the dialog widgets sensitivity
347  **/
348 static void
sign_test_tool_update_sensitivity_cb(G_GNUC_UNUSED GtkWidget * dummy,SignTestToolState * state)349 sign_test_tool_update_sensitivity_cb (G_GNUC_UNUSED GtkWidget *dummy,
350 				      SignTestToolState *state)
351 {
352         GSList *input_range;
353 
354 	/* Checking first input range*/
355         input_range = gnm_expr_entry_parse_as_list
356 		(GNM_EXPR_ENTRY (state->base.input_entry),
357 		 state->base.sheet);
358 	if (input_range == NULL) {
359 		gtk_label_set_text (GTK_LABEL (state->base.warning),
360 				    (state->base.input_entry_2 == NULL)
361 				    ? _("The input range is invalid.")
362 				    : _("The first input range is invalid."));
363 		gtk_widget_set_sensitive (state->base.ok_button, FALSE);
364 		return;
365 	} else
366 		range_list_destroy (input_range);
367 
368 	if (sign_test_tool_update_common_sensitivity_cb (state)) {
369 		gtk_label_set_text (GTK_LABEL (state->base.warning), "");
370 		gtk_widget_set_sensitive (state->base.ok_button, TRUE);
371 	}
372 
373 }
374 
375 /**
376  * dialog_sign_test_tool:
377  *
378  **/
379 int
dialog_sign_test_tool(WBCGtk * wbcg,Sheet * sheet,signtest_type type)380 dialog_sign_test_tool (WBCGtk *wbcg, Sheet *sheet, signtest_type type)
381 {
382 	char const * plugins[] = { "Gnumeric_fnstat",
383 				   "Gnumeric_fnlogical",
384 				   "Gnumeric_fnmath",
385 				   "Gnumeric_fninfo",
386 				   NULL};
387         SignTestToolState *state;
388 	GtkWidget *w;
389 
390 	if ((wbcg == NULL) ||
391 	    gnm_check_for_plugins_missing (plugins, wbcg_toplevel (wbcg)))
392 		return 1;
393 
394 	/* Only pop up one copy per workbook */
395 	if (gnm_dialog_raise_if_exists (wbcg, SIGN_TEST_KEY_ONE))
396 		return 0;
397 
398 	state = g_new0 (SignTestToolState, 1);
399 
400 	if (dialog_tool_init (&state->base, wbcg, sheet,
401 			      GNUMERIC_HELP_LINK_SIGN_TEST,
402 			      "res:ui/sign-test.ui", "Sign-Test",
403 			      _("Could not create the Sign Test Tool dialog."),
404 			      SIGN_TEST_KEY_ONE,
405 			      G_CALLBACK (sign_test_tool_ok_clicked_cb),
406 			      NULL,
407 			      G_CALLBACK (sign_test_tool_update_sensitivity_cb),
408 			      0))
409 	{
410 		g_free(state);
411 		return 0;
412 	}
413 
414 
415 	state->alpha_entry = tool_setup_update
416 		(&state->base, "alpha-entry",
417 		 G_CALLBACK (sign_test_two_tool_update_sensitivity_cb),
418 		 state);
419 	state->median_entry = tool_setup_update
420 		(&state->base, "median-entry",
421 		 G_CALLBACK (sign_test_two_tool_update_sensitivity_cb),
422 		 state);
423 
424 	int_to_entry (GTK_ENTRY (state->median_entry), 0);
425 	float_to_entry (GTK_ENTRY (state->alpha_entry), 0.05);
426 
427 	w =  go_gtk_builder_get_widget (state->base.gui,
428 				   (type == SIGNTEST) ? "signtest"
429 				   : "signedranktest");
430 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), TRUE);
431 
432 	gnm_dao_set_put (GNM_DAO (state->base.gdao), TRUE, TRUE);
433 	sign_test_tool_update_sensitivity_cb (NULL, state);
434 	tool_load_selection ((GnmGenericToolState *)state, TRUE);
435 
436 	return 0;
437 
438 }
439