1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "select-cases-dialog.h"
22 #include "psppire-dialog.h"
23 #include "psppire-data-window.h"
24 #include "psppire-selector.h"
25 #include "dict-display.h"
26 #include "dialog-common.h"
27 #include "widget-io.h"
33 #define _(msgid) gettext (msgid)
34 #define N_(msgid) msgid
38 /* FIXME: These shouldn't be here */
39 #include "psppire-data-store.h"
42 struct select_cases_dialog
44 /* The XML that created the dialog */
47 GtkWidget *spinbutton ;
48 GtkWidget *spinbutton1 ;
49 GtkWidget *spinbutton2 ;
54 PsppireDataStore *data_store;
57 static gchar * generate_syntax (const struct select_cases_dialog *scd);
61 set_sensitivity_from_toggle (GtkToggleButton *togglebutton, gpointer data)
64 gboolean active = gtk_toggle_button_get_active (togglebutton);
66 gtk_widget_set_sensitive (w, active);
70 set_sensitivity_from_toggle_invert (GtkToggleButton *togglebutton,
74 gboolean active = gtk_toggle_button_get_active (togglebutton);
76 gtk_widget_set_sensitive (w, !active);
81 static const gchar label1[]=N_("Approximately %3d%% of all cases.");
82 static const gchar label2[]=N_("Exactly %3d cases from the first %3d cases.");
86 sample_subdialog (GtkButton *b, gpointer data)
89 struct select_cases_dialog *scd = data;
91 gint case_count = psppire_data_store_get_case_count (scd->data_store);
93 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
94 "select-cases-dialog");
95 GtkWidget *dialog = get_widget_assert (scd->xml,
96 "select-cases-random-sample-dialog");
97 GtkWidget *percent = get_widget_assert (scd->xml,
98 "radiobutton-sample-percent");
99 GtkWidget *sample_n_cases = get_widget_assert (scd->xml,
100 "radiobutton-sample-n-cases");
101 GtkWidget *table = get_widget_assert (scd->xml,
102 "select-cases-random-sample-table");
106 scd->hbox1 = widget_scanf (gettext (label1), &scd->spinbutton);
108 gtk_widget_show (scd->hbox1);
110 gtk_table_attach_defaults (GTK_TABLE (table),
111 scd->hbox1, 1, 2, 0, 1);
113 g_signal_connect (percent, "toggled",
114 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
116 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
123 widget_scanf (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
125 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
128 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
131 gtk_widget_show (scd->hbox2);
132 gtk_widget_set_sensitive (scd->hbox2, FALSE);
134 gtk_table_attach_defaults (GTK_TABLE (table),
135 scd->hbox2, 1, 2, 1, 2);
137 g_signal_connect (sample_n_cases, "toggled",
138 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
140 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
144 gtk_window_set_transient_for (GTK_WINDOW (dialog),
145 GTK_WINDOW (parent_dialog));
147 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
149 if ( response != PSPPIRE_RESPONSE_CONTINUE)
151 g_signal_handlers_disconnect_by_func
153 G_CALLBACK (set_sensitivity_from_toggle),
156 g_signal_handlers_disconnect_by_func
157 (G_OBJECT (sample_n_cases),
158 G_CALLBACK (set_sensitivity_from_toggle),
161 gtk_widget_destroy(scd->hbox1);
162 gtk_widget_destroy(scd->hbox2);
163 scd->hbox1 = scd->hbox2 = NULL;
168 GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
170 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
172 text = widget_printf (gettext(label1), scd->spinbutton);
173 gtk_label_set_text (GTK_LABEL (l0), text);
178 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
179 gtk_label_set_text (GTK_LABEL (l0), text);
188 range_subdialog (GtkButton *b, gpointer data)
191 struct select_cases_dialog *scd = data;
193 gint n_cases = psppire_data_store_get_case_count (scd->data_store);
195 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
196 "select-cases-dialog");
198 GtkWidget *dialog = get_widget_assert (scd->xml,
199 "select-cases-range-dialog");
201 GtkWidget *first = get_widget_assert (scd->xml,
202 "range-dialog-first");
204 GtkWidget *last = get_widget_assert (scd->xml,
205 "range-dialog-last");
208 gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
209 gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
211 gtk_window_set_transient_for (GTK_WINDOW (dialog),
212 GTK_WINDOW (parent_dialog));
215 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
216 if ( response == PSPPIRE_RESPONSE_CONTINUE)
218 GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
219 GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
220 GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
221 gchar *text = widget_printf (_("%d thru %d"), first, last);
223 gtk_label_set_text (GTK_LABEL (l1), text);
230 set_radiobutton (GtkWidget *button, gpointer data)
232 GtkToggleButton *toggle = data;
233 gtk_toggle_button_set_active (toggle, TRUE);
236 /* Pops up the Select Cases dialog box */
238 select_cases_dialog (PsppireDataWindow *de)
241 struct select_cases_dialog scd = {0,0,0,0,0,0};
243 GtkWidget *entry = NULL;
244 GtkWidget *selector ;
245 GtkWidget *button_range;
246 GtkWidget *button_sample;
248 scd.xml = builder_new ("select-cases.ui");
250 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
252 button_range = get_widget_assert (scd.xml, "button-range");
253 button_sample = get_widget_assert (scd.xml, "button-sample");
254 entry = get_widget_assert (scd.xml, "filter-variable-entry");
255 selector = get_widget_assert (scd.xml, "psppire-selector-filter");
258 GtkWidget *button_if =
259 get_widget_assert (scd.xml, "button-if");
261 GtkWidget *radiobutton_if =
262 get_widget_assert (scd.xml, "radiobutton-if");
264 GtkWidget *radiobutton_all =
265 get_widget_assert (scd.xml, "radiobutton-all");
267 GtkWidget *radiobutton_sample =
268 get_widget_assert (scd.xml, "radiobutton-sample");
270 GtkWidget *radiobutton_range =
271 get_widget_assert (scd.xml, "radiobutton-range");
273 GtkWidget *radiobutton_filter =
274 get_widget_assert (scd.xml, "radiobutton-filter-variable");
276 GtkWidget *range_label =
277 get_widget_assert (scd.xml, "range-sample-label");
279 GtkWidget *sample_label =
280 get_widget_assert (scd.xml, "random-sample-label");
282 g_signal_connect (radiobutton_all, "toggled",
283 G_CALLBACK (set_sensitivity_from_toggle_invert),
284 get_widget_assert (scd.xml, "filter-delete-button-box")
287 g_signal_connect (button_if, "clicked",
288 G_CALLBACK (set_radiobutton), radiobutton_if);
290 g_signal_connect (button_sample, "clicked",
291 G_CALLBACK (set_radiobutton), radiobutton_sample);
293 g_signal_connect (button_range, "clicked",
294 G_CALLBACK (set_radiobutton), radiobutton_range);
296 g_signal_connect (selector, "clicked",
297 G_CALLBACK (set_radiobutton), radiobutton_filter);
299 g_signal_connect (selector, "selected",
300 G_CALLBACK (set_radiobutton), radiobutton_filter);
302 g_signal_connect (radiobutton_range, "toggled",
303 G_CALLBACK (set_sensitivity_from_toggle),
307 g_signal_connect (radiobutton_sample, "toggled",
308 G_CALLBACK (set_sensitivity_from_toggle),
312 g_signal_connect (radiobutton_filter, "toggled",
313 G_CALLBACK (set_sensitivity_from_toggle),
320 dialog = get_widget_assert (scd.xml, "select-cases-dialog");
321 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
324 GtkWidget *source = get_widget_assert (scd.xml, "select-cases-treeview");
326 g_object_set (source, "model",
327 scd.data_store->dict,
329 GTK_SELECTION_SINGLE, NULL);
331 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
332 is_currently_in_entry);
337 g_signal_connect (button_range,
338 "clicked", G_CALLBACK (range_subdialog), &scd);
341 g_signal_connect (button_sample,
342 "clicked", G_CALLBACK (sample_subdialog), &scd);
345 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
349 case GTK_RESPONSE_OK:
350 g_free (execute_syntax_string (generate_syntax (&scd)));
352 case PSPPIRE_RESPONSE_PASTE:
353 g_free (paste_syntax_to_window (generate_syntax (&scd)));
359 g_object_unref (scd.xml);
364 generate_syntax_filter (const struct select_cases_dialog *scd)
367 GString *string = g_string_new ("");
369 const gchar filter[]="filter_$";
370 const gchar key[]="case_$";
372 if ( gtk_toggle_button_get_active
373 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
374 "radiobutton-range"))))
376 GtkSpinButton *first =
377 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
378 "range-dialog-first"));
380 GtkSpinButton *last =
381 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
382 "range-dialog-last"));
384 g_string_append_printf (string,
385 "COMPUTE filter_$ = ($CASENUM >= %ld "
386 "AND $CASENUM <= %ld).\n",
387 (long) gtk_spin_button_get_value (first),
388 (long) gtk_spin_button_get_value (last)
391 g_string_append (string, "EXECUTE.\n");
393 else if ( gtk_toggle_button_get_active
394 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
395 "radiobutton-sample"))))
397 GtkWidget *random_sample =
398 get_widget_assert (scd->xml,
399 "radiobutton-sample-percent");
401 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
403 const double percentage =
404 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
406 g_string_append_printf (string,
407 "COMPUTE %s = RV.UNIFORM (0,1) < %g.\n",
409 percentage / 100.0 );
414 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
415 const gint from_n_cases =
416 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
419 const gchar ranvar[]="rv_$";
421 g_string_append_printf (string,
422 "COMPUTE %s = $CASENUM.\n", key);
424 g_string_append_printf (string,
425 "COMPUTE %s = %s > %d.\n",
426 filter, key, from_n_cases);
428 g_string_append_printf (string,
429 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
432 g_string_append_printf (string,
436 g_string_append (string, "EXECUTE.\n");
439 g_string_append_printf (string,
440 "COMPUTE %s = $CASENUM.\n",
443 g_string_append_printf (string,
444 "COMPUTE %s = %s <= %d\n",
449 g_string_append (string, "EXECUTE.\n");
452 g_string_append_printf (string,
456 g_string_append_printf (string,
457 "DELETE VARIABLES %s, %s.\n",
462 g_string_append (string, "EXECUTE.\n");
467 g_string_append_printf (string, "FILTER BY %s.\n", filter);
470 g_string_free (string, FALSE);
475 generate_syntax_delete (const struct select_cases_dialog *scd)
478 GString *string = NULL;
480 if ( gtk_toggle_button_get_active
481 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
482 "radiobutton-all"))))
484 return xstrdup ("\n");
487 string = g_string_new ("");
489 if ( gtk_toggle_button_get_active
490 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
491 "radiobutton-sample"))))
493 GtkWidget *random_sample =
494 get_widget_assert (scd->xml,
495 "radiobutton-sample-percent");
497 g_string_append (string, "SAMPLE ");
499 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
501 const double percentage =
502 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
503 g_string_append_printf (string, "%g.", percentage / 100.0);
508 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
509 const gint from_n_cases =
510 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
512 g_string_append_printf (string, "%d FROM %d .", n_cases, from_n_cases);
516 else if ( gtk_toggle_button_get_active
517 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
518 "radiobutton-range"))))
520 GtkSpinButton *first =
521 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
522 "range-dialog-first"));
524 GtkSpinButton *last =
525 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
526 "range-dialog-last"));
528 g_string_append_printf (string,
529 "COMPUTE filter_$ = ($CASENUM >= %ld "
530 "AND $CASENUM <= %ld).\n",
531 (long) gtk_spin_button_get_value (first),
532 (long) gtk_spin_button_get_value (last)
534 g_string_append (string, "EXECUTE.\n");
535 g_string_append_printf (string, "SELECT IF filter_$.\n");
538 else if ( gtk_toggle_button_get_active
540 (get_widget_assert (scd->xml,
541 "radiobutton-filter-variable"))))
544 GTK_ENTRY (get_widget_assert (scd->xml,
545 "filter-variable-entry"));
547 g_string_append_printf (string, "SELECT IF (%s <> 0).",
548 gtk_entry_get_text (entry));
552 g_string_append (string, "\n");
557 g_string_free (string, FALSE);
563 generate_syntax (const struct select_cases_dialog *scd)
565 /* In the simple case, all we need to do is cancel any existing filter */
566 if ( gtk_toggle_button_get_active
567 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
568 "radiobutton-all"))))
570 return g_strdup ("FILTER OFF.\n");
574 /* Are we filtering or deleting ? */
575 if ( gtk_toggle_button_get_active
576 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
577 "radiobutton-delete"))))
579 return generate_syntax_delete (scd);
583 return generate_syntax_filter (scd);