1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2014 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"
23 #include "psppire-dialog.h"
24 #include "psppire-data-window.h"
25 #include "psppire-selector.h"
26 #include "dict-display.h"
27 #include "dialog-common.h"
28 #include "widget-io.h"
29 #include "psppire-scanf.h"
30 #include "builder-wrapper.h"
37 #define _(msgid) gettext (msgid)
38 #define N_(msgid) msgid
42 /* FIXME: These shouldn't be here */
43 #include "psppire-data-store.h"
46 struct select_cases_dialog
48 /* The XML that created the dialog */
51 GtkWidget *spinbutton ;
52 GtkWidget *spinbutton1 ;
53 GtkWidget *spinbutton2 ;
58 PsppireDataStore *data_store;
61 static gchar * generate_syntax (const struct select_cases_dialog *scd);
64 static const gchar label1[] = N_("Approximately %3d%% of all cases.");
65 static const gchar label2[] = N_("Exactly %3d cases from the first %3d cases.");
69 sample_subdialog (GtkButton *b, gpointer data)
72 struct select_cases_dialog *scd = data;
74 gint case_count = psppire_data_store_get_case_count (scd->data_store);
76 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
77 "select-cases-dialog");
78 GtkWidget *dialog = get_widget_assert (scd->xml,
79 "select-cases-random-sample-dialog");
80 GtkWidget *percent = get_widget_assert (scd->xml,
81 "radiobutton-sample-percent");
82 GtkWidget *sample_n_cases = get_widget_assert (scd->xml,
83 "radiobutton-sample-n-cases");
84 GtkWidget *table = get_widget_assert (scd->xml,
85 "select-cases-random-sample-table");
89 scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
91 gtk_widget_show (scd->hbox1);
93 gtk_grid_attach (GTK_GRID (table),
98 g_signal_connect (percent, "toggled",
99 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
101 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
108 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
110 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
113 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
116 gtk_widget_show (scd->hbox2);
117 gtk_widget_set_sensitive (scd->hbox2, FALSE);
119 gtk_grid_attach (GTK_GRID (table),
123 g_signal_connect (sample_n_cases, "toggled",
124 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
126 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
130 gtk_window_set_transient_for (GTK_WINDOW (dialog),
131 GTK_WINDOW (parent_dialog));
133 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
135 if ( response != PSPPIRE_RESPONSE_CONTINUE)
137 g_signal_handlers_disconnect_by_func
139 G_CALLBACK (set_sensitivity_from_toggle),
142 g_signal_handlers_disconnect_by_func
143 (G_OBJECT (sample_n_cases),
144 G_CALLBACK (set_sensitivity_from_toggle),
147 gtk_widget_destroy(scd->hbox1);
148 gtk_widget_destroy(scd->hbox2);
149 scd->hbox1 = scd->hbox2 = NULL;
154 GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
156 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
158 text = widget_printf (gettext(label1), scd->spinbutton);
159 gtk_label_set_text (GTK_LABEL (l0), text);
164 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
165 gtk_label_set_text (GTK_LABEL (l0), text);
174 range_subdialog (GtkButton *b, gpointer data)
177 struct select_cases_dialog *scd = data;
179 gint n_cases = psppire_data_store_get_case_count (scd->data_store);
181 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
182 "select-cases-dialog");
184 GtkWidget *dialog = get_widget_assert (scd->xml,
185 "select-cases-range-dialog");
187 GtkWidget *first = get_widget_assert (scd->xml,
188 "range-dialog-first");
190 GtkWidget *last = get_widget_assert (scd->xml,
191 "range-dialog-last");
194 gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
195 gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
197 gtk_window_set_transient_for (GTK_WINDOW (dialog),
198 GTK_WINDOW (parent_dialog));
201 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
202 if ( response == PSPPIRE_RESPONSE_CONTINUE)
204 GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
205 GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
206 GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
207 gchar *text = widget_printf (_("%d thru %d"), first, last);
209 gtk_label_set_text (GTK_LABEL (l1), text);
216 set_radiobutton (GtkWidget *button, gpointer data)
218 GtkToggleButton *toggle = data;
219 gtk_toggle_button_set_active (toggle, TRUE);
222 /* Pops up the Select Cases dialog box */
224 select_cases_dialog (PsppireDataWindow *de)
227 struct select_cases_dialog scd = {0,0,0,0,0,0};
229 GtkWidget *entry = NULL;
230 GtkWidget *selector ;
231 GtkWidget *button_range;
232 GtkWidget *button_sample;
234 scd.xml = builder_new ("select-cases.ui");
236 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
238 button_range = get_widget_assert (scd.xml, "button-range");
239 button_sample = get_widget_assert (scd.xml, "button-sample");
240 entry = get_widget_assert (scd.xml, "filter-variable-entry");
241 selector = get_widget_assert (scd.xml, "psppire-selector-filter");
244 GtkWidget *button_if =
245 get_widget_assert (scd.xml, "button-if");
247 GtkWidget *radiobutton_if =
248 get_widget_assert (scd.xml, "radiobutton-if");
250 GtkWidget *radiobutton_all =
251 get_widget_assert (scd.xml, "radiobutton-all");
253 GtkWidget *radiobutton_sample =
254 get_widget_assert (scd.xml, "radiobutton-sample");
256 GtkWidget *radiobutton_range =
257 get_widget_assert (scd.xml, "radiobutton-range");
259 GtkWidget *radiobutton_filter =
260 get_widget_assert (scd.xml, "radiobutton-filter-variable");
262 GtkWidget *range_label =
263 get_widget_assert (scd.xml, "range-sample-label");
265 GtkWidget *sample_label =
266 get_widget_assert (scd.xml, "random-sample-label");
268 g_signal_connect (radiobutton_all, "toggled",
269 G_CALLBACK (set_sensitivity_from_toggle_invert),
270 get_widget_assert (scd.xml, "filter-delete-button-box")
273 g_signal_connect (button_if, "clicked",
274 G_CALLBACK (set_radiobutton), radiobutton_if);
276 g_signal_connect (button_sample, "clicked",
277 G_CALLBACK (set_radiobutton), radiobutton_sample);
279 g_signal_connect (button_range, "clicked",
280 G_CALLBACK (set_radiobutton), radiobutton_range);
282 g_signal_connect (selector, "clicked",
283 G_CALLBACK (set_radiobutton), radiobutton_filter);
285 g_signal_connect (selector, "selected",
286 G_CALLBACK (set_radiobutton), radiobutton_filter);
288 g_signal_connect (radiobutton_range, "toggled",
289 G_CALLBACK (set_sensitivity_from_toggle),
293 g_signal_connect (radiobutton_sample, "toggled",
294 G_CALLBACK (set_sensitivity_from_toggle),
298 g_signal_connect (radiobutton_filter, "toggled",
299 G_CALLBACK (set_sensitivity_from_toggle),
306 dialog = get_widget_assert (scd.xml, "select-cases-dialog");
307 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
310 GtkWidget *source = get_widget_assert (scd.xml, "select-cases-treeview");
312 g_object_set (source, "model",
313 scd.data_store->dict,
315 GTK_SELECTION_SINGLE, NULL);
317 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
318 is_currently_in_entry);
323 g_signal_connect (button_range,
324 "clicked", G_CALLBACK (range_subdialog), &scd);
327 g_signal_connect (button_sample,
328 "clicked", G_CALLBACK (sample_subdialog), &scd);
331 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
335 case GTK_RESPONSE_OK:
336 g_free (execute_syntax_string (de, generate_syntax (&scd)));
338 case PSPPIRE_RESPONSE_PASTE:
339 g_free (paste_syntax_to_window (generate_syntax (&scd)));
345 g_object_unref (scd.xml);
350 generate_syntax_filter (const struct select_cases_dialog *scd)
355 const gchar *filter = "filter_$";
356 const gchar key[]="case_$";
358 ds_init_empty (&dss);
360 if (gtk_toggle_button_get_active
361 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
362 "radiobutton-range"))))
364 GtkSpinButton *first =
365 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
366 "range-dialog-first"));
368 GtkSpinButton *last =
369 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
370 "range-dialog-last"));
372 ds_put_c_format (&dss,
373 "COMPUTE filter_$ = ($CASENUM >= %ld "
374 "AND $CASENUM <= %ld).\n",
375 (long) gtk_spin_button_get_value (first),
376 (long) gtk_spin_button_get_value (last)
379 ds_put_cstr (&dss, "EXECUTE.\n");
381 else if ( gtk_toggle_button_get_active
382 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
383 "radiobutton-sample"))))
385 GtkWidget *random_sample =
386 get_widget_assert (scd->xml,
387 "radiobutton-sample-percent");
389 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
391 const double percentage =
392 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
394 ds_put_c_format (&dss,
395 "COMPUTE %s = RV.UNIFORM (0,1) < %.*g.\n",
397 DBL_DIG + 1, percentage / 100.0 );
402 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
403 const gint from_n_cases =
404 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
407 const gchar ranvar[]="rv_$";
409 ds_put_c_format (&dss,
410 "COMPUTE %s = $CASENUM.\n", key);
412 ds_put_c_format (&dss,
413 "COMPUTE %s = %s > %d.\n",
414 filter, key, from_n_cases);
416 ds_put_c_format (&dss,
417 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
420 ds_put_c_format (&dss,
424 ds_put_cstr (&dss, "EXECUTE.\n");
427 ds_put_c_format (&dss,
428 "COMPUTE %s = $CASENUM.\n",
431 ds_put_c_format (&dss,
432 "COMPUTE %s = %s <= %d\n",
437 ds_put_cstr (&dss, "EXECUTE.\n");
440 ds_put_c_format (&dss,
444 ds_put_c_format (&dss,
445 "DELETE VARIABLES %s, %s.\n",
449 ds_put_cstr (&dss, "EXECUTE.\n");
454 GTK_ENTRY (get_widget_assert (scd->xml,
455 "filter-variable-entry"));
456 filter = gtk_entry_get_text (entry);
459 ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
461 text = ds_steal_cstr (&dss);
469 generate_syntax_delete (const struct select_cases_dialog *scd)
474 if ( gtk_toggle_button_get_active
475 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
476 "radiobutton-all"))))
478 return xstrdup ("\n");
481 ds_init_empty (&dss);
483 if ( gtk_toggle_button_get_active
484 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
485 "radiobutton-sample"))))
487 GtkWidget *random_sample =
488 get_widget_assert (scd->xml,
489 "radiobutton-sample-percent");
491 ds_put_cstr (&dss, "SAMPLE ");
493 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
495 const double percentage =
496 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
497 ds_put_c_format (&dss, "%g.", percentage / 100.0);
502 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
503 const gint from_n_cases =
504 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
506 ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
510 else if ( gtk_toggle_button_get_active
511 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
512 "radiobutton-range"))))
514 GtkSpinButton *first =
515 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
516 "range-dialog-first"));
518 GtkSpinButton *last =
519 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
520 "range-dialog-last"));
522 ds_put_c_format (&dss,
523 "COMPUTE filter_$ = ($CASENUM >= %ld "
524 "AND $CASENUM <= %ld).\n",
525 (long) gtk_spin_button_get_value (first),
526 (long) gtk_spin_button_get_value (last)
528 ds_put_cstr (&dss, "EXECUTE.\n");
529 ds_put_c_format (&dss, "SELECT IF filter_$.\n");
532 else if ( gtk_toggle_button_get_active
534 (get_widget_assert (scd->xml,
535 "radiobutton-filter-variable"))))
538 GTK_ENTRY (get_widget_assert (scd->xml,
539 "filter-variable-entry"));
541 ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
542 gtk_entry_get_text (entry));
546 ds_put_cstr (&dss, "\n");
548 text = ds_steal_cstr (&dss);
557 generate_syntax (const struct select_cases_dialog *scd)
559 /* In the simple case, all we need to do is cancel any existing filter */
560 if ( gtk_toggle_button_get_active
561 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
562 "radiobutton-all"))))
564 return g_strdup ("FILTER OFF.\n");
568 /* Are we filtering or deleting ? */
569 if ( gtk_toggle_button_get_active
570 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
571 "radiobutton-delete"))))
573 return generate_syntax_delete (scd);
577 return generate_syntax_filter (scd);