1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2008, 2009, 2010, 2011 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"
28 #include "psppire-scanf.h"
29 #include "builder-wrapper.h"
36 #define _(msgid) gettext (msgid)
37 #define N_(msgid) msgid
41 /* FIXME: These shouldn't be here */
42 #include "psppire-data-store.h"
45 struct select_cases_dialog
47 /* The XML that created the dialog */
50 GtkWidget *spinbutton ;
51 GtkWidget *spinbutton1 ;
52 GtkWidget *spinbutton2 ;
57 PsppireDataStore *data_store;
60 static gchar * generate_syntax (const struct select_cases_dialog *scd);
64 set_sensitivity_from_toggle (GtkToggleButton *togglebutton, gpointer data)
67 gboolean active = gtk_toggle_button_get_active (togglebutton);
69 gtk_widget_set_sensitive (w, active);
73 set_sensitivity_from_toggle_invert (GtkToggleButton *togglebutton,
77 gboolean active = gtk_toggle_button_get_active (togglebutton);
79 gtk_widget_set_sensitive (w, !active);
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.");
89 sample_subdialog (GtkButton *b, gpointer data)
92 struct select_cases_dialog *scd = data;
94 gint case_count = psppire_data_store_get_case_count (scd->data_store);
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");
109 scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
111 gtk_widget_show (scd->hbox1);
113 gtk_table_attach_defaults (GTK_TABLE (table),
114 scd->hbox1, 1, 2, 0, 1);
116 g_signal_connect (percent, "toggled",
117 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
119 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
126 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
128 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
131 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
134 gtk_widget_show (scd->hbox2);
135 gtk_widget_set_sensitive (scd->hbox2, FALSE);
137 gtk_table_attach_defaults (GTK_TABLE (table),
138 scd->hbox2, 1, 2, 1, 2);
140 g_signal_connect (sample_n_cases, "toggled",
141 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
143 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
147 gtk_window_set_transient_for (GTK_WINDOW (dialog),
148 GTK_WINDOW (parent_dialog));
150 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
152 if ( response != PSPPIRE_RESPONSE_CONTINUE)
154 g_signal_handlers_disconnect_by_func
156 G_CALLBACK (set_sensitivity_from_toggle),
159 g_signal_handlers_disconnect_by_func
160 (G_OBJECT (sample_n_cases),
161 G_CALLBACK (set_sensitivity_from_toggle),
164 gtk_widget_destroy(scd->hbox1);
165 gtk_widget_destroy(scd->hbox2);
166 scd->hbox1 = scd->hbox2 = NULL;
171 GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
173 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
175 text = widget_printf (gettext(label1), scd->spinbutton);
176 gtk_label_set_text (GTK_LABEL (l0), text);
181 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
182 gtk_label_set_text (GTK_LABEL (l0), text);
191 range_subdialog (GtkButton *b, gpointer data)
194 struct select_cases_dialog *scd = data;
196 gint n_cases = psppire_data_store_get_case_count (scd->data_store);
198 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
199 "select-cases-dialog");
201 GtkWidget *dialog = get_widget_assert (scd->xml,
202 "select-cases-range-dialog");
204 GtkWidget *first = get_widget_assert (scd->xml,
205 "range-dialog-first");
207 GtkWidget *last = get_widget_assert (scd->xml,
208 "range-dialog-last");
211 gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
212 gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
214 gtk_window_set_transient_for (GTK_WINDOW (dialog),
215 GTK_WINDOW (parent_dialog));
218 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
219 if ( response == PSPPIRE_RESPONSE_CONTINUE)
221 GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
222 GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
223 GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
224 gchar *text = widget_printf (_("%d thru %d"), first, last);
226 gtk_label_set_text (GTK_LABEL (l1), text);
233 set_radiobutton (GtkWidget *button, gpointer data)
235 GtkToggleButton *toggle = data;
236 gtk_toggle_button_set_active (toggle, TRUE);
239 /* Pops up the Select Cases dialog box */
241 select_cases_dialog (PsppireDataWindow *de)
244 struct select_cases_dialog scd = {0,0,0,0,0,0};
246 GtkWidget *entry = NULL;
247 GtkWidget *selector ;
248 GtkWidget *button_range;
249 GtkWidget *button_sample;
251 scd.xml = builder_new ("select-cases.ui");
253 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
255 button_range = get_widget_assert (scd.xml, "button-range");
256 button_sample = get_widget_assert (scd.xml, "button-sample");
257 entry = get_widget_assert (scd.xml, "filter-variable-entry");
258 selector = get_widget_assert (scd.xml, "psppire-selector-filter");
261 GtkWidget *button_if =
262 get_widget_assert (scd.xml, "button-if");
264 GtkWidget *radiobutton_if =
265 get_widget_assert (scd.xml, "radiobutton-if");
267 GtkWidget *radiobutton_all =
268 get_widget_assert (scd.xml, "radiobutton-all");
270 GtkWidget *radiobutton_sample =
271 get_widget_assert (scd.xml, "radiobutton-sample");
273 GtkWidget *radiobutton_range =
274 get_widget_assert (scd.xml, "radiobutton-range");
276 GtkWidget *radiobutton_filter =
277 get_widget_assert (scd.xml, "radiobutton-filter-variable");
279 GtkWidget *range_label =
280 get_widget_assert (scd.xml, "range-sample-label");
282 GtkWidget *sample_label =
283 get_widget_assert (scd.xml, "random-sample-label");
285 g_signal_connect (radiobutton_all, "toggled",
286 G_CALLBACK (set_sensitivity_from_toggle_invert),
287 get_widget_assert (scd.xml, "filter-delete-button-box")
290 g_signal_connect (button_if, "clicked",
291 G_CALLBACK (set_radiobutton), radiobutton_if);
293 g_signal_connect (button_sample, "clicked",
294 G_CALLBACK (set_radiobutton), radiobutton_sample);
296 g_signal_connect (button_range, "clicked",
297 G_CALLBACK (set_radiobutton), radiobutton_range);
299 g_signal_connect (selector, "clicked",
300 G_CALLBACK (set_radiobutton), radiobutton_filter);
302 g_signal_connect (selector, "selected",
303 G_CALLBACK (set_radiobutton), radiobutton_filter);
305 g_signal_connect (radiobutton_range, "toggled",
306 G_CALLBACK (set_sensitivity_from_toggle),
310 g_signal_connect (radiobutton_sample, "toggled",
311 G_CALLBACK (set_sensitivity_from_toggle),
315 g_signal_connect (radiobutton_filter, "toggled",
316 G_CALLBACK (set_sensitivity_from_toggle),
323 dialog = get_widget_assert (scd.xml, "select-cases-dialog");
324 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
327 GtkWidget *source = get_widget_assert (scd.xml, "select-cases-treeview");
329 g_object_set (source, "model",
330 scd.data_store->dict,
332 GTK_SELECTION_SINGLE, NULL);
334 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
335 is_currently_in_entry);
340 g_signal_connect (button_range,
341 "clicked", G_CALLBACK (range_subdialog), &scd);
344 g_signal_connect (button_sample,
345 "clicked", G_CALLBACK (sample_subdialog), &scd);
348 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
352 case GTK_RESPONSE_OK:
353 g_free (execute_syntax_string (de, generate_syntax (&scd)));
355 case PSPPIRE_RESPONSE_PASTE:
356 g_free (paste_syntax_to_window (generate_syntax (&scd)));
362 g_object_unref (scd.xml);
367 generate_syntax_filter (const struct select_cases_dialog *scd)
370 GString *string = g_string_new ("");
372 const gchar *filter = "filter_$";
373 const gchar key[]="case_$";
375 if ( gtk_toggle_button_get_active
376 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
377 "radiobutton-range"))))
379 GtkSpinButton *first =
380 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
381 "range-dialog-first"));
383 GtkSpinButton *last =
384 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
385 "range-dialog-last"));
387 g_string_append_printf (string,
388 "COMPUTE filter_$ = ($CASENUM >= %ld "
389 "AND $CASENUM <= %ld).\n",
390 (long) gtk_spin_button_get_value (first),
391 (long) gtk_spin_button_get_value (last)
394 g_string_append (string, "EXECUTE.\n");
396 else if ( gtk_toggle_button_get_active
397 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
398 "radiobutton-sample"))))
400 GtkWidget *random_sample =
401 get_widget_assert (scd->xml,
402 "radiobutton-sample-percent");
404 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
406 const double percentage =
407 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
409 g_string_append_printf (string,
410 "COMPUTE %s = RV.UNIFORM (0,1) < %g.\n",
412 percentage / 100.0 );
417 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
418 const gint from_n_cases =
419 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
422 const gchar ranvar[]="rv_$";
424 g_string_append_printf (string,
425 "COMPUTE %s = $CASENUM.\n", key);
427 g_string_append_printf (string,
428 "COMPUTE %s = %s > %d.\n",
429 filter, key, from_n_cases);
431 g_string_append_printf (string,
432 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
435 g_string_append_printf (string,
439 g_string_append (string, "EXECUTE.\n");
442 g_string_append_printf (string,
443 "COMPUTE %s = $CASENUM.\n",
446 g_string_append_printf (string,
447 "COMPUTE %s = %s <= %d\n",
452 g_string_append (string, "EXECUTE.\n");
455 g_string_append_printf (string,
459 g_string_append_printf (string,
460 "DELETE VARIABLES %s, %s.\n",
465 g_string_append (string, "EXECUTE.\n");
471 GTK_ENTRY (get_widget_assert (scd->xml,
472 "filter-variable-entry"));
473 filter = gtk_entry_get_text (entry);
477 g_string_append_printf (string, "FILTER BY %s.\n", filter);
480 g_string_free (string, FALSE);
485 generate_syntax_delete (const struct select_cases_dialog *scd)
488 GString *string = NULL;
490 if ( gtk_toggle_button_get_active
491 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
492 "radiobutton-all"))))
494 return xstrdup ("\n");
497 string = g_string_new ("");
499 if ( gtk_toggle_button_get_active
500 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
501 "radiobutton-sample"))))
503 GtkWidget *random_sample =
504 get_widget_assert (scd->xml,
505 "radiobutton-sample-percent");
507 g_string_append (string, "SAMPLE ");
509 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
511 const double percentage =
512 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
513 g_string_append_printf (string, "%g.", percentage / 100.0);
518 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
519 const gint from_n_cases =
520 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
522 g_string_append_printf (string, "%d FROM %d .", n_cases, from_n_cases);
526 else if ( gtk_toggle_button_get_active
527 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
528 "radiobutton-range"))))
530 GtkSpinButton *first =
531 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
532 "range-dialog-first"));
534 GtkSpinButton *last =
535 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
536 "range-dialog-last"));
538 g_string_append_printf (string,
539 "COMPUTE filter_$ = ($CASENUM >= %ld "
540 "AND $CASENUM <= %ld).\n",
541 (long) gtk_spin_button_get_value (first),
542 (long) gtk_spin_button_get_value (last)
544 g_string_append (string, "EXECUTE.\n");
545 g_string_append_printf (string, "SELECT IF filter_$.\n");
548 else if ( gtk_toggle_button_get_active
550 (get_widget_assert (scd->xml,
551 "radiobutton-filter-variable"))))
554 GTK_ENTRY (get_widget_assert (scd->xml,
555 "filter-variable-entry"));
557 g_string_append_printf (string, "SELECT IF (%s <> 0).",
558 gtk_entry_get_text (entry));
562 g_string_append (string, "\n");
567 g_string_free (string, FALSE);
573 generate_syntax (const struct select_cases_dialog *scd)
575 /* In the simple case, all we need to do is cancel any existing filter */
576 if ( gtk_toggle_button_get_active
577 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
578 "radiobutton-all"))))
580 return g_strdup ("FILTER OFF.\n");
584 /* Are we filtering or deleting ? */
585 if ( gtk_toggle_button_get_active
586 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
587 "radiobutton-delete"))))
589 return generate_syntax_delete (scd);
593 return generate_syntax_filter (scd);