1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2010 Free Software Foundation
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 "checkbox-treeview.h"
20 #include "frequencies-dialog.h"
21 #include "psppire-var-view.h"
26 #include <language/syntax-string-source.h>
27 #include <ui/gui/psppire-data-window.h>
28 #include <ui/gui/dialog-common.h>
29 #include <ui/gui/dict-display.h>
30 #include <ui/gui/helper.h>
31 #include <ui/gui/psppire-dialog.h>
32 #include <ui/gui/psppire-var-store.h>
36 #define _(msgid) gettext (msgid)
37 #define N_(msgid) msgid
40 #define FREQUENCY_STATS \
41 FS (MEAN, N_("Mean")) \
42 FS (STDDEV, N_("Standard deviation")) \
43 FS (MINIMUM, N_("Minimum")) \
44 FS (MAXIMUM, N_("Maximum")) \
45 FS (SEMEAN, N_("Standard error of the mean")) \
46 FS (VARIANCE, N_("Variance")) \
47 FS (SKEWNESS, N_("Skewness")) \
48 FS (SESKEW, N_("Standard error of the skewness")) \
49 FS (RANGE, N_("Range")) \
50 FS (MODE, N_("Mode")) \
51 FS (KURTOSIS, N_("Kurtosis")) \
52 FS (SEKURT, N_("Standard error of the kurtosis")) \
53 FS (MEDIAN, N_("Median")) \
58 #define FS(NAME, LABEL) FS_##NAME,
66 #define FS(NAME, LABEL) B_FS_##NAME = 1u << FS_##NAME,
69 B_FS_ALL = (1u << N_FREQUENCY_STATS) - 1,
70 B_FS_DEFAULT = B_FS_MEAN | B_FS_STDDEV | B_FS_MINIMUM | B_FS_MAXIMUM
74 static const struct checkbox_entry_item stats[] =
76 #define FS(NAME, LABEL) {#NAME, LABEL},
100 enum frq_order order;
101 enum frq_table table;
111 struct charts_options
119 enum frq_scale scale;
121 bool pie_include_missing;
124 struct frequencies_dialog
127 GtkTreeView *stat_vars;
130 GtkWidget *tables_button;
131 GtkWidget *charts_button;
133 GtkToggleButton *include_missing;
137 /* Frequency Tables dialog. */
138 GtkWidget *tables_dialog;
139 struct tables_options tables_opts;
141 GtkToggleButton *always;
142 GtkToggleButton *never;
143 GtkToggleButton *limit;
144 GtkSpinButton *limit_spinbutton;
146 GtkToggleButton *avalue;
147 GtkToggleButton *dvalue;
148 GtkToggleButton *afreq;
149 GtkToggleButton *dfreq;
152 GtkWidget *charts_dialog;
153 struct charts_options charts_opts;
155 GtkToggleButton *freqs;
156 GtkToggleButton *percents;
158 GtkToggleButton *min;
159 GtkSpinButton *min_spin;
160 GtkToggleButton *max;
161 GtkSpinButton *max_spin;
163 GtkToggleButton *hist;
164 GtkToggleButton *normal;
166 GtkToggleButton *pie;
167 GtkToggleButton *pie_include_missing;
171 refresh (PsppireDialog *dialog, struct frequencies_dialog *fd)
177 GtkTreeModel *liststore = gtk_tree_view_get_model (fd->stat_vars);
178 gtk_list_store_clear (GTK_LIST_STORE (liststore));
180 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
181 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
182 gtk_list_store_set (GTK_LIST_STORE (fd->stats), &iter,
183 CHECKBOX_COLUMN_SELECTED,
184 (B_FS_DEFAULT & (1u << i)) ? true : false, -1);
188 generate_syntax (const struct frequencies_dialog *fd)
196 GString *string = g_string_new ("FREQUENCIES");
198 g_string_append (string, "\n\t/VARIABLES=");
199 psppire_var_view_append_names (PSPPIRE_VAR_VIEW (fd->stat_vars), 0, string);
201 g_string_append (string, "\n\t/FORMAT=");
203 switch (fd->tables_opts.order)
206 g_string_append (string, "AVALUE");
209 g_string_append (string, "DVALUE");
212 g_string_append (string, "AFREQ");
215 g_string_append (string, "DFREQ");
218 g_assert_not_reached();
221 g_string_append (string, " ");
223 switch (fd->tables_opts.table)
226 g_string_append (string, "TABLE");
229 g_string_append (string, "NOTABLE");
232 g_string_append_printf (string, "LIMIT (%d)", fd->tables_opts.limit);
237 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
238 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
241 gtk_tree_model_get (fd->stats, &iter,
242 CHECKBOX_COLUMN_SELECTED, &toggled, -1);
247 if (selected != B_FS_DEFAULT)
249 g_string_append (string, "\n\t/STATISTICS=");
250 if (selected == B_FS_ALL)
251 g_string_append (string, "ALL");
252 else if (selected == 0)
253 g_string_append (string, "NONE");
257 if ((selected & B_FS_DEFAULT) == B_FS_DEFAULT)
259 g_string_append (string, "DEFAULT");
260 selected &= ~B_FS_DEFAULT;
263 for (i = 0; i < N_FREQUENCY_STATS; i++)
264 if (selected & (1u << i))
267 g_string_append (string, " ");
268 g_string_append (string, stats[i].name);
273 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->include_missing)))
274 g_string_append (string, "\n\t/MISSING=INCLUDE");
276 if (fd->charts_opts.draw_hist)
278 g_string_append (string, "\n\t/HISTOGRAM=");
279 g_string_append (string,
280 fd->charts_opts.draw_normal ? "NORMAL" : "NONORMAL");
282 if (fd->charts_opts.scale == FRQ_PERCENT)
283 g_string_append (string, " PERCENT");
285 if (fd->charts_opts.use_min)
286 g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts.min);
287 if (fd->charts_opts.use_max)
288 g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts.max);
291 if (fd->charts_opts.draw_pie)
293 g_string_append (string, "\n\t/PIECHART=");
295 if (fd->charts_opts.pie_include_missing)
296 g_string_append (string, " MISSING");
298 if (fd->charts_opts.use_min)
299 g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts.min);
300 if (fd->charts_opts.use_max)
301 g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts.max);
304 g_string_append (string, ".\n");
308 g_string_free (string, FALSE);
313 /* Dialog is valid iff at least one variable has been selected */
315 dialog_state_valid (gpointer data)
317 struct frequencies_dialog *fd = data;
319 GtkTreeModel *vars = gtk_tree_view_get_model (fd->stat_vars);
323 return gtk_tree_model_get_iter_first (vars, ¬used);
328 on_tables_clicked (struct frequencies_dialog *fd)
332 switch (fd->tables_opts.order)
335 gtk_toggle_button_set_active (fd->avalue, TRUE);
338 gtk_toggle_button_set_active (fd->dvalue, TRUE);
341 gtk_toggle_button_set_active (fd->afreq, TRUE);
344 gtk_toggle_button_set_active (fd->dfreq, TRUE);
348 switch (fd->tables_opts.table)
351 gtk_toggle_button_set_active (fd->always, TRUE);
354 gtk_toggle_button_set_active (fd->never, TRUE);
357 gtk_toggle_button_set_active (fd->limit, TRUE);
360 gtk_spin_button_set_value (fd->limit_spinbutton,
361 fd->tables_opts.limit);
362 g_signal_emit_by_name (fd->limit, "toggled");
364 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->tables_dialog));
366 if ( ret == PSPPIRE_RESPONSE_CONTINUE )
368 if (gtk_toggle_button_get_active (fd->avalue))
369 fd->tables_opts.order = FRQ_AVALUE;
370 else if (gtk_toggle_button_get_active (fd->dvalue))
371 fd->tables_opts.order = FRQ_DVALUE;
372 else if (gtk_toggle_button_get_active (fd->afreq))
373 fd->tables_opts.order = FRQ_ACOUNT;
374 else if (gtk_toggle_button_get_active (fd->dfreq))
375 fd->tables_opts.order = FRQ_DCOUNT;
377 if (gtk_toggle_button_get_active (fd->always))
378 fd->tables_opts.table = FRQ_TABLE;
379 else if (gtk_toggle_button_get_active (fd->never))
380 fd->tables_opts.table = FRQ_NOTABLE;
382 fd->tables_opts.table = FRQ_LIMIT;
384 fd->tables_opts.limit = gtk_spin_button_get_value (fd->limit_spinbutton);
389 on_charts_clicked (struct frequencies_dialog *fd)
393 gtk_toggle_button_set_active (fd->min, fd->charts_opts.use_min);
394 gtk_spin_button_set_value (fd->min_spin, fd->charts_opts.min);
395 g_signal_emit_by_name (fd->min, "toggled");
397 gtk_toggle_button_set_active (fd->max, fd->charts_opts.use_max);
398 gtk_spin_button_set_value (fd->max_spin, fd->charts_opts.max);
399 g_signal_emit_by_name (fd->max, "toggled");
401 gtk_toggle_button_set_active (fd->hist, fd->charts_opts.draw_hist);
402 gtk_toggle_button_set_active (fd->normal, fd->charts_opts.draw_normal);
403 g_signal_emit_by_name (fd->hist, "toggled");
405 switch (fd->charts_opts.scale)
408 gtk_toggle_button_set_active (fd->freqs, TRUE);
411 gtk_toggle_button_set_active (fd->percents, TRUE);
416 gtk_toggle_button_set_active (fd->pie, fd->charts_opts.draw_pie);
417 gtk_toggle_button_set_active (fd->pie_include_missing,
418 fd->charts_opts.pie_include_missing);
419 g_signal_emit_by_name (fd->pie, "toggled");
421 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->charts_dialog));
423 if ( ret == PSPPIRE_RESPONSE_CONTINUE )
425 fd->charts_opts.use_min = gtk_toggle_button_get_active (fd->min);
426 fd->charts_opts.min = gtk_spin_button_get_value (fd->min_spin);
428 fd->charts_opts.use_max = gtk_toggle_button_get_active (fd->max);
429 fd->charts_opts.max = gtk_spin_button_get_value (fd->max_spin);
431 fd->charts_opts.draw_hist = gtk_toggle_button_get_active (fd->hist);
432 fd->charts_opts.draw_normal = gtk_toggle_button_get_active (fd->normal);
433 if (gtk_toggle_button_get_active (fd->freqs))
434 fd->charts_opts.scale = FRQ_FREQ;
435 else if (gtk_toggle_button_get_active (fd->percents))
436 fd->charts_opts.scale = FRQ_PERCENT;
438 fd->charts_opts.draw_pie = gtk_toggle_button_get_active (fd->pie);
439 fd->charts_opts.pie_include_missing
440 = gtk_toggle_button_get_active (fd->pie_include_missing);
445 /* Makes widget W's sensitivity follow the active state of TOGGLE */
447 sensitive_if_active (GtkToggleButton *toggle, GtkWidget *w)
449 gboolean active = gtk_toggle_button_get_active (toggle);
451 gtk_widget_set_sensitive (w, active);
454 /* Pops up the Frequencies dialog box */
456 frequencies_dialog (GObject *o, gpointer data)
459 PsppireDataWindow *de = PSPPIRE_DATA_WINDOW (data);
461 struct frequencies_dialog fd;
463 GtkBuilder *xml = builder_new ("frequencies.ui");
465 GtkWidget *dialog = get_widget_assert (xml, "frequencies-dialog");
466 GtkWidget *source = get_widget_assert (xml, "dict-treeview");
467 GtkWidget *dest = get_widget_assert (xml, "var-treeview");
468 GtkWidget *tables_button = get_widget_assert (xml, "tables-button");
469 GtkWidget *charts_button = get_widget_assert (xml, "charts-button");
470 GtkWidget *stats_treeview = get_widget_assert (xml, "stats-treeview");
472 PsppireVarStore *vs = NULL;
474 g_object_get (de->data_editor, "var-store", &vs, NULL);
476 put_checkbox_items_in_treeview (GTK_TREE_VIEW(stats_treeview),
483 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
485 g_object_get (vs, "dictionary", &fd.dict, NULL);
486 g_object_set (source, "model", fd.dict, NULL);
488 fd.stat_vars = GTK_TREE_VIEW (dest);
489 fd.tables_button = get_widget_assert (xml, "tables-button");
490 fd.charts_button = get_widget_assert (xml, "charts-button");
492 fd.include_missing = GTK_TOGGLE_BUTTON (
493 get_widget_assert (xml, "include_missing"));
495 fd.stats = gtk_tree_view_get_model (GTK_TREE_VIEW (stats_treeview));
497 /* Frequency Tables dialog. */
498 fd.tables_dialog = get_widget_assert (xml, "tables-dialog");
499 fd.tables_opts.order = FRQ_AVALUE;
500 fd.tables_opts.table = FRQ_TABLE;
501 fd.tables_opts.limit = 50;
503 fd.always = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "always"));
504 fd.never = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "never"));
505 fd.limit = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "limit"));
506 fd.limit_spinbutton =
507 GTK_SPIN_BUTTON (get_widget_assert (xml, "limit-spin"));
508 g_signal_connect (fd.limit, "toggled",
509 G_CALLBACK (sensitive_if_active), fd.limit_spinbutton);
511 fd.avalue = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "avalue"));
512 fd.dvalue = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "dvalue"));
513 fd.afreq = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "afreq"));
514 fd.dfreq = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "dfreq"));
516 gtk_window_set_transient_for (GTK_WINDOW (fd.tables_dialog),
520 fd.charts_dialog = get_widget_assert (xml, "charts-dialog");
521 fd.charts_opts.use_min = false;
522 fd.charts_opts.min = 0;
523 fd.charts_opts.use_max = false;
524 fd.charts_opts.max = 100;
525 fd.charts_opts.draw_hist = false;
526 fd.charts_opts.draw_normal = false;
527 fd.charts_opts.scale = FRQ_FREQ;
528 fd.charts_opts.draw_pie = false;
529 fd.charts_opts.pie_include_missing = false;
531 fd.freqs = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "freqs"));
532 fd.percents = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "percents"));
534 fd.min = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "min"));
535 fd.min_spin = GTK_SPIN_BUTTON (get_widget_assert (xml, "min-spin"));
536 g_signal_connect (fd.min, "toggled",
537 G_CALLBACK (sensitive_if_active), fd.min_spin);
538 fd.max = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "max"));
539 fd.max_spin = GTK_SPIN_BUTTON (get_widget_assert (xml, "max-spin"));
540 g_signal_connect (fd.max, "toggled",
541 G_CALLBACK (sensitive_if_active), fd.max_spin);
543 fd.hist = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "hist"));
544 fd.normal = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "normal"));
545 g_signal_connect (fd.hist, "toggled",
546 G_CALLBACK (sensitive_if_active), fd.normal);
548 fd.pie = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pie"));
549 fd.pie_include_missing = GTK_TOGGLE_BUTTON (
550 get_widget_assert (xml, "pie-include-missing"));
551 g_signal_connect (fd.pie, "toggled",
552 G_CALLBACK (sensitive_if_active), fd.pie_include_missing);
554 gtk_window_set_transient_for (GTK_WINDOW (fd.charts_dialog),
558 g_signal_connect (dialog, "refresh", G_CALLBACK (refresh), &fd);
560 psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog),
561 dialog_state_valid, &fd);
563 g_signal_connect_swapped (tables_button, "clicked",
564 G_CALLBACK (on_tables_clicked), &fd);
565 g_signal_connect_swapped (charts_button, "clicked",
566 G_CALLBACK (on_charts_clicked), &fd);
568 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
573 case GTK_RESPONSE_OK:
575 gchar *syntax = generate_syntax (&fd);
577 struct getl_interface *sss = create_syntax_string_source (syntax);
578 execute_syntax (sss);
583 case PSPPIRE_RESPONSE_PASTE:
585 gchar *syntax = generate_syntax (&fd);
586 paste_syntax_in_new_window (syntax);
594 g_object_unref (xml);