1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2014, 2015 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 GtkWidget *spinbutton ;
49 GtkWidget *spinbutton1 ;
50 GtkWidget *spinbutton2 ;
55 PsppireDataStore *data_store;
56 GtkWidget *parent_dialog ;
59 GtkWidget *sample_n_cases ;
63 GtkWidget *radiobutton_range ;
66 GtkWidget *radiobutton_sample;
67 GtkWidget *radiobutton_all;
69 GtkWidget *radiobutton_filter;
70 GtkWidget *radiobutton_delete;
71 GtkWidget *range_subdialog;
74 static gchar * generate_syntax (const struct select_cases_dialog *scd);
77 static const gchar label1[] = N_("Approximately %3d%% of all cases.");
78 static const gchar label2[] = N_("Exactly %3d cases from the first %3d cases.");
82 sample_subdialog (GtkButton *b, gpointer data)
85 struct select_cases_dialog *scd = data;
87 gint case_count = psppire_data_store_get_case_count (scd->data_store);
91 scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
93 gtk_widget_show (scd->hbox1);
95 gtk_grid_attach (GTK_GRID (scd->table),
100 g_signal_connect (scd->percent, "toggled",
101 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
103 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scd->percent), TRUE);
110 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
112 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
115 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
118 gtk_widget_show (scd->hbox2);
119 gtk_widget_set_sensitive (scd->hbox2, FALSE);
121 gtk_grid_attach (GTK_GRID (scd->table),
125 g_signal_connect (scd->sample_n_cases, "toggled",
126 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
128 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scd->sample_n_cases), FALSE);
132 gtk_window_set_transient_for (GTK_WINDOW (scd->dialog),
133 GTK_WINDOW (scd->parent_dialog));
135 response = psppire_dialog_run (PSPPIRE_DIALOG (scd->dialog));
137 if ( response != PSPPIRE_RESPONSE_CONTINUE)
139 g_signal_handlers_disconnect_by_func
140 (G_OBJECT (scd->percent),
141 G_CALLBACK (set_sensitivity_from_toggle),
144 g_signal_handlers_disconnect_by_func
145 (G_OBJECT (scd->sample_n_cases),
146 G_CALLBACK (set_sensitivity_from_toggle),
149 gtk_widget_destroy(scd->hbox1);
150 gtk_widget_destroy(scd->hbox2);
151 scd->hbox1 = scd->hbox2 = NULL;
157 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
159 text = widget_printf (gettext(label1), scd->spinbutton);
160 gtk_label_set_text (GTK_LABEL (scd->l0), text);
165 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
166 gtk_label_set_text (GTK_LABEL (scd->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 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->last), 1, n_cases);
182 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->first), 1, n_cases);
184 gtk_window_set_transient_for (GTK_WINDOW (scd->range_subdialog),
185 GTK_WINDOW (scd->parent_dialog));
187 response = psppire_dialog_run (PSPPIRE_DIALOG (scd->range_subdialog));
188 if ( response == PSPPIRE_RESPONSE_CONTINUE)
190 gchar *text = widget_printf (_("%d thru %d"), scd->first, scd->last);
191 gtk_label_set_text (GTK_LABEL (scd->l1), text);
197 set_radiobutton (GtkWidget *button, gpointer data)
199 GtkToggleButton *toggle = data;
200 gtk_toggle_button_set_active (toggle, TRUE);
203 /* Pops up the Select Cases dialog box */
205 select_cases_dialog (PsppireDataWindow *de)
208 struct select_cases_dialog scd = {0,0,0,0,0,0};
209 GtkWidget *entry = NULL;
210 GtkWidget *selector ;
212 GtkBuilder *xml = builder_new ("select-cases.ui");
214 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
217 *button_range = get_widget_assert (xml, "button-range");
219 button_sample = get_widget_assert (xml, "button-sample");
220 scd.entry = get_widget_assert (xml, "filter-variable-entry");
221 selector = get_widget_assert (xml, "psppire-selector-filter");
223 scd.parent_dialog = get_widget_assert (xml, "select-cases-dialog");
224 scd.dialog = get_widget_assert (xml, "select-cases-random-sample-dialog");
225 scd.percent = get_widget_assert (xml, "radiobutton-sample-percent");
226 scd.sample_n_cases = get_widget_assert (xml, "radiobutton-sample-n-cases");
227 scd.table = get_widget_assert (xml, "select-cases-random-sample-table");
229 scd.l0 = get_widget_assert (xml, "random-sample-label");;
231 scd.radiobutton_range = get_widget_assert (xml, "radiobutton-range");
232 scd.range_subdialog = get_widget_assert (xml, "select-cases-range-dialog");
234 scd.first = get_widget_assert (xml, "range-dialog-first");
235 scd.last = get_widget_assert (xml, "range-dialog-last");
237 scd.l1 = get_widget_assert (xml, "range-sample-label");
238 scd.radiobutton_sample = get_widget_assert (xml, "radiobutton-sample");
240 scd.radiobutton_all = get_widget_assert (xml, "radiobutton-all");
241 scd.radiobutton_filter = get_widget_assert (xml, "radiobutton-filter-variable");
242 scd.radiobutton_delete = get_widget_assert (xml, "radiobutton-delete");
245 GtkWidget *button_if =
246 get_widget_assert (xml, "button-if");
248 GtkWidget *radiobutton_if =
249 get_widget_assert (xml, "radiobutton-if");
251 GtkWidget *sample_label =
252 get_widget_assert (xml, "random-sample-label");
254 g_signal_connect (scd.radiobutton_all, "toggled",
255 G_CALLBACK (set_sensitivity_from_toggle_invert),
256 get_widget_assert (xml, "filter-delete-button-box")
259 g_signal_connect (button_if, "clicked",
260 G_CALLBACK (set_radiobutton), radiobutton_if);
262 g_signal_connect (button_sample, "clicked",
263 G_CALLBACK (set_radiobutton), scd.radiobutton_sample);
265 g_signal_connect (button_range, "clicked",
266 G_CALLBACK (set_radiobutton), scd.radiobutton_range);
268 g_signal_connect (selector, "clicked",
269 G_CALLBACK (set_radiobutton), scd.radiobutton_filter);
271 g_signal_connect (selector, "selected",
272 G_CALLBACK (set_radiobutton), scd.radiobutton_filter);
274 g_signal_connect (scd.radiobutton_range, "toggled",
275 G_CALLBACK (set_sensitivity_from_toggle),
278 g_signal_connect (scd.radiobutton_sample, "toggled",
279 G_CALLBACK (set_sensitivity_from_toggle),
282 g_signal_connect (scd.radiobutton_filter, "toggled",
283 G_CALLBACK (set_sensitivity_from_toggle),
289 GtkWidget *dialog = get_widget_assert (xml, "select-cases-dialog");
290 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
293 GtkWidget *source = get_widget_assert (xml, "select-cases-treeview");
295 g_object_set (source, "model",
296 scd.data_store->dict,
298 GTK_SELECTION_SINGLE, NULL);
300 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
301 is_currently_in_entry);
304 g_signal_connect (button_range,
305 "clicked", G_CALLBACK (range_subdialog), &scd);
308 g_signal_connect (button_sample,
309 "clicked", G_CALLBACK (sample_subdialog), &scd);
312 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
316 case GTK_RESPONSE_OK:
317 g_free (execute_syntax_string (de, generate_syntax (&scd)));
319 case PSPPIRE_RESPONSE_PASTE:
320 g_free (paste_syntax_to_window (generate_syntax (&scd)));
326 g_object_unref (xml);
331 generate_syntax_filter (const struct select_cases_dialog *scd)
336 const gchar *filter = "filter_$";
337 const gchar key[]="case_$";
339 ds_init_empty (&dss);
341 if (gtk_toggle_button_get_active
342 (GTK_TOGGLE_BUTTON (scd->radiobutton_range)))
344 ds_put_c_format (&dss,
345 "COMPUTE filter_$ = ($CASENUM >= %ld "
346 "AND $CASENUM <= %ld).\n",
347 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->first)),
348 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->last)));
350 ds_put_cstr (&dss, "EXECUTE.\n");
352 else if ( gtk_toggle_button_get_active
353 (GTK_TOGGLE_BUTTON (scd->radiobutton_sample)))
355 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
357 const double percentage =
358 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
360 ds_put_c_format (&dss,
361 "COMPUTE %s = RV.UNIFORM (0,1) < %.*g.\n",
363 DBL_DIG + 1, percentage / 100.0 );
368 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
369 const gint from_n_cases =
370 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
373 const gchar ranvar[]="rv_$";
375 ds_put_c_format (&dss,
376 "COMPUTE %s = $CASENUM.\n", key);
378 ds_put_c_format (&dss,
379 "COMPUTE %s = %s > %d.\n",
380 filter, key, from_n_cases);
382 ds_put_c_format (&dss,
383 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
386 ds_put_c_format (&dss,
390 ds_put_cstr (&dss, "EXECUTE.\n");
393 ds_put_c_format (&dss,
394 "COMPUTE %s = $CASENUM.\n",
397 ds_put_c_format (&dss,
398 "COMPUTE %s = %s <= %d\n",
403 ds_put_cstr (&dss, "EXECUTE.\n");
406 ds_put_c_format (&dss,
410 ds_put_c_format (&dss,
411 "DELETE VARIABLES %s, %s.\n",
415 ds_put_cstr (&dss, "EXECUTE.\n");
419 filter = gtk_entry_get_text (GTK_ENTRY (scd->entry));
422 ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
424 text = ds_steal_cstr (&dss);
432 generate_syntax_delete (const struct select_cases_dialog *scd)
437 if ( gtk_toggle_button_get_active
438 (GTK_TOGGLE_BUTTON (scd->radiobutton_all)))
440 return xstrdup ("\n");
443 ds_init_empty (&dss);
445 if ( gtk_toggle_button_get_active
446 (GTK_TOGGLE_BUTTON (scd->radiobutton_sample)))
448 ds_put_cstr (&dss, "SAMPLE ");
450 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
452 const double percentage =
453 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
454 ds_put_c_format (&dss, "%g.", percentage / 100.0);
459 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
460 const gint from_n_cases =
461 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
463 ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
467 else if ( gtk_toggle_button_get_active
468 (GTK_TOGGLE_BUTTON (scd->radiobutton_range)))
470 ds_put_c_format (&dss,
471 "COMPUTE filter_$ = ($CASENUM >= %ld "
472 "AND $CASENUM <= %ld).\n",
473 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->first)),
474 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->last)));
475 ds_put_cstr (&dss, "EXECUTE.\n");
476 ds_put_c_format (&dss, "SELECT IF filter_$.\n");
479 else if (gtk_toggle_button_get_active
480 (GTK_TOGGLE_BUTTON (scd->radiobutton_filter)))
482 ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
483 gtk_entry_get_text (GTK_ENTRY (scd->entry)));
487 ds_put_cstr (&dss, "\n");
489 text = ds_steal_cstr (&dss);
498 generate_syntax (const struct select_cases_dialog *scd)
500 /* In the simple case, all we need to do is cancel any existing filter */
501 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->radiobutton_all)))
503 return g_strdup ("FILTER OFF.\n");
506 /* Are we filtering or deleting ? */
507 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->radiobutton_delete)))
509 return generate_syntax_delete (scd);
513 return generate_syntax_filter (scd);