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