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 <ui/gui/psppire-data-window.h>
27 #include <ui/gui/dialog-common.h>
28 #include <ui/gui/dict-display.h>
29 #include <ui/gui/helper.h>
30 #include <ui/gui/psppire-dialog.h>
31 #include <ui/gui/psppire-var-store.h>
35 #define _(msgid) gettext (msgid)
36 #define N_(msgid) msgid
39 #define FREQUENCY_STATS \
40 FS (MEAN, N_("Mean")) \
41 FS (STDDEV, N_("Standard deviation")) \
42 FS (MINIMUM, N_("Minimum")) \
43 FS (MAXIMUM, N_("Maximum")) \
44 FS (SEMEAN, N_("Standard error of the mean")) \
45 FS (VARIANCE, N_("Variance")) \
46 FS (SKEWNESS, N_("Skewness")) \
47 FS (SESKEW, N_("Standard error of the skewness")) \
48 FS (RANGE, N_("Range")) \
49 FS (MODE, N_("Mode")) \
50 FS (KURTOSIS, N_("Kurtosis")) \
51 FS (SEKURT, N_("Standard error of the kurtosis")) \
52 FS (MEDIAN, N_("Median")) \
57 #define FS(NAME, LABEL) FS_##NAME,
65 #define FS(NAME, LABEL) B_FS_##NAME = 1u << FS_##NAME,
68 B_FS_ALL = (1u << N_FREQUENCY_STATS) - 1,
69 B_FS_DEFAULT = B_FS_MEAN | B_FS_STDDEV | B_FS_MINIMUM | B_FS_MAXIMUM
73 static const struct checkbox_entry_item stats[] =
75 #define FS(NAME, LABEL) {#NAME, LABEL},
100 enum frq_table table;
110 struct charts_options
118 enum frq_scale scale;
120 bool pie_include_missing;
123 struct frequencies_dialog
126 GtkTreeView *stat_vars;
129 GtkWidget *tables_button;
130 GtkWidget *charts_button;
132 GtkToggleButton *include_missing;
136 /* Frequency Tables dialog. */
137 GtkWidget *tables_dialog;
138 struct tables_options tables_opts;
140 GtkToggleButton *always;
141 GtkToggleButton *never;
142 GtkToggleButton *limit;
143 GtkSpinButton *limit_spinbutton;
145 GtkToggleButton *avalue;
146 GtkToggleButton *dvalue;
147 GtkToggleButton *afreq;
148 GtkToggleButton *dfreq;
151 GtkWidget *charts_dialog;
152 struct charts_options charts_opts;
154 GtkToggleButton *freqs;
155 GtkToggleButton *percents;
157 GtkToggleButton *min;
158 GtkSpinButton *min_spin;
159 GtkToggleButton *max;
160 GtkSpinButton *max_spin;
162 GtkToggleButton *hist;
163 GtkToggleButton *normal;
165 GtkToggleButton *pie;
166 GtkToggleButton *pie_include_missing;
170 refresh (PsppireDialog *dialog, struct frequencies_dialog *fd)
176 GtkTreeModel *liststore = gtk_tree_view_get_model (fd->stat_vars);
177 gtk_list_store_clear (GTK_LIST_STORE (liststore));
179 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
180 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
181 gtk_list_store_set (GTK_LIST_STORE (fd->stats), &iter,
182 CHECKBOX_COLUMN_SELECTED,
183 (B_FS_DEFAULT & (1u << i)) ? true : false, -1);
187 generate_syntax (const struct frequencies_dialog *fd)
195 GString *string = g_string_new ("FREQUENCIES");
197 g_string_append (string, "\n\t/VARIABLES=");
198 psppire_var_view_append_names (PSPPIRE_VAR_VIEW (fd->stat_vars), 0, string);
200 g_string_append (string, "\n\t/FORMAT=");
202 switch (fd->tables_opts.order)
205 g_string_append (string, "AVALUE");
208 g_string_append (string, "DVALUE");
211 g_string_append (string, "AFREQ");
214 g_string_append (string, "DFREQ");
217 g_assert_not_reached();
220 g_string_append (string, " ");
222 switch (fd->tables_opts.table)
225 g_string_append (string, "TABLE");
228 g_string_append (string, "NOTABLE");
231 g_string_append_printf (string, "LIMIT (%d)", fd->tables_opts.limit);
236 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
237 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
240 gtk_tree_model_get (fd->stats, &iter,
241 CHECKBOX_COLUMN_SELECTED, &toggled, -1);
246 if (selected != B_FS_DEFAULT)
248 g_string_append (string, "\n\t/STATISTICS=");
249 if (selected == B_FS_ALL)
250 g_string_append (string, "ALL");
251 else if (selected == 0)
252 g_string_append (string, "NONE");
256 if ((selected & B_FS_DEFAULT) == B_FS_DEFAULT)
258 g_string_append (string, "DEFAULT");
259 selected &= ~B_FS_DEFAULT;
262 for (i = 0; i < N_FREQUENCY_STATS; i++)
263 if (selected & (1u << i))
266 g_string_append (string, " ");
267 g_string_append (string, stats[i].name);
272 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->include_missing)))
273 g_string_append (string, "\n\t/MISSING=INCLUDE");
275 if (fd->charts_opts.draw_hist)
277 g_string_append (string, "\n\t/HISTOGRAM=");
278 g_string_append (string,
279 fd->charts_opts.draw_normal ? "NORMAL" : "NONORMAL");
281 if (fd->charts_opts.scale == FRQ_PERCENT)
282 g_string_append (string, " PERCENT");
284 if (fd->charts_opts.use_min)
285 g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts.min);
286 if (fd->charts_opts.use_max)
287 g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts.max);
290 if (fd->charts_opts.draw_pie)
292 g_string_append (string, "\n\t/PIECHART=");
294 if (fd->charts_opts.pie_include_missing)
295 g_string_append (string, " MISSING");
297 if (fd->charts_opts.use_min)
298 g_string_append_printf (string, " MIN(%.15g)", fd->charts_opts.min);
299 if (fd->charts_opts.use_max)
300 g_string_append_printf (string, " MAX(%.15g)", fd->charts_opts.max);
303 g_string_append (string, ".\n");
307 g_string_free (string, FALSE);
312 /* Dialog is valid iff at least one variable has been selected */
314 dialog_state_valid (gpointer data)
316 struct frequencies_dialog *fd = data;
318 GtkTreeModel *vars = gtk_tree_view_get_model (fd->stat_vars);
322 return gtk_tree_model_get_iter_first (vars, ¬used);
327 on_tables_clicked (struct frequencies_dialog *fd)
331 switch (fd->tables_opts.order)
334 gtk_toggle_button_set_active (fd->avalue, TRUE);
337 gtk_toggle_button_set_active (fd->dvalue, TRUE);
340 gtk_toggle_button_set_active (fd->afreq, TRUE);
343 gtk_toggle_button_set_active (fd->dfreq, TRUE);
347 switch (fd->tables_opts.table)
350 gtk_toggle_button_set_active (fd->always, TRUE);
353 gtk_toggle_button_set_active (fd->never, TRUE);
356 gtk_toggle_button_set_active (fd->limit, TRUE);
359 gtk_spin_button_set_value (fd->limit_spinbutton,
360 fd->tables_opts.limit);
361 g_signal_emit_by_name (fd->limit, "toggled");
363 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->tables_dialog));
365 if ( ret == PSPPIRE_RESPONSE_CONTINUE )
367 if (gtk_toggle_button_get_active (fd->avalue))
368 fd->tables_opts.order = FRQ_AVALUE;
369 else if (gtk_toggle_button_get_active (fd->dvalue))
370 fd->tables_opts.order = FRQ_DVALUE;
371 else if (gtk_toggle_button_get_active (fd->afreq))
372 fd->tables_opts.order = FRQ_ACOUNT;
373 else if (gtk_toggle_button_get_active (fd->dfreq))
374 fd->tables_opts.order = FRQ_DCOUNT;
376 if (gtk_toggle_button_get_active (fd->always))
377 fd->tables_opts.table = FRQ_TABLE;
378 else if (gtk_toggle_button_get_active (fd->never))
379 fd->tables_opts.table = FRQ_NOTABLE;
381 fd->tables_opts.table = FRQ_LIMIT;
383 fd->tables_opts.limit = gtk_spin_button_get_value (fd->limit_spinbutton);
388 on_charts_clicked (struct frequencies_dialog *fd)
392 gtk_toggle_button_set_active (fd->min, fd->charts_opts.use_min);
393 gtk_spin_button_set_value (fd->min_spin, fd->charts_opts.min);
394 g_signal_emit_by_name (fd->min, "toggled");
396 gtk_toggle_button_set_active (fd->max, fd->charts_opts.use_max);
397 gtk_spin_button_set_value (fd->max_spin, fd->charts_opts.max);
398 g_signal_emit_by_name (fd->max, "toggled");
400 gtk_toggle_button_set_active (fd->hist, fd->charts_opts.draw_hist);
401 gtk_toggle_button_set_active (fd->normal, fd->charts_opts.draw_normal);
402 g_signal_emit_by_name (fd->hist, "toggled");
404 switch (fd->charts_opts.scale)
407 gtk_toggle_button_set_active (fd->freqs, TRUE);
410 gtk_toggle_button_set_active (fd->percents, TRUE);
415 gtk_toggle_button_set_active (fd->pie, fd->charts_opts.draw_pie);
416 gtk_toggle_button_set_active (fd->pie_include_missing,
417 fd->charts_opts.pie_include_missing);
418 g_signal_emit_by_name (fd->pie, "toggled");
420 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->charts_dialog));
422 if ( ret == PSPPIRE_RESPONSE_CONTINUE )
424 fd->charts_opts.use_min = gtk_toggle_button_get_active (fd->min);
425 fd->charts_opts.min = gtk_spin_button_get_value (fd->min_spin);
427 fd->charts_opts.use_max = gtk_toggle_button_get_active (fd->max);
428 fd->charts_opts.max = gtk_spin_button_get_value (fd->max_spin);
430 fd->charts_opts.draw_hist = gtk_toggle_button_get_active (fd->hist);
431 fd->charts_opts.draw_normal = gtk_toggle_button_get_active (fd->normal);
432 if (gtk_toggle_button_get_active (fd->freqs))
433 fd->charts_opts.scale = FRQ_FREQ;
434 else if (gtk_toggle_button_get_active (fd->percents))
435 fd->charts_opts.scale = FRQ_PERCENT;
437 fd->charts_opts.draw_pie = gtk_toggle_button_get_active (fd->pie);
438 fd->charts_opts.pie_include_missing
439 = gtk_toggle_button_get_active (fd->pie_include_missing);
444 /* Makes widget W's sensitivity follow the active state of TOGGLE */
446 sensitive_if_active (GtkToggleButton *toggle, GtkWidget *w)
448 gboolean active = gtk_toggle_button_get_active (toggle);
450 gtk_widget_set_sensitive (w, active);
453 /* Pops up the Frequencies dialog box */
455 frequencies_dialog (PsppireDataWindow *de)
459 struct frequencies_dialog fd;
461 GtkBuilder *xml = builder_new ("frequencies.ui");
463 GtkWidget *dialog = get_widget_assert (xml, "frequencies-dialog");
464 GtkWidget *source = get_widget_assert (xml, "dict-treeview");
465 GtkWidget *dest = get_widget_assert (xml, "var-treeview");
466 GtkWidget *tables_button = get_widget_assert (xml, "tables-button");
467 GtkWidget *charts_button = get_widget_assert (xml, "charts-button");
468 GtkWidget *stats_treeview = get_widget_assert (xml, "stats-treeview");
470 PsppireVarStore *vs = NULL;
472 g_object_get (de->data_editor, "var-store", &vs, NULL);
474 put_checkbox_items_in_treeview (GTK_TREE_VIEW(stats_treeview),
481 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (de));
483 g_object_get (vs, "dictionary", &fd.dict, NULL);
484 g_object_set (source, "model", fd.dict, NULL);
486 fd.stat_vars = GTK_TREE_VIEW (dest);
487 fd.tables_button = get_widget_assert (xml, "tables-button");
488 fd.charts_button = get_widget_assert (xml, "charts-button");
490 fd.include_missing = GTK_TOGGLE_BUTTON (
491 get_widget_assert (xml, "include_missing"));
493 fd.stats = gtk_tree_view_get_model (GTK_TREE_VIEW (stats_treeview));
495 /* Frequency Tables dialog. */
496 fd.tables_dialog = get_widget_assert (xml, "tables-dialog");
497 fd.tables_opts.order = FRQ_AVALUE;
498 fd.tables_opts.table = FRQ_TABLE;
499 fd.tables_opts.limit = 50;
501 fd.always = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "always"));
502 fd.never = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "never"));
503 fd.limit = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "limit"));
504 fd.limit_spinbutton =
505 GTK_SPIN_BUTTON (get_widget_assert (xml, "limit-spin"));
506 g_signal_connect (fd.limit, "toggled",
507 G_CALLBACK (sensitive_if_active), fd.limit_spinbutton);
509 fd.avalue = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "avalue"));
510 fd.dvalue = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "dvalue"));
511 fd.afreq = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "afreq"));
512 fd.dfreq = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "dfreq"));
514 gtk_window_set_transient_for (GTK_WINDOW (fd.tables_dialog),
518 fd.charts_dialog = get_widget_assert (xml, "charts-dialog");
519 fd.charts_opts.use_min = false;
520 fd.charts_opts.min = 0;
521 fd.charts_opts.use_max = false;
522 fd.charts_opts.max = 100;
523 fd.charts_opts.draw_hist = false;
524 fd.charts_opts.draw_normal = false;
525 fd.charts_opts.scale = FRQ_FREQ;
526 fd.charts_opts.draw_pie = false;
527 fd.charts_opts.pie_include_missing = false;
529 fd.freqs = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "freqs"));
530 fd.percents = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "percents"));
532 fd.min = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "min"));
533 fd.min_spin = GTK_SPIN_BUTTON (get_widget_assert (xml, "min-spin"));
534 g_signal_connect (fd.min, "toggled",
535 G_CALLBACK (sensitive_if_active), fd.min_spin);
536 fd.max = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "max"));
537 fd.max_spin = GTK_SPIN_BUTTON (get_widget_assert (xml, "max-spin"));
538 g_signal_connect (fd.max, "toggled",
539 G_CALLBACK (sensitive_if_active), fd.max_spin);
541 fd.hist = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "hist"));
542 fd.normal = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "normal"));
543 g_signal_connect (fd.hist, "toggled",
544 G_CALLBACK (sensitive_if_active), fd.normal);
546 fd.pie = GTK_TOGGLE_BUTTON (get_widget_assert (xml, "pie"));
547 fd.pie_include_missing = GTK_TOGGLE_BUTTON (
548 get_widget_assert (xml, "pie-include-missing"));
549 g_signal_connect (fd.pie, "toggled",
550 G_CALLBACK (sensitive_if_active), fd.pie_include_missing);
552 gtk_window_set_transient_for (GTK_WINDOW (fd.charts_dialog),
556 g_signal_connect (dialog, "refresh", G_CALLBACK (refresh), &fd);
558 psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (dialog),
559 dialog_state_valid, &fd);
561 g_signal_connect_swapped (tables_button, "clicked",
562 G_CALLBACK (on_tables_clicked), &fd);
563 g_signal_connect_swapped (charts_button, "clicked",
564 G_CALLBACK (on_charts_clicked), &fd);
566 response = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
571 case GTK_RESPONSE_OK:
572 g_free (execute_syntax_string (generate_syntax (&fd)));
574 case PSPPIRE_RESPONSE_PASTE:
575 g_free (paste_syntax_to_window (generate_syntax (&fd)));
581 g_object_unref (xml);