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);
63 static const gchar label1[]=N_("Approximately %3d%% of all cases.");
64 static const gchar label2[]=N_("Exactly %3d cases from the first %3d cases.");
68 sample_subdialog (GtkButton *b, gpointer data)
71 struct select_cases_dialog *scd = data;
73 gint case_count = psppire_data_store_get_case_count (scd->data_store);
75 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
76 "select-cases-dialog");
77 GtkWidget *dialog = get_widget_assert (scd->xml,
78 "select-cases-random-sample-dialog");
79 GtkWidget *percent = get_widget_assert (scd->xml,
80 "radiobutton-sample-percent");
81 GtkWidget *sample_n_cases = get_widget_assert (scd->xml,
82 "radiobutton-sample-n-cases");
83 GtkWidget *table = get_widget_assert (scd->xml,
84 "select-cases-random-sample-table");
88 scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
90 gtk_widget_show (scd->hbox1);
92 gtk_table_attach_defaults (GTK_TABLE (table),
93 scd->hbox1, 1, 2, 0, 1);
95 g_signal_connect (percent, "toggled",
96 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
98 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (percent), TRUE);
105 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
107 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
110 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
113 gtk_widget_show (scd->hbox2);
114 gtk_widget_set_sensitive (scd->hbox2, FALSE);
116 gtk_table_attach_defaults (GTK_TABLE (table),
117 scd->hbox2, 1, 2, 1, 2);
119 g_signal_connect (sample_n_cases, "toggled",
120 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
122 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_n_cases), FALSE);
126 gtk_window_set_transient_for (GTK_WINDOW (dialog),
127 GTK_WINDOW (parent_dialog));
129 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
131 if ( response != PSPPIRE_RESPONSE_CONTINUE)
133 g_signal_handlers_disconnect_by_func
135 G_CALLBACK (set_sensitivity_from_toggle),
138 g_signal_handlers_disconnect_by_func
139 (G_OBJECT (sample_n_cases),
140 G_CALLBACK (set_sensitivity_from_toggle),
143 gtk_widget_destroy(scd->hbox1);
144 gtk_widget_destroy(scd->hbox2);
145 scd->hbox1 = scd->hbox2 = NULL;
150 GtkWidget *l0 = get_widget_assert (scd->xml, "random-sample-label");
152 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (percent)))
154 text = widget_printf (gettext(label1), scd->spinbutton);
155 gtk_label_set_text (GTK_LABEL (l0), text);
160 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
161 gtk_label_set_text (GTK_LABEL (l0), text);
170 range_subdialog (GtkButton *b, gpointer data)
173 struct select_cases_dialog *scd = data;
175 gint n_cases = psppire_data_store_get_case_count (scd->data_store);
177 GtkWidget *parent_dialog = get_widget_assert (scd->xml,
178 "select-cases-dialog");
180 GtkWidget *dialog = get_widget_assert (scd->xml,
181 "select-cases-range-dialog");
183 GtkWidget *first = get_widget_assert (scd->xml,
184 "range-dialog-first");
186 GtkWidget *last = get_widget_assert (scd->xml,
187 "range-dialog-last");
190 gtk_spin_button_set_range (GTK_SPIN_BUTTON (last), 1, n_cases);
191 gtk_spin_button_set_range (GTK_SPIN_BUTTON (first), 1, n_cases);
193 gtk_window_set_transient_for (GTK_WINDOW (dialog),
194 GTK_WINDOW (parent_dialog));
197 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
198 if ( response == PSPPIRE_RESPONSE_CONTINUE)
200 GtkWidget *first = get_widget_assert (scd->xml, "range-dialog-first");
201 GtkWidget *last = get_widget_assert (scd->xml, "range-dialog-last");
202 GtkWidget *l1 = get_widget_assert (scd->xml, "range-sample-label");
203 gchar *text = widget_printf (_("%d thru %d"), first, last);
205 gtk_label_set_text (GTK_LABEL (l1), text);
212 set_radiobutton (GtkWidget *button, gpointer data)
214 GtkToggleButton *toggle = data;
215 gtk_toggle_button_set_active (toggle, TRUE);
218 /* Pops up the Select Cases dialog box */
220 select_cases_dialog (PsppireDataWindow *de)
223 struct select_cases_dialog scd = {0,0,0,0,0,0};
225 GtkWidget *entry = NULL;
226 GtkWidget *selector ;
227 GtkWidget *button_range;
228 GtkWidget *button_sample;
230 scd.xml = builder_new ("select-cases.ui");
232 g_object_get (de->data_editor, "data-store", &scd.data_store, NULL);
234 button_range = get_widget_assert (scd.xml, "button-range");
235 button_sample = get_widget_assert (scd.xml, "button-sample");
236 entry = get_widget_assert (scd.xml, "filter-variable-entry");
237 selector = get_widget_assert (scd.xml, "psppire-selector-filter");
240 GtkWidget *button_if =
241 get_widget_assert (scd.xml, "button-if");
243 GtkWidget *radiobutton_if =
244 get_widget_assert (scd.xml, "radiobutton-if");
246 GtkWidget *radiobutton_all =
247 get_widget_assert (scd.xml, "radiobutton-all");
249 GtkWidget *radiobutton_sample =
250 get_widget_assert (scd.xml, "radiobutton-sample");
252 GtkWidget *radiobutton_range =
253 get_widget_assert (scd.xml, "radiobutton-range");
255 GtkWidget *radiobutton_filter =
256 get_widget_assert (scd.xml, "radiobutton-filter-variable");
258 GtkWidget *range_label =
259 get_widget_assert (scd.xml, "range-sample-label");
261 GtkWidget *sample_label =
262 get_widget_assert (scd.xml, "random-sample-label");
264 g_signal_connect (radiobutton_all, "toggled",
265 G_CALLBACK (set_sensitivity_from_toggle_invert),
266 get_widget_assert (scd.xml, "filter-delete-button-box")
269 g_signal_connect (button_if, "clicked",
270 G_CALLBACK (set_radiobutton), radiobutton_if);
272 g_signal_connect (button_sample, "clicked",
273 G_CALLBACK (set_radiobutton), radiobutton_sample);
275 g_signal_connect (button_range, "clicked",
276 G_CALLBACK (set_radiobutton), radiobutton_range);
278 g_signal_connect (selector, "clicked",
279 G_CALLBACK (set_radiobutton), radiobutton_filter);
281 g_signal_connect (selector, "selected",
282 G_CALLBACK (set_radiobutton), radiobutton_filter);
284 g_signal_connect (radiobutton_range, "toggled",
285 G_CALLBACK (set_sensitivity_from_toggle),
289 g_signal_connect (radiobutton_sample, "toggled",
290 G_CALLBACK (set_sensitivity_from_toggle),
294 g_signal_connect (radiobutton_filter, "toggled",
295 G_CALLBACK (set_sensitivity_from_toggle),
302 dialog = get_widget_assert (scd.xml, "select-cases-dialog");
303 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
306 GtkWidget *source = get_widget_assert (scd.xml, "select-cases-treeview");
308 g_object_set (source, "model",
309 scd.data_store->dict,
311 GTK_SELECTION_SINGLE, NULL);
313 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
314 is_currently_in_entry);
319 g_signal_connect (button_range,
320 "clicked", G_CALLBACK (range_subdialog), &scd);
323 g_signal_connect (button_sample,
324 "clicked", G_CALLBACK (sample_subdialog), &scd);
327 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
331 case GTK_RESPONSE_OK:
332 g_free (execute_syntax_string (de, generate_syntax (&scd)));
334 case PSPPIRE_RESPONSE_PASTE:
335 g_free (paste_syntax_to_window (generate_syntax (&scd)));
341 g_object_unref (scd.xml);
346 generate_syntax_filter (const struct select_cases_dialog *scd)
351 const gchar *filter = "filter_$";
352 const gchar key[]="case_$";
354 ds_init_empty (&dss);
356 if (gtk_toggle_button_get_active
357 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
358 "radiobutton-range"))))
360 GtkSpinButton *first =
361 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
362 "range-dialog-first"));
364 GtkSpinButton *last =
365 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
366 "range-dialog-last"));
368 ds_put_c_format (&dss,
369 "COMPUTE filter_$ = ($CASENUM >= %ld "
370 "AND $CASENUM <= %ld).\n",
371 (long) gtk_spin_button_get_value (first),
372 (long) gtk_spin_button_get_value (last)
375 ds_put_cstr (&dss, "EXECUTE.\n");
377 else if ( gtk_toggle_button_get_active
378 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
379 "radiobutton-sample"))))
381 GtkWidget *random_sample =
382 get_widget_assert (scd->xml,
383 "radiobutton-sample-percent");
385 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
387 const double percentage =
388 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
390 ds_put_c_format (&dss,
391 "COMPUTE %s = RV.UNIFORM (0,1) < %g.\n",
393 percentage / 100.0 );
398 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
399 const gint from_n_cases =
400 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
403 const gchar ranvar[]="rv_$";
405 ds_put_c_format (&dss,
406 "COMPUTE %s = $CASENUM.\n", key);
408 ds_put_c_format (&dss,
409 "COMPUTE %s = %s > %d.\n",
410 filter, key, from_n_cases);
412 ds_put_c_format (&dss,
413 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
416 ds_put_c_format (&dss,
420 ds_put_cstr (&dss, "EXECUTE.\n");
423 ds_put_c_format (&dss,
424 "COMPUTE %s = $CASENUM.\n",
427 ds_put_c_format (&dss,
428 "COMPUTE %s = %s <= %d\n",
433 ds_put_cstr (&dss, "EXECUTE.\n");
436 ds_put_c_format (&dss,
440 ds_put_c_format (&dss,
441 "DELETE VARIABLES %s, %s.\n",
445 ds_put_cstr (&dss, "EXECUTE.\n");
450 GTK_ENTRY (get_widget_assert (scd->xml,
451 "filter-variable-entry"));
452 filter = gtk_entry_get_text (entry);
455 ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
457 text = ds_steal_cstr (&dss);
465 generate_syntax_delete (const struct select_cases_dialog *scd)
470 if ( gtk_toggle_button_get_active
471 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
472 "radiobutton-all"))))
474 return xstrdup ("\n");
477 ds_init_empty (&dss);
479 if ( gtk_toggle_button_get_active
480 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
481 "radiobutton-sample"))))
483 GtkWidget *random_sample =
484 get_widget_assert (scd->xml,
485 "radiobutton-sample-percent");
487 ds_put_cstr (&dss, "SAMPLE ");
489 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (random_sample)))
491 const double percentage =
492 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
493 ds_put_c_format (&dss, "%g.", percentage / 100.0);
498 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
499 const gint from_n_cases =
500 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
502 ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
506 else if ( gtk_toggle_button_get_active
507 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
508 "radiobutton-range"))))
510 GtkSpinButton *first =
511 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
512 "range-dialog-first"));
514 GtkSpinButton *last =
515 GTK_SPIN_BUTTON (get_widget_assert (scd->xml,
516 "range-dialog-last"));
518 ds_put_c_format (&dss,
519 "COMPUTE filter_$ = ($CASENUM >= %ld "
520 "AND $CASENUM <= %ld).\n",
521 (long) gtk_spin_button_get_value (first),
522 (long) gtk_spin_button_get_value (last)
524 ds_put_cstr (&dss, "EXECUTE.\n");
525 ds_put_c_format (&dss, "SELECT IF filter_$.\n");
528 else if ( gtk_toggle_button_get_active
530 (get_widget_assert (scd->xml,
531 "radiobutton-filter-variable"))))
534 GTK_ENTRY (get_widget_assert (scd->xml,
535 "filter-variable-entry"));
537 ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
538 gtk_entry_get_text (entry));
542 ds_put_cstr (&dss, "\n");
544 text = ds_steal_cstr (&dss);
553 generate_syntax (const struct select_cases_dialog *scd)
555 /* In the simple case, all we need to do is cancel any existing filter */
556 if ( gtk_toggle_button_get_active
557 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
558 "radiobutton-all"))))
560 return g_strdup ("FILTER OFF.\n");
564 /* Are we filtering or deleting ? */
565 if ( gtk_toggle_button_get_active
566 (GTK_TOGGLE_BUTTON (get_widget_assert (scd->xml,
567 "radiobutton-delete"))))
569 return generate_syntax_delete (scd);
573 return generate_syntax_filter (scd);