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/>. */
21 #include "builder-wrapper.h"
22 #include "dialog-common.h"
23 #include "dict-display.h"
24 #include "libpspp/str.h"
25 #include "psppire-data-store.h"
26 #include "psppire-data-window.h"
27 #include "psppire-dialog-action-select.h"
28 #include "psppire-dialog.h"
29 #include "psppire-dict.h"
30 #include "psppire-scanf.h"
31 #include "psppire-value-entry.h"
32 #include "psppire-var-view.h"
33 #include "widget-io.h"
35 #include <ui/syntax-gen.h>
40 #define _(msgid) gettext (msgid)
41 #define N_(msgid) msgid
43 static void psppire_dialog_action_select_class_init (PsppireDialogActionSelectClass *class);
45 G_DEFINE_TYPE (PsppireDialogActionSelect, psppire_dialog_action_select, PSPPIRE_TYPE_DIALOG_ACTION);
48 dialog_state_valid (gpointer data)
55 refresh (PsppireDialogAction *pda)
57 PsppireDialogActionSelect *act = PSPPIRE_DIALOG_ACTION_SELECT (pda);
59 gtk_entry_set_text (GTK_ENTRY (act->entry), "");
60 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (act->radiobutton_all), TRUE);
61 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (act->radiobutton_filter), TRUE);
63 gtk_label_set_text (GTK_LABEL (act->l1), "");
64 gtk_label_set_text (GTK_LABEL (act->l0), "");
69 set_radiobutton (GtkWidget *button, gpointer data)
71 GtkToggleButton *toggle = data;
72 gtk_toggle_button_set_active (toggle, TRUE);
76 static const gchar label1[] = N_("Approximately %3d%% of all cases.");
77 static const gchar label2[] = N_("Exactly %3d cases from the first %3d cases.");
81 sample_subdialog (GtkButton *b, gpointer data)
84 PsppireDialogActionSelect *scd = PSPPIRE_DIALOG_ACTION_SELECT (data);
85 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data);
87 PsppireDataStore *data_store = NULL;
88 g_object_get (PSPPIRE_DATA_WINDOW (pda->toplevel)->data_editor,
89 "data-store", &data_store,
92 gint case_count = psppire_data_store_get_case_count (data_store);
96 scd->hbox1 = psppire_scanf_new (gettext (label1), &scd->spinbutton);
98 gtk_widget_show (scd->hbox1);
100 gtk_grid_attach (GTK_GRID (scd->table),
105 g_signal_connect (scd->percent, "toggled",
106 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox1);
108 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scd->percent), TRUE);
115 psppire_scanf_new (gettext (label2), &scd->spinbutton1, &scd->spinbutton2);
117 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton1),
120 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->spinbutton2),
123 gtk_widget_show (scd->hbox2);
124 gtk_widget_set_sensitive (scd->hbox2, FALSE);
126 gtk_grid_attach (GTK_GRID (scd->table),
130 g_signal_connect (scd->sample_n_cases, "toggled",
131 G_CALLBACK (set_sensitivity_from_toggle), scd->hbox2);
133 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scd->sample_n_cases), FALSE);
137 gtk_window_set_transient_for (GTK_WINDOW (scd->rsample_dialog),
138 GTK_WINDOW (pda->dialog));
140 response = psppire_dialog_run (PSPPIRE_DIALOG (scd->rsample_dialog));
142 if ( response != PSPPIRE_RESPONSE_CONTINUE)
144 g_signal_handlers_disconnect_by_func
145 (G_OBJECT (scd->percent),
146 G_CALLBACK (set_sensitivity_from_toggle),
149 g_signal_handlers_disconnect_by_func
150 (G_OBJECT (scd->sample_n_cases),
151 G_CALLBACK (set_sensitivity_from_toggle),
154 gtk_widget_destroy(scd->hbox1);
155 gtk_widget_destroy(scd->hbox2);
156 scd->hbox1 = scd->hbox2 = NULL;
162 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
164 text = widget_printf (gettext(label1), scd->spinbutton);
165 gtk_label_set_text (GTK_LABEL (scd->l0), text);
170 widget_printf (gettext(label2), scd->spinbutton1, scd->spinbutton2);
171 gtk_label_set_text (GTK_LABEL (scd->l0), text);
181 range_subdialog (GtkButton *b, gpointer data)
184 PsppireDialogActionSelect *scd = PSPPIRE_DIALOG_ACTION_SELECT (data);
185 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (data);
187 PsppireDataStore *data_store = NULL;
188 g_object_get (PSPPIRE_DATA_WINDOW (pda->toplevel)->data_editor,
189 "data-store", &data_store,
192 gint n_cases = psppire_data_store_get_case_count (data_store);
194 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->last), 1, n_cases);
195 gtk_spin_button_set_range (GTK_SPIN_BUTTON (scd->first), 1, n_cases);
197 gtk_window_set_transient_for (GTK_WINDOW (scd->range_subdialog),
198 GTK_WINDOW (pda->dialog));
200 response = psppire_dialog_run (PSPPIRE_DIALOG (scd->range_subdialog));
201 if ( response == PSPPIRE_RESPONSE_CONTINUE)
203 gchar *text = widget_printf (_("%d thru %d"), scd->first, scd->last);
204 gtk_label_set_text (GTK_LABEL (scd->l1), text);
211 psppire_dialog_action_select_activate (PsppireDialogAction *a)
213 PsppireDialogActionSelect *act = PSPPIRE_DIALOG_ACTION_SELECT (a);
214 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
216 GHashTable *thing = psppire_dialog_action_get_hash_table (pda);
217 GtkBuilder *xml = g_hash_table_lookup (thing, a);
220 xml = builder_new ("select-cases.ui");
221 g_hash_table_insert (thing, a, xml);
224 pda->dialog = get_widget_assert (xml, "select-cases-dialog");
225 pda->source = get_widget_assert (xml, "select-cases-treeview");
227 g_object_set (pda->source,
228 "selection-mode", GTK_SELECTION_SINGLE,
231 act->entry = get_widget_assert (xml, "filter-variable-entry");
233 GtkWidget *selector = get_widget_assert (xml, "psppire-selector-filter");
234 psppire_selector_set_filter_func (PSPPIRE_SELECTOR (selector),
235 is_currently_in_entry);
237 act->rsample_dialog = get_widget_assert (xml, "select-cases-random-sample-dialog");
238 act->percent = get_widget_assert (xml, "radiobutton-sample-percent");
239 act->sample_n_cases = get_widget_assert (xml, "radiobutton-sample-n-cases");
240 act->table = get_widget_assert (xml, "select-cases-random-sample-table");
242 act->l0 = get_widget_assert (xml, "random-sample-label");;
244 act->radiobutton_range = get_widget_assert (xml, "radiobutton-range");
245 act->range_subdialog = get_widget_assert (xml, "select-cases-range-dialog");
247 act->first = get_widget_assert (xml, "range-dialog-first");
248 act->last = get_widget_assert (xml, "range-dialog-last");
250 act->l1 = get_widget_assert (xml, "range-sample-label");
251 act->radiobutton_sample = get_widget_assert (xml, "radiobutton-sample");
253 act->radiobutton_all = get_widget_assert (xml, "radiobutton-all");
254 act->radiobutton_filter_variable = get_widget_assert (xml, "radiobutton-filter-variable");
256 act->radiobutton_filter = get_widget_assert (xml, "radiobutton-filter");
257 act->radiobutton_delete = get_widget_assert (xml, "radiobutton-delete");
260 GtkWidget *button_range = get_widget_assert (xml, "button-range");
261 GtkWidget *button_sample = get_widget_assert (xml, "button-sample");
263 GtkWidget *button_if =get_widget_assert (xml, "button-if");
265 GtkWidget *radiobutton_if = get_widget_assert (xml, "radiobutton-if");
267 GtkWidget *sample_label = get_widget_assert (xml, "random-sample-label");
269 g_signal_connect (act->radiobutton_all, "toggled",
270 G_CALLBACK (set_sensitivity_from_toggle_invert),
271 get_widget_assert (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), act->radiobutton_sample);
279 g_signal_connect (button_range, "clicked",
280 G_CALLBACK (set_radiobutton), act->radiobutton_range);
282 g_signal_connect (selector, "clicked",
283 G_CALLBACK (set_radiobutton), act->radiobutton_filter_variable);
285 g_signal_connect (selector, "selected",
286 G_CALLBACK (set_radiobutton), act->radiobutton_filter_variable);
288 g_signal_connect (act->radiobutton_range, "toggled",
289 G_CALLBACK (set_sensitivity_from_toggle),
292 g_signal_connect (act->radiobutton_sample, "toggled",
293 G_CALLBACK (set_sensitivity_from_toggle),
296 g_signal_connect (act->radiobutton_filter_variable, "toggled",
297 G_CALLBACK (set_sensitivity_from_toggle),
300 g_signal_connect (button_range,
301 "clicked", G_CALLBACK (range_subdialog), act);
303 g_signal_connect (button_sample,
304 "clicked", G_CALLBACK (sample_subdialog), act);
307 psppire_dialog_action_set_refresh (pda, refresh);
309 psppire_dialog_action_set_valid_predicate (pda,
312 if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_select_parent_class)->activate)
313 PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_select_parent_class)->activate (pda);
318 generate_syntax_filter (PsppireDialogAction *a)
320 PsppireDialogActionSelect *scd = PSPPIRE_DIALOG_ACTION_SELECT (a);
325 const gchar *filter = "filter_$";
326 const gchar key[]="case_$";
328 ds_init_empty (&dss);
330 if (gtk_toggle_button_get_active
331 (GTK_TOGGLE_BUTTON (scd->radiobutton_range)))
333 ds_put_c_format (&dss,
334 "COMPUTE filter_$ = ($CASENUM >= %ld "
335 "AND $CASENUM <= %ld).\n",
336 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->first)),
337 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->last)));
339 ds_put_cstr (&dss, "EXECUTE.\n");
341 else if ( gtk_toggle_button_get_active
342 (GTK_TOGGLE_BUTTON (scd->radiobutton_sample)))
344 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
346 const double percentage =
347 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
349 ds_put_c_format (&dss,
350 "COMPUTE %s = RV.UNIFORM (0,1) < %.*g.\n",
352 DBL_DIG + 1, percentage / 100.0 );
357 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
358 const gint from_n_cases =
359 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
362 const gchar ranvar[]="rv_$";
364 ds_put_c_format (&dss,
365 "COMPUTE %s = $CASENUM.\n", key);
367 ds_put_c_format (&dss,
368 "COMPUTE %s = %s > %d.\n",
369 filter, key, from_n_cases);
371 ds_put_c_format (&dss,
372 "COMPUTE %s = RV.UNIFORM (0, 1).\n",
375 ds_put_c_format (&dss,
379 ds_put_cstr (&dss, "EXECUTE.\n");
382 ds_put_c_format (&dss,
383 "COMPUTE %s = $CASENUM.\n",
386 ds_put_c_format (&dss,
387 "COMPUTE %s = %s <= %d\n",
392 ds_put_cstr (&dss, "EXECUTE.\n");
395 ds_put_c_format (&dss,
399 ds_put_c_format (&dss,
400 "DELETE VARIABLES %s, %s.\n",
404 ds_put_cstr (&dss, "EXECUTE.\n");
408 filter = gtk_entry_get_text (GTK_ENTRY (scd->entry));
411 ds_put_c_format (&dss, "FILTER BY %s.\n", filter);
413 text = ds_steal_cstr (&dss);
422 generate_syntax_delete (PsppireDialogAction *a)
424 PsppireDialogActionSelect *scd = PSPPIRE_DIALOG_ACTION_SELECT (a);
428 if ( gtk_toggle_button_get_active
429 (GTK_TOGGLE_BUTTON (scd->radiobutton_all)))
431 return xstrdup ("\n");
434 ds_init_empty (&dss);
436 if ( gtk_toggle_button_get_active
437 (GTK_TOGGLE_BUTTON (scd->radiobutton_sample)))
439 ds_put_cstr (&dss, "SAMPLE ");
441 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->percent)))
443 const double percentage =
444 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton));
445 ds_put_c_format (&dss, "%g.", percentage / 100.0);
450 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton1));
451 const gint from_n_cases =
452 gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->spinbutton2));
454 ds_put_c_format (&dss, "%d FROM %d .", n_cases, from_n_cases);
458 else if ( gtk_toggle_button_get_active
459 (GTK_TOGGLE_BUTTON (scd->radiobutton_range)))
461 ds_put_c_format (&dss,
462 "COMPUTE filter_$ = ($CASENUM >= %ld "
463 "AND $CASENUM <= %ld).\n",
464 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->first)),
465 (long) gtk_spin_button_get_value (GTK_SPIN_BUTTON (scd->last)));
466 ds_put_cstr (&dss, "EXECUTE.\n");
467 ds_put_c_format (&dss, "SELECT IF filter_$.\n");
470 else if (gtk_toggle_button_get_active
471 (GTK_TOGGLE_BUTTON (scd->radiobutton_filter_variable)))
473 ds_put_c_format (&dss, "SELECT IF (%s <> 0).",
474 gtk_entry_get_text (GTK_ENTRY (scd->entry)));
478 ds_put_cstr (&dss, "\n");
480 text = ds_steal_cstr (&dss);
489 generate_syntax (PsppireDialogAction *a)
491 PsppireDialogActionSelect *scd = PSPPIRE_DIALOG_ACTION_SELECT (a);
493 /* In the simple case, all we need to do is cancel any existing filter */
494 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->radiobutton_all)))
496 return g_strdup ("FILTER OFF.\n");
499 /* Are we filtering or deleting ? */
500 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (scd->radiobutton_delete)))
502 return generate_syntax_delete (a);
506 return generate_syntax_filter (a);
512 psppire_dialog_action_select_class_init (PsppireDialogActionSelectClass *class)
514 psppire_dialog_action_set_activation (class, psppire_dialog_action_select_activate);
516 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
521 psppire_dialog_action_select_init (PsppireDialogActionSelect *act)