Remove unnecessary dependencies on gtksheet.h
[pspp-builds.git] / src / ui / gui / t-test-independent-samples-dialog.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 #include <config.h>
20 #include <glade/glade.h>
21 #include <gtk/gtk.h>
22 #include "t-test-independent-samples-dialog.h"
23 #include "psppire-dict.h"
24 #include "psppire-var-store.h"
25 #include "helper.h"
26 #include "data-editor.h"
27 #include "psppire-dialog.h"
28 #include "dialog-common.h"
29 #include "dict-display.h"
30 #include "widget-io.h"
31 #include "t-test-options.h"
32 #include <libpspp/syntax-gen.h>
33
34 #include <language/syntax-string-source.h>
35 #include "syntax-editor.h"
36
37 #include <gl/xalloc.h>
38
39 #include <gettext.h>
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) msgid
42
43
44 enum group_definition
45   {
46     GROUPS_UNDEF,
47     GROUPS_VALUES,
48     GROUPS_CUT_POINT
49   };
50
51 struct tt_groups_dialog
52 {
53   GtkWidget *dialog;
54   GtkWidget *label;
55   GtkWidget *table1;
56   GtkWidget *table2;
57   GtkWidget *hbox1;
58
59   GtkWidget *values_toggle_button;
60   GtkWidget *cut_point_toggle_button;
61
62   GtkWidget *grp_entry[2];
63   GtkWidget *cut_point_entry;
64
65   enum group_definition group_defn;
66   gchar *val[2];
67 };
68
69 static void
70 set_group_criterion_type (GtkToggleButton *button,
71                           struct tt_groups_dialog *groups)
72 {
73   gboolean by_values = gtk_toggle_button_get_active (button);
74
75   gtk_widget_set_sensitive (groups->label, by_values);
76   gtk_widget_set_sensitive (groups->table2, by_values);
77
78   gtk_widget_set_sensitive (groups->hbox1, !by_values);
79 }
80
81 static void
82 tt_groups_dialog_destroy (struct tt_groups_dialog *grps)
83 {
84   g_object_unref (grps->table1);
85   g_object_unref (grps->table2);
86
87   g_free (grps->val[0]);
88   g_free (grps->val[1]);
89
90   g_free (grps);
91 }
92
93 static struct tt_groups_dialog *
94 tt_groups_dialog_create (GladeXML *xml, GtkWindow *parent)
95 {
96   struct tt_groups_dialog *grps = xmalloc (sizeof (*grps));
97
98   grps->group_defn = GROUPS_UNDEF;
99
100   grps->dialog = get_widget_assert (xml, "define-groups-dialog");
101   grps->table1 = get_widget_assert (xml, "table1");
102   grps->table2 = get_widget_assert (xml, "table2");
103   grps->label  = get_widget_assert (xml, "label4");
104   grps->hbox1  = get_widget_assert (xml, "hbox1");
105
106   grps->grp_entry[0] = get_widget_assert (xml, "group1-entry");
107   grps->grp_entry[1] = get_widget_assert (xml, "group2-entry");
108   grps->cut_point_entry = get_widget_assert (xml, "cut-point-entry");
109
110   grps->cut_point_toggle_button = get_widget_assert (xml, "radiobutton4");
111   grps->values_toggle_button = get_widget_assert (xml, "radiobutton3");
112
113   g_object_ref (grps->table1);
114   g_object_ref (grps->table2);
115
116   g_signal_connect (grps->values_toggle_button, "toggled",
117                     G_CALLBACK (set_group_criterion_type), grps);
118
119   gtk_window_set_transient_for (GTK_WINDOW (grps->dialog), parent);
120
121   grps->val[0] = strdup ("");
122   grps->val[1] = strdup ("");
123
124   return grps;
125 }
126
127
128 struct tt_indep_samples_dialog
129 {
130   GladeXML *xml;  /* The xml that generated the widgets */
131   GtkWidget *dialog;
132   PsppireDict *dict;
133   GtkWidget *define_groups_button;
134   GtkWidget *groups_entry;
135
136   struct tt_groups_dialog *grps;
137   struct tt_options_dialog *opts;
138 };
139
140
141 static void
142 set_define_groups_sensitivity (GtkEntry *entry,
143                                struct tt_indep_samples_dialog *tt_d)
144 {
145   const gchar *text = gtk_entry_get_text (entry);
146
147   const struct variable *v = psppire_dict_lookup_var (tt_d->dict, text);
148
149   gtk_widget_set_sensitive (tt_d->define_groups_button, v != NULL);
150 }
151
152
153 static gchar *
154 generate_syntax (const struct tt_indep_samples_dialog *d)
155 {
156   struct variable *group_variable;
157   gchar *text;
158
159   GtkWidget *tv =
160     get_widget_assert (d->xml, "indep-samples-t-test-treeview2");
161
162   GString *str = g_string_new ("T-TEST /VARIABLES=");
163
164   append_variable_names (str, d->dict, GTK_TREE_VIEW (tv), 0);
165
166   g_string_append (str, "\n\t/GROUPS=");
167
168   group_variable =
169     psppire_dict_lookup_var (d->dict,
170                              gtk_entry_get_text (GTK_ENTRY (d->groups_entry)));
171
172   g_string_append (str, var_get_name (group_variable));
173
174   if (d->grps->group_defn != GROUPS_UNDEF)
175     {
176       g_string_append (str, "(");
177
178       if ( var_is_alpha (group_variable))
179         {
180           struct string s;
181           ds_init_cstr (&s, d->grps->val[0]);
182           gen_quoted_string (&s);
183           g_string_append (str, ds_cstr (&s));
184           ds_destroy (&s);
185         }
186       else
187         {
188           g_string_append (str, d->grps->val[0]);
189         }
190
191       if ( d->grps->group_defn == GROUPS_VALUES )
192         {
193           g_string_append (str, ",");
194
195           if ( var_is_alpha (group_variable))
196             {
197               struct string s;
198               ds_init_cstr (&s, d->grps->val[1]);
199               gen_quoted_string (&s);
200               g_string_append (str, ds_cstr (&s));
201               ds_destroy (&s);
202             }
203           else
204             {
205               g_string_append (str, d->grps->val[1]);
206             }
207         }
208
209       g_string_append (str, ")");
210     }
211
212   tt_options_dialog_append_syntax (d->opts, str);
213
214   g_string_append (str, ".\n");
215
216   text = str->str;
217
218   g_string_free (str, FALSE);
219
220   return text;
221 }
222
223 static void
224 refresh (struct tt_indep_samples_dialog *ttd)
225 {
226   GtkWidget *tv =
227     get_widget_assert (ttd->xml, "indep-samples-t-test-treeview2");
228
229   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tv));
230
231   gtk_entry_set_text (GTK_ENTRY (ttd->groups_entry), "");
232
233   gtk_list_store_clear (GTK_LIST_STORE (model));
234
235   gtk_widget_set_sensitive (ttd->define_groups_button, FALSE);
236 }
237
238
239 /* Returns TRUE iff the define groups subdialog has a
240    state which defines a valid group criterion */
241 static gboolean
242 define_groups_state_valid (gpointer data)
243 {
244   struct tt_groups_dialog *d = data;
245
246   if ( gtk_toggle_button_get_active
247        (GTK_TOGGLE_BUTTON (d->values_toggle_button)))
248     {
249       if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (d->grp_entry[0]))))
250         return FALSE;
251
252       if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (d->grp_entry[1]))))
253         return FALSE;
254     }
255   else
256     {
257       if ( 0 == strcmp ("",
258                         gtk_entry_get_text (GTK_ENTRY (d->cut_point_entry))))
259         return FALSE;
260     }
261
262   return TRUE;
263 }
264
265 static void
266 run_define_groups (struct tt_indep_samples_dialog *ttd)
267 {
268   struct tt_groups_dialog *grps = ttd->grps;
269
270   gint response;
271
272   GtkWidget *box = get_widget_assert (ttd->xml, "dialog-hbox2");
273
274   const gchar *text = gtk_entry_get_text (GTK_ENTRY (ttd->groups_entry));
275
276   const struct variable *v = psppire_dict_lookup_var (ttd->dict, text);
277
278   if ( grps->table2->parent)
279     gtk_container_remove (GTK_CONTAINER (grps->table2->parent), grps->table2);
280
281   if ( grps->table1->parent)
282     gtk_container_remove (GTK_CONTAINER (grps->table1->parent), grps->table1);
283
284
285   if ( var_is_numeric (v))
286     {
287       gtk_table_attach_defaults (GTK_TABLE (grps->table1), grps->table2,
288                                  1, 2, 1, 2);
289
290       gtk_container_add (GTK_CONTAINER (box), grps->table1);
291     }
292   else
293     {
294       gtk_container_add (GTK_CONTAINER (box), grps->table2);
295       grps->group_defn = GROUPS_VALUES;
296     }
297
298
299   psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (grps->dialog),
300                                       define_groups_state_valid, grps);
301
302   if ( grps->group_defn != GROUPS_CUT_POINT )
303     {
304       gtk_toggle_button_set_active
305         (GTK_TOGGLE_BUTTON (grps->cut_point_toggle_button), TRUE);
306
307       gtk_toggle_button_set_active
308         (GTK_TOGGLE_BUTTON (grps->values_toggle_button), TRUE);
309
310       gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[0]), grps->val[0]);
311       gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[1]), grps->val[1]);
312
313       gtk_entry_set_text (GTK_ENTRY (grps->cut_point_entry), "");
314     }
315   else
316     {
317       gtk_toggle_button_set_active
318         (GTK_TOGGLE_BUTTON (grps->values_toggle_button), TRUE);
319
320       gtk_toggle_button_set_active
321         (GTK_TOGGLE_BUTTON (grps->cut_point_toggle_button), TRUE);
322
323       gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[0]), "");
324       gtk_entry_set_text (GTK_ENTRY (grps->grp_entry[1]), "");
325
326       gtk_entry_set_text (GTK_ENTRY (grps->cut_point_entry), grps->val[0]);
327     }
328
329   g_signal_emit_by_name (grps->grp_entry[0], "changed");
330   g_signal_emit_by_name (grps->grp_entry[1], "changed");
331   g_signal_emit_by_name (grps->cut_point_entry, "changed");
332
333   response = psppire_dialog_run (PSPPIRE_DIALOG (grps->dialog));
334
335   if (response == PSPPIRE_RESPONSE_CONTINUE)
336     {
337       g_free (grps->val[0]);
338       g_free (grps->val[1]);
339
340       if (gtk_toggle_button_get_active
341           (GTK_TOGGLE_BUTTON (grps->values_toggle_button)))
342         {
343           grps->group_defn = GROUPS_VALUES;
344
345           grps->val[0] =
346             strdup (gtk_entry_get_text (GTK_ENTRY (grps->grp_entry[0])));
347
348           grps->val[1] =
349             strdup (gtk_entry_get_text (GTK_ENTRY (grps->grp_entry[1])));
350         }
351       else
352         {
353           grps->group_defn = GROUPS_CUT_POINT;
354
355           grps->val[1] = NULL;
356
357           grps->val[0] =
358             strdup (gtk_entry_get_text (GTK_ENTRY (grps->cut_point_entry)));
359         }
360
361       psppire_dialog_notify_change (PSPPIRE_DIALOG (ttd->dialog));
362     }
363 }
364
365
366
367 static gboolean
368 dialog_state_valid (gpointer data)
369 {
370   struct tt_indep_samples_dialog *tt_d = data;
371
372   GtkWidget *tv_vars =
373     get_widget_assert (tt_d->xml, "indep-samples-t-test-treeview2");
374
375   GtkTreeModel *vars = gtk_tree_view_get_model (GTK_TREE_VIEW (tv_vars));
376
377   GtkTreeIter notused;
378
379   if ( 0 == strcmp ("", gtk_entry_get_text (GTK_ENTRY (tt_d->groups_entry))))
380     return FALSE;
381
382   if ( 0 == gtk_tree_model_get_iter_first (vars, &notused))
383     return FALSE;
384
385   if ( tt_d->grps->group_defn == GROUPS_UNDEF)
386     return FALSE;
387
388   return TRUE;
389 }
390
391 /* Pops up the dialog box */
392 void
393 t_test_independent_samples_dialog (GObject *o, gpointer data)
394 {
395   struct tt_indep_samples_dialog tt_d;
396   gint response;
397   struct data_editor *de = data;
398
399   PsppireVarStore *vs = NULL;
400
401   GladeXML *xml = XML_NEW ("t-test.glade");
402
403   GtkWidget *dict_view =
404     get_widget_assert (xml, "indep-samples-t-test-treeview1");
405
406   GtkWidget *test_variables_treeview =
407     get_widget_assert (xml, "indep-samples-t-test-treeview2");
408
409   GtkWidget *selector2 =
410     get_widget_assert (xml, "indep-samples-t-test-selector2");
411
412   GtkWidget *selector1 =
413     get_widget_assert (xml, "indep-samples-t-test-selector1");
414
415   GtkWidget *options_button =
416     get_widget_assert (xml, "indep-samples-t-test-options-button");
417
418   g_object_get (de->data_editor, "var-store", &vs, NULL);
419
420   tt_d.dialog = get_widget_assert (xml, "t-test-independent-samples-dialog");
421   tt_d.xml = xml;
422   tt_d.dict = vs->dict;
423
424   tt_d.define_groups_button = get_widget_assert (xml, "define-groups-button");
425   tt_d.groups_entry = get_widget_assert (xml, "indep-samples-t-test-entry");
426   tt_d.opts = tt_options_dialog_create (xml, de->parent.window);
427   tt_d.grps = tt_groups_dialog_create (xml, de->parent.window);
428
429
430   gtk_window_set_transient_for (GTK_WINDOW (tt_d.dialog), de->parent.window);
431
432   attach_dictionary_to_treeview (GTK_TREE_VIEW (dict_view),
433                                  vs->dict,
434                                  GTK_SELECTION_MULTIPLE, NULL);
435
436   set_dest_model (GTK_TREE_VIEW (test_variables_treeview), vs->dict);
437
438
439   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector1),
440                                  dict_view, test_variables_treeview,
441                                  insert_source_row_into_tree_view,
442                                  NULL,
443                                  NULL);
444
445   psppire_selector_set_allow (PSPPIRE_SELECTOR (selector1),
446                               numeric_only);
447
448
449   psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector2),
450                                  dict_view, tt_d.groups_entry,
451                                  insert_source_row_into_entry,
452                                  is_currently_in_entry,
453                                  NULL);
454
455   g_signal_connect_swapped (tt_d.define_groups_button, "clicked",
456                             G_CALLBACK (run_define_groups), &tt_d);
457
458
459   g_signal_connect_swapped (options_button, "clicked",
460                             G_CALLBACK (tt_options_dialog_run), tt_d.opts);
461
462
463   g_signal_connect_swapped (tt_d.dialog, "refresh", G_CALLBACK (refresh),
464                             &tt_d);
465
466   g_signal_connect (tt_d.groups_entry, "changed",
467                     G_CALLBACK (set_define_groups_sensitivity), &tt_d);
468
469
470   psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (tt_d.dialog),
471                                       dialog_state_valid, &tt_d);
472
473   response = psppire_dialog_run (PSPPIRE_DIALOG (tt_d.dialog));
474
475   switch (response)
476     {
477     case GTK_RESPONSE_OK:
478       {
479         gchar *syntax = generate_syntax (&tt_d);
480         struct getl_interface *sss = create_syntax_string_source (syntax);
481         execute_syntax (sss);
482
483         g_free (syntax);
484       }
485       break;
486     case PSPPIRE_RESPONSE_PASTE:
487       {
488         gchar *syntax = generate_syntax (&tt_d);
489
490         struct syntax_editor *se =
491           (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL);
492
493         gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1);
494
495         g_free (syntax);
496       }
497       break;
498     default:
499       break;
500     }
501
502   tt_options_dialog_destroy (tt_d.opts);
503   tt_groups_dialog_destroy (tt_d.grps);
504
505   g_object_unref (xml);
506 }
507
508