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_table_attach_defaults (GTK_TABLE (table),
94 scd->hbox1, 1, 2, 0, 1);
96 g_signal_connect (percent, "toggled",
97 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
99 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
106 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
108 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
111 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
114 gtk_widget_show (scd->hbox2);
115 gtk_widget_set_sensitive (scd->hbox2, FALSE);
117 gtk_table_attach_defaults (GTK_TABLE (table),
118 scd->hbox2, 1, 2, 1, 2);
120 g_signal_connect (sample_n_cases, "toggled",
121 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
123 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
127 gtk_window_set_transient_for (GTK_WINDOW (dialog),
128 GTK_WINDOW (parent_dialog));
130 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
132 if ( response != PSPPIRE_RESPONSE_CONTINUE)
134 g_signal_handlers_disconnect_by_func
136 G_CALLBACK (set_sensitivity_from_toggle),
139 g_signal_handlers_disconnect_by_func
140 (G_OBJECT (sample_n_cases),
141 G_CALLBACK (set_sensitivity_from_toggle),
144 gtk_widget_destroy(scd->hbox1);
145 gtk_widget_destroy(scd->hbox2);
146 scd->hbox1 = scd->hbox2 = NULL;
151 GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
153 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
155 text = widget_printf (gettext(label1), scd->spinbutton);
156 gtk_label_set_text (GTK_LABEL (l0), text);
161 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
162 gtk_label_set_text (GTK_LABEL (l0), text);
171 range_subdialog (GtkButton *b, gpointer data)
174 struct select_cases_dialog *scd = data;
176 gint n_cases = psppire_data_store_get_case_count (scd->data_store);
178 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
179 "select-cases-dialog");
181 GtkWidget *dialog = get_widget_assert (scd->xml,
182 "select-cases-range-dialog");
184 GtkWidget *first = get_widget_assert (scd->xml,
185 "range-dialog-first");
187 GtkWidget *last = get_widget_assert (scd->xml,
188 "range-dialog-last");
191 gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
192 gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
194 gtk_window_set_transient_for (GTK_WINDOW (dialog),
195 GTK_WINDOW (parent_dialog));
198 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
199 if ( response == PSPPIRE_RESPONSE_CONTINUE)
201 GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
202 GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
203 GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
204 gchar *text = widget_printf (_("%d thru %d"), first, last);
206 gtk_label_set_text (GTK_LABEL (l1), text);
213 set_radiobutton (GtkWidget *button, gpointer data)
215 GtkToggleButton *toggle = data;
216 gtk_toggle_button_set_active (toggle, TRUE);
219 /* Pops up the Select Cases dialog box */
221 select_cases_dialog (PsppireDataWindow *de)
224 struct select_cases_dialog scd = {0,0,0,0,0,0};
226 GtkWidget *entry = NULL;
227 GtkWidget *selector ;
228 GtkWidget *button_range;
229 GtkWidget *button_sample;
231 scd.xml = builder_new ("select-cases.ui");
233 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
235 button_range = get_widget_assert (scd.xml, "button-range");
236 button_sample = get_widget_assert (scd.xml, "button-sample");
237 entry = get_widget_assert (scd.xml, "filter-variable-entry");
238 selector = get_widget_assert (scd.xml, "psppire-selector-filter");
241 GtkWidget *button_if =
242 get_widget_assert (scd.xml, "button-if");
244 GtkWidget *radiobutton_if =
245 get_widget_assert (scd.xml, "radiobutton-if");
247 GtkWidget *radiobutton_all =
248 get_widget_assert (scd.xml, "radiobutton-all");
250 GtkWidget *radiobutton_sample =
251 get_widget_assert (scd.xml, "radiobutton-sample");
253 GtkWidget *radiobutton_range =
254 get_widget_assert (scd.xml, "radiobutton-range");
256 GtkWidget *radiobutton_filter =
257 get_widget_assert (scd.xml, "radiobutton-filter-variable");
259 GtkWidget *range_label =
260 get_widget_assert (scd.xml, "range-sample-label");
262 GtkWidget *sample_label =
263 get_widget_assert (scd.xml, "random-sample-label");
265 g_signal_connect (radiobutton_all, "toggled",
266 G_CALLBACK (set_sensitivity_from_toggle_invert),
267 get_widget_assert (scd.xml, "filter-delete-button-box")
270 g_signal_connect (button_if, "clicked",
271 G_CALLBACK (set_radiobutton), radiobutton_if);
273 g_signal_connect (button_sample, "clicked",
274 G_CALLBACK (set_radiobutton), radiobutton_sample);
276 g_signal_connect (button_range, "clicked",
277 G_CALLBACK (set_radiobutton), radiobutton_range);
279 g_signal_connect (selector, "clicked",
280 G_CALLBACK (set_radiobutton), radiobutton_filter);
282 g_signal_connect (selector, "selected",
283 G_CALLBACK (set_radiobutton), radiobutton_filter);
285 g_signal_connect (radiobutton_range, "toggled",
286 G_CALLBACK (set_sensitivity_from_toggle),
290 g_signal_connect (radiobutton_sample, "toggled",
291 G_CALLBACK (set_sensitivity_from_toggle),
295 g_signal_connect (radiobutton_filter, "toggled",
296 G_CALLBACK (set_sensitivity_from_toggle),
303 dialog = get_widget_assert (scd.xml, "select-cases-dialog");
304 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
307 GtkWidget *source = get_widget_assert (scd.xml, "select-cases-treeview");
309 g_object_set (source, "model",
310 scd.data_store->dict,
312 GTK_SELECTION_SINGLE, NULL);
314 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
315 is_currently_in_entry);
320 g_signal_connect (button_range,
321 "clicked", G_CALLBACK (range_subdialog), &scd);
324 g_signal_connect (button_sample,
325 "clicked", G_CALLBACK (sample_subdialog), &scd);
328 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
332 case GTK_RESPONSE_OK:
333 g_free (execute_syntax_string (de, generate_syntax (&scd)));
335 case PSPPIRE_RESPONSE_PASTE:
336 g_free (paste_syntax_to_window (generate_syntax (&scd)));
342 g_object_unref (scd.xml);
347 generate_syntax_filter (const struct select_cases_dialog *scd)
352 const gchar *filter = "filter_$";
353 const gchar key[]="case_$";
355 ds_init_empty (&dss);
357 if (gtk_toggle_button_get_active
358 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
359 "radiobutton-range"))))
361 GtkSpinButton *first =
362 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
363 "range-dialog-first"));
365 GtkSpinButton *last =
366 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
367 "range-dialog-last"));
369 ds_put_c_format (&dss,
370 "COMPUTE filter_$ = ($CASENUM >= %ld "
371 "AND $CASENUM <= %ld).\n",
372 (long) gtk_spin_button_get_value (first),
373 (long) gtk_spin_button_get_value (last)
376 ds_put_cstr (&dss, "EXECUTE.\n");
378 else if ( gtk_toggle_button_get_active
379 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
380 "radiobutton-sample"))))
382 GtkWidget *random_sample =
383 get_widget_assert (scd->xml,
384 "radiobutton-sample-percent");
386 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
388 const double percentage =
389 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
391 ds_put_c_format (&dss,
392 "COMPUTE %s = RV.UNIFORM (0,1) < %.*g.\n",
394 DBL_DIG + 1, percentage / 100.0 );
399 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
400 const gint from_n_cases =
401 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
404 const gchar ranvar[]="rv_$";
406 ds_put_c_format (&dss,
407 "COMPUTE %s = $CASENUM.\n", key);
409 ds_put_c_format (&dss,
410 "COMPUTE %s = %s > %d.\n",
411 filter, key, from_n_cases);
413 ds_put_c_format (&dss,
414 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
417 ds_put_c_format (&dss,
421 ds_put_cstr (&dss, "EXECUTE.\n");
424 ds_put_c_format (&dss,
425 "COMPUTE %s = $CASENUM.\n",
428 ds_put_c_format (&dss,
429 "COMPUTE %s = %s <= %d\n",
434 ds_put_cstr (&dss, "EXECUTE.\n");
437 ds_put_c_format (&dss,
441 ds_put_c_format (&dss,
442 "DELETE VARIABLES %s, %s.\n",
446 ds_put_cstr (&dss, "EXECUTE.\n");
451 GTK_ENTRY (get_widget_assert (scd->xml,
452 "filter-variable-entry"));
453 filter = gtk_entry_get_text (entry);
456 ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
458 text = ds_steal_cstr (&dss);
466 generate_syntax_delete (const struct select_cases_dialog *scd)
471 if ( gtk_toggle_button_get_active
472 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
473 "radiobutton-all"))))
475 return xstrdup ("\n");
478 ds_init_empty (&dss);
480 if ( gtk_toggle_button_get_active
481 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
482 "radiobutton-sample"))))
484 GtkWidget *random_sample =
485 get_widget_assert (scd->xml,
486 "radiobutton-sample-percent");
488 ds_put_cstr (&dss, "SAMPLE ");
490 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
492 const double percentage =
493 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
494 ds_put_c_format (&dss, "%g.", percentage / 100.0);
499 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
500 const gint from_n_cases =
501 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
503 ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
507 else if ( gtk_toggle_button_get_active
508 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
509 "radiobutton-range"))))
511 GtkSpinButton *first =
512 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
513 "range-dialog-first"));
515 GtkSpinButton *last =
516 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
517 "range-dialog-last"));
519 ds_put_c_format (&dss,
520 "COMPUTE filter_$ = ($CASENUM >= %ld "
521 "AND $CASENUM <= %ld).\n",
522 (long) gtk_spin_button_get_value (first),
523 (long) gtk_spin_button_get_value (last)
525 ds_put_cstr (&dss, "EXECUTE.\n");
526 ds_put_c_format (&dss, "SELECT IF filter_$.\n");
529 else if ( gtk_toggle_button_get_active
531 (get_widget_assert (scd->xml,
532 "radiobutton-filter-variable"))))
535 GTK_ENTRY (get_widget_assert (scd->xml,
536 "filter-variable-entry"));
538 ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
539 gtk_entry_get_text (entry));
543 ds_put_cstr (&dss, "\n");
545 text = ds_steal_cstr (&dss);
554 generate_syntax (const struct select_cases_dialog *scd)
556 /* In the simple case, all we need to do is cancel any existing filter */
557 if ( gtk_toggle_button_get_active
558 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
559 "radiobutton-all"))))
561 return g_strdup ("FILTER OFF.\n");
565 /* Are we filtering or deleting ? */
566 if ( gtk_toggle_button_get_active
567 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
568 "radiobutton-delete"))))
570 return generate_syntax_delete (scd);
574 return generate_syntax_filter (scd);