Remove unnecessary dependencies on gtksheet.h
[pspp-builds.git] / src / ui / gui / select-cases-dialog.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2007  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 #include <config.h>
21
22 #include "select-cases-dialog.h"
23 #include <gtk/gtk.h>
24 #include <glade/glade.h>
25 #include "helper.h"
26 #include "psppire-dialog.h"
27 #include "data-editor.h"
28 #include "dialog-common.h"
29 #include "dict-display.h"
30 #include "widget-io.h"
31 #include <language/syntax-string-source.h>
32 #include "syntax-editor.h"
33
34
35 #include <gettext.h>
36 #define _(msgid) gettext (msgid)
37 #define N_(msgid) msgid
38
39
40
41 /* FIXME: These shouldn't be here */
42 #include "psppire-data-store.h"
43
44
45 struct select_cases_dialog
46 {
47   /* The XML that created the dialog */
48   GladeXML *xml;
49
50   GtkWidget *spinbutton ;
51   GtkWidget *spinbutton1 ;
52   GtkWidget *spinbutton2 ;
53
54   GtkWidget *hbox1;
55   GtkWidget *hbox2;
56
57   PsppireDataStore *data_store;
58 };
59
60 static gchar * generate_syntax (const struct select_cases_dialog *scd);
61
62
63 static void
64 set_sensitivity_from_toggle (GtkToggleButton *togglebutton,  gpointer data)
65 {
66   GtkWidget *w = data;
67   gboolean active = gtk_toggle_button_get_active (togglebutton);
68
69   gtk_widget_set_sensitive (w, active);
70 }
71
72 static void
73 set_sensitivity_from_toggle_invert (GtkToggleButton *togglebutton,
74                                     gpointer data)
75 {
76   GtkWidget *w = data;
77   gboolean active = gtk_toggle_button_get_active (togglebutton);
78
79   gtk_widget_set_sensitive (w, !active);
80 }
81
82
83
84 static const gchar label1[]=N_("Approximately %3d%% of all cases.");
85 static const gchar label2[]=N_("Exactly %3d cases from the first %3d cases.");
86
87
88 static void
89 sample_subdialog (GtkButton *b, gpointer data)
90 {
91   gint response;
92   struct select_cases_dialog *scd = data;
93
94   gint case_count = psppire_data_store_get_case_count (scd->data_store);
95
96   GtkWidget *parent_dialog = get_widget_assert (scd->xml,
97                                                 "select-cases-dialog");
98   GtkWidget *dialog = get_widget_assert (scd->xml,
99                                          "select-cases-random-sample-dialog");
100   GtkWidget *percent = get_widget_assert (scd->xml,
101                                           "radiobutton-sample-percent");
102   GtkWidget *sample_n_cases = get_widget_assert (scd->xml,
103                                                  "radiobutton-sample-n-cases");
104   GtkWidget *table = get_widget_assert (scd->xml,
105                                         "select-cases-random-sample-table");
106
107   if ( ! scd->hbox1 )
108     {
109       scd->hbox1 = widget_scanf (gettext (label1), &scd->spinbutton);
110
111       gtk_widget_show (scd->hbox1);
112
113       gtk_table_attach_defaults (GTK_TABLE (table),
114                                  scd->hbox1, 1, 2, 0, 1);
115
116       g_signal_connect (G_OBJECT (percent), "toggled",
117                         G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
118
119       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
120     }
121
122
123   if ( ! scd->hbox2 )
124     {
125       scd->hbox2 =
126         widget_scanf (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
127
128       gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
129                                  1, case_count);
130
131       gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
132                                  1, case_count);
133
134       gtk_widget_show (scd->hbox2);
135       gtk_widget_set_sensitive (scd->hbox2, FALSE);
136
137       gtk_table_attach_defaults (GTK_TABLE (table),
138                                  scd->hbox2, 1, 2, 1, 2);
139
140       g_signal_connect (G_OBJECT (sample_n_cases), "toggled",
141                         G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
142
143       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
144     }
145
146
147   gtk_window_set_transient_for (GTK_WINDOW (dialog),
148                                 GTK_WINDOW (parent_dialog));
149
150   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
151
152   if ( response != PSPPIRE_RESPONSE_CONTINUE)
153     {
154       g_signal_handlers_disconnect_by_func
155         (G_OBJECT (percent),
156          G_CALLBACK (set_sensitivity_from_toggle),
157          scd->hbox1);
158
159       g_signal_handlers_disconnect_by_func
160         (G_OBJECT (sample_n_cases),
161          G_CALLBACK (set_sensitivity_from_toggle),
162          scd->hbox2);
163
164       gtk_widget_destroy(scd->hbox1);
165       gtk_widget_destroy(scd->hbox2);
166       scd->hbox1 = scd->hbox2 = NULL;
167     }
168   else
169     {
170       gchar *text;
171       GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
172
173       if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
174         {
175           text = widget_printf (gettext(label1), scd->spinbutton);
176           gtk_label_set_text (GTK_LABEL (l0), text);
177         }
178       else
179         {
180           text =
181             widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
182           gtk_label_set_text (GTK_LABEL (l0), text);
183
184         }
185       g_free (text);
186
187     }
188 }
189
190 static void
191 range_subdialog (GtkButton *b, gpointer data)
192 {
193   gint response;
194   struct select_cases_dialog *scd = data;
195
196   gint n_cases = psppire_data_store_get_case_count (scd->data_store);
197
198   GtkWidget *parent_dialog = get_widget_assert (scd->xml,
199                                                 "select-cases-dialog");
200
201   GtkWidget *dialog = get_widget_assert (scd->xml,
202                                          "select-cases-range-dialog");
203
204   GtkWidget *first = get_widget_assert (scd->xml,
205                                         "range-dialog-first");
206
207   GtkWidget *last = get_widget_assert (scd->xml,
208                                         "range-dialog-last");
209
210
211   gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
212
213   gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
214
215   gtk_window_set_transient_for (GTK_WINDOW (dialog),
216                                 GTK_WINDOW (parent_dialog));
217
218
219   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
220   if ( response == PSPPIRE_RESPONSE_CONTINUE)
221     {
222       GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
223       GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
224       GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
225       gchar *text = widget_printf (_("%d thru %d"), first, last);
226
227       gtk_label_set_text (GTK_LABEL (l1), text);
228
229       g_free (text);
230     }
231 }
232
233 static void
234 set_radiobutton (GtkWidget *button, gpointer data)
235 {
236   GtkToggleButton *toggle = data;
237   gtk_toggle_button_set_active (toggle, TRUE);
238 }
239
240 /* Pops up the Select Cases dialog box */
241 void
242 select_cases_dialog (GObject *o, gpointer data)
243 {
244   gint response;
245   struct select_cases_dialog scd = {0,0,0,0,0,0};
246   GtkWidget *dialog   ;
247   struct data_editor *de = data;
248   GtkWidget *entry = NULL;
249   GtkWidget *selector ;
250   GtkWidget *button_range;
251   GtkWidget *button_sample;
252
253   scd.xml = XML_NEW ("psppire.glade");
254
255   g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
256
257   button_range = get_widget_assert (scd.xml, "button-range");
258   button_sample = get_widget_assert (scd.xml, "button-sample");
259   entry = get_widget_assert (scd.xml, "filter-variable-entry");
260   selector = get_widget_assert (scd.xml, "psppire-selector-filter");
261
262   {
263     GtkWidget *button_if =
264       get_widget_assert (scd.xml, "button-if");
265
266     GtkWidget *radiobutton_if =
267       get_widget_assert (scd.xml, "radiobutton-if");
268
269     GtkWidget *radiobutton_all =
270       get_widget_assert (scd.xml, "radiobutton-all");
271
272     GtkWidget *radiobutton_sample =
273       get_widget_assert (scd.xml, "radiobutton-sample");
274
275     GtkWidget *radiobutton_range =
276       get_widget_assert (scd.xml, "radiobutton-range");
277
278     GtkWidget *radiobutton_filter =
279       get_widget_assert (scd.xml, "radiobutton-filter-variable");
280
281     GtkWidget *range_label =
282       get_widget_assert (scd.xml, "range-sample-label");
283
284     GtkWidget *sample_label =
285       get_widget_assert (scd.xml, "random-sample-label");
286
287     g_signal_connect (radiobutton_all, "toggled",
288                       G_CALLBACK (set_sensitivity_from_toggle_invert),
289                       get_widget_assert (scd.xml, "filter-delete-button-box")
290                       );
291
292     g_signal_connect (button_if, "clicked",
293                       G_CALLBACK (set_radiobutton), radiobutton_if);
294
295     g_signal_connect (button_sample, "clicked",
296                       G_CALLBACK (set_radiobutton), radiobutton_sample);
297
298     g_signal_connect (button_range,  "clicked",
299                       G_CALLBACK (set_radiobutton), radiobutton_range);
300
301     g_signal_connect (selector, "clicked",
302                       G_CALLBACK (set_radiobutton), radiobutton_filter);
303
304     g_signal_connect (selector, "selected",
305                       G_CALLBACK (set_radiobutton), radiobutton_filter);
306
307     g_signal_connect (radiobutton_range, "toggled",
308                       G_CALLBACK (set_sensitivity_from_toggle),
309                       range_label
310                       );
311
312     g_signal_connect (radiobutton_sample, "toggled",
313                       G_CALLBACK (set_sensitivity_from_toggle),
314                       sample_label
315                       );
316
317     g_signal_connect (radiobutton_filter, "toggled",
318                       G_CALLBACK (set_sensitivity_from_toggle),
319                       entry
320                       );
321   }
322
323
324
325   dialog = get_widget_assert (scd.xml, "select-cases-dialog");
326   gtk_window_set_transient_for (GTK_WINDOW (dialog), de->parent.window);
327
328   {
329     GtkWidget *source = get_widget_assert   (scd.xml, "select-cases-treeview");
330
331     attach_dictionary_to_treeview (GTK_TREE_VIEW (source),
332                                    scd.data_store->dict,
333                                    GTK_SELECTION_SINGLE, NULL);
334
335     psppire_selector_set_subjects (PSPPIRE_SELECTOR (selector),
336                                    source,
337                                    entry,
338                                    insert_source_row_into_entry,
339                                    is_currently_in_entry,
340                                    NULL);
341   }
342
343
344
345   g_signal_connect (button_range,
346                     "clicked", G_CALLBACK (range_subdialog), &scd);
347
348
349   g_signal_connect (button_sample,
350                     "clicked", G_CALLBACK (sample_subdialog), &scd);
351
352
353   response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
354
355   switch (response)
356     {
357     case GTK_RESPONSE_OK:
358       {
359         gchar *syntax = generate_syntax (&scd);
360         struct getl_interface *sss = create_syntax_string_source (syntax);
361         execute_syntax (sss);
362
363         g_free (syntax);
364       }
365       break;
366     case PSPPIRE_RESPONSE_PASTE:
367       {
368         gchar *syntax = generate_syntax (&scd);
369
370         struct syntax_editor *se =
371           (struct syntax_editor *) window_create (WINDOW_SYNTAX, NULL);
372
373         gtk_text_buffer_insert_at_cursor (se->buffer, syntax, -1);
374
375         g_free (syntax);
376       }
377       break;
378     default:
379       break;
380     }
381
382   g_object_unref (scd.xml);
383 }
384
385
386 static gchar *
387 generate_syntax (const struct select_cases_dialog *scd)
388 {
389   gchar *text = NULL;
390   GString *string = NULL;
391
392   if ( gtk_toggle_button_get_active
393        (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
394                                               "radiobutton-all"))))
395     {
396       return strdup ("\n");
397     }
398
399   string = g_string_new ("");
400
401   if ( gtk_toggle_button_get_active
402        (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
403                                               "radiobutton-sample"))))
404   {
405     GtkWidget *random_sample =
406       get_widget_assert (scd->xml,
407                          "radiobutton-sample-percent");
408
409     g_string_append (string, "SAMPLE ");
410
411     if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
412       {
413         const double percentage =
414           gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
415         g_string_append_printf (string, "%g.", percentage / 100.0);
416       }
417     else
418       {
419         const gint n_cases =
420           gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
421         const gint from_n_cases =
422           gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
423
424         g_string_append_printf (string, "%d FROM %d .", n_cases, from_n_cases);
425       }
426
427   }
428   else if ( gtk_toggle_button_get_active
429             (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
430                                                    "radiobutton-range"))))
431     {
432       GtkSpinButton *first =
433         GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
434                                            "range-dialog-first"));
435
436       GtkSpinButton *last =
437         GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
438                                            "range-dialog-last"));
439
440       g_string_append_printf (string,
441                               "COMPUTE filter_$ = ($CASENUM >= %ld "
442                                "AND $CASENUM <= %ld).\n",
443                               (long) gtk_spin_button_get_value (first),
444                               (long) gtk_spin_button_get_value (last)
445                               );
446       g_string_append (string, "EXECUTE.\n");
447       g_string_append_printf (string, "SELECT IF filter_$.\n");
448
449     }
450   else if ( gtk_toggle_button_get_active
451             (GTK_TOGGLE_BUTTON
452              (get_widget_assert (scd->xml,
453                                  "radiobutton-filter-variable"))))
454     {
455       GtkEntry *entry =
456         GTK_ENTRY (get_widget_assert (scd->xml,
457                                       "filter-variable-entry"));
458
459       g_string_append_printf (string, "SELECT IF (%s <> 0).",
460                               gtk_entry_get_text (entry));
461     }
462
463
464   g_string_append (string, "\n");
465
466
467   /* Are we filtering or deleting ? */
468   if ( gtk_toggle_button_get_active
469        (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
470                                               "radiobutton-delete"))))
471     {
472       g_string_append (string, "EXECUTE.\n");
473
474       if ( gtk_toggle_button_get_active
475            (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
476                                                   "radiobutton-range"))))
477         {
478           g_string_append (string, "DELETE VARIABLES filter_$.\n");
479         }
480     }
481
482
483   text  = string->str;
484   g_string_free (string, FALSE);
485   return text;
486 }