1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2012, 2015 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/>. */
20 #include "psppire-dialog-action-frequencies.h"
21 #include "psppire-value-entry.h"
23 #include "dialog-common.h"
25 #include <ui/syntax-gen.h>
26 #include "psppire-var-view.h"
28 #include "psppire-dialog.h"
29 #include "builder-wrapper.h"
30 #include "psppire-checkbox-treeview.h"
31 #include "psppire-dict.h"
32 #include "libpspp/str.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")) \
59 #define FS(NAME, LABEL) FS_##NAME,
67 #define FS(NAME, LABEL) B_FS_##NAME = 1u << FS_##NAME,
70 B_FS_ALL = (1u << N_FREQUENCY_STATS) - 1,
71 B_FS_DEFAULT = B_FS_MEAN | B_FS_STDDEV | B_FS_MINIMUM | B_FS_MAXIMUM
75 static const struct checkbox_entry_item stats[] = {
76 #define FS(NAME, LABEL) {#NAME, LABEL},
83 on_tables_clicked (PsppireDialogActionFrequencies * fd)
87 switch (fd->tables_opts_order)
90 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->avalue), TRUE);
93 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->dvalue), TRUE);
96 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->afreq), TRUE);
99 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->dfreq), TRUE);
103 switch (fd->tables_opts_table)
106 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->always), TRUE);
109 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->never), TRUE);
112 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->limit), TRUE);
116 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->limit_spinbutton),
117 fd->tables_opts_limit);
119 g_signal_emit_by_name (fd->limit, "toggled");
121 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->tables_dialog));
123 if (ret == PSPPIRE_RESPONSE_CONTINUE)
125 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->avalue)))
126 fd->tables_opts_order = FRQ_AVALUE;
127 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->dvalue)))
128 fd->tables_opts_order = FRQ_DVALUE;
129 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->afreq)))
130 fd->tables_opts_order = FRQ_ACOUNT;
131 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->dfreq)))
132 fd->tables_opts_order = FRQ_DCOUNT;
134 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->always)))
135 fd->tables_opts_table = FRQ_TABLE;
136 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->never)))
137 fd->tables_opts_table = FRQ_NOTABLE;
139 fd->tables_opts_table = FRQ_LIMIT;
142 fd->tables_opts_limit =
143 gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->limit_spinbutton));
149 on_charts_clicked (PsppireDialogActionFrequencies *fd)
153 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->min), fd->charts_opts_use_min);
154 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->min_spin), fd->charts_opts_min);
155 g_signal_emit_by_name (fd->min, "toggled");
157 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->max), fd->charts_opts_use_max);
158 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->max_spin), fd->charts_opts_max);
159 g_signal_emit_by_name (fd->max, "toggled");
161 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->hist), fd->charts_opts_draw_hist);
162 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->normal), fd->charts_opts_draw_normal);
163 g_signal_emit_by_name (fd->hist, "toggled");
165 switch (fd->charts_opts_scale)
168 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->freqs), TRUE);
171 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->percents), TRUE);
175 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->pie), fd->charts_opts_draw_pie);
176 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->pie_include_missing),
177 fd->charts_opts_pie_include_missing);
179 g_signal_emit_by_name (fd->pie, "toggled");
182 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->bar), fd->charts_opts_draw_bar);
183 g_signal_emit_by_name (fd->bar, "toggled");
185 ret = psppire_dialog_run (PSPPIRE_DIALOG (fd->charts_dialog));
187 if (ret == PSPPIRE_RESPONSE_CONTINUE)
189 fd->charts_opts_use_min = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->min));
190 fd->charts_opts_min = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->min_spin));
192 fd->charts_opts_use_max = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->max));
193 fd->charts_opts_max = gtk_spin_button_get_value (GTK_SPIN_BUTTON (fd->max_spin));
195 fd->charts_opts_draw_hist = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->hist));
196 fd->charts_opts_draw_normal = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->normal));
197 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->freqs)))
198 fd->charts_opts_scale = FRQ_FREQ;
199 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->percents)))
200 fd->charts_opts_scale = FRQ_PERCENT;
202 fd->charts_opts_draw_pie = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->pie));
203 fd->charts_opts_pie_include_missing
204 = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->pie_include_missing));
207 fd->charts_opts_draw_bar = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->bar));
213 psppire_dialog_action_frequencies_class_init
214 (PsppireDialogActionFrequenciesClass * class);
216 G_DEFINE_TYPE (PsppireDialogActionFrequencies,
217 psppire_dialog_action_frequencies, PSPPIRE_TYPE_DIALOG_ACTION);
220 dialog_state_valid (gpointer data)
222 PsppireDialogActionFrequencies *fd =
223 PSPPIRE_DIALOG_ACTION_FREQUENCIES (data);
226 gtk_tree_view_get_model (GTK_TREE_VIEW (fd->stat_vars));
230 return gtk_tree_model_get_iter_first (vars, ¬used);
234 refresh (PsppireDialogAction * fdx)
236 PsppireDialogActionFrequencies *fd =
237 PSPPIRE_DIALOG_ACTION_FREQUENCIES (fdx);
243 GtkTreeModel *liststore =
244 gtk_tree_view_get_model (GTK_TREE_VIEW (fd->stat_vars));
245 gtk_list_store_clear (GTK_LIST_STORE (liststore));
247 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
248 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
249 gtk_list_store_set (GTK_LIST_STORE (fd->stats), &iter,
250 CHECKBOX_COLUMN_SELECTED,
251 (B_FS_DEFAULT & (1u << i)) ? true : false, -1);
255 psppire_dialog_action_frequencies_activate (PsppireDialogAction *a, GVariant *param)
257 PsppireDialogActionFrequencies *act = PSPPIRE_DIALOG_ACTION_FREQUENCIES (a);
258 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
260 GtkBuilder *xml = builder_new ("frequencies.ui");
262 GtkWidget *stats_treeview = get_widget_assert (xml, "stats-treeview");
264 psppire_checkbox_treeview_populate (PSPPIRE_CHECKBOX_TREEVIEW (stats_treeview),
265 B_FS_DEFAULT, N_FREQUENCY_STATS, stats);
267 act->stats = gtk_tree_view_get_model (GTK_TREE_VIEW (stats_treeview));
269 GtkWidget *tables_button = get_widget_assert (xml, "tables-button");
270 GtkWidget *charts_button = get_widget_assert (xml, "charts-button");
272 pda->dialog = get_widget_assert (xml, "frequencies-dialog");
273 pda->source = get_widget_assert (xml, "dict-treeview");
275 act->stat_vars = get_widget_assert (xml, "var-treeview");
277 act->include_missing = get_widget_assert (xml, "include_missing");
278 act->tables_dialog = get_widget_assert (xml, "tables-dialog");
279 act->charts_dialog = get_widget_assert (xml, "charts-dialog");
280 act->always = get_widget_assert (xml, "always");
281 act->never = get_widget_assert (xml, "never");
282 act->limit = get_widget_assert (xml, "limit");
283 act->limit_spinbutton = get_widget_assert (xml, "limit-spin");
285 g_signal_connect (act->limit, "toggled",
286 G_CALLBACK (set_sensitivity_from_toggle),
287 act->limit_spinbutton);
289 act->avalue = get_widget_assert (xml, "avalue");
290 act->dvalue = get_widget_assert (xml, "dvalue");
291 act->afreq = get_widget_assert (xml, "afreq");
292 act->dfreq = get_widget_assert (xml, "dfreq");
294 act->charts_opts_use_min = false;
295 act->charts_opts_min = 0;
296 act->charts_opts_use_max = false;
297 act->charts_opts_max = 100;
298 act->charts_opts_draw_hist = false;
299 act->charts_opts_draw_normal = false;
300 act->charts_opts_scale = FRQ_FREQ;
301 act->charts_opts_draw_pie = false;
302 act->charts_opts_draw_bar = false;
303 act->charts_opts_pie_include_missing = false;
305 act->freqs = get_widget_assert (xml, "freqs");
306 act->percents = get_widget_assert (xml, "percents");
308 act->min = get_widget_assert (xml, "min");
309 act->min_spin = get_widget_assert (xml, "min-spin");
310 g_signal_connect (act->min, "toggled",
311 G_CALLBACK (set_sensitivity_from_toggle), act->min_spin);
312 act->max = get_widget_assert (xml, "max");
313 act->max_spin = get_widget_assert (xml, "max-spin");
314 g_signal_connect (act->max, "toggled",
315 G_CALLBACK (set_sensitivity_from_toggle), act->max_spin);
317 act->hist = get_widget_assert (xml, "hist");
318 act->normal = get_widget_assert (xml, "normal");
319 g_signal_connect (act->hist, "toggled",
320 G_CALLBACK (set_sensitivity_from_toggle), act->normal);
322 act->pie = (get_widget_assert (xml, "pie"));
323 act->pie_include_missing = get_widget_assert (xml, "pie-include-missing");
325 act->bar = (get_widget_assert (xml, "bar"));
327 act->tables_opts_order = FRQ_AVALUE;
328 act->tables_opts_table = FRQ_TABLE;
329 act->tables_opts_limit = 50;
331 g_signal_connect_swapped (tables_button, "clicked",
332 G_CALLBACK (on_tables_clicked), act);
334 g_signal_connect_swapped (charts_button, "clicked",
335 G_CALLBACK (on_charts_clicked), act);
337 psppire_dialog_action_set_refresh (pda, refresh);
339 psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
345 generate_syntax (const PsppireDialogAction * a)
347 PsppireDialogActionFrequencies *fd = PSPPIRE_DIALOG_ACTION_FREQUENCIES (a);
355 ds_init_cstr (&str, "FREQUENCIES");
357 ds_put_cstr (&str, "\n\t/VARIABLES=");
358 psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (fd->stat_vars), 0, &str);
360 ds_put_cstr (&str, "\n\t/FORMAT=");
362 switch (fd->tables_opts_order)
365 ds_put_cstr (&str, "AVALUE");
368 ds_put_cstr (&str, "DVALUE");
371 ds_put_cstr (&str, "AFREQ");
374 ds_put_cstr (&str, "DFREQ");
377 g_assert_not_reached ();
380 ds_put_cstr (&str, " ");
382 switch (fd->tables_opts_table)
385 ds_put_cstr (&str, "TABLE");
388 ds_put_cstr (&str, "NOTABLE");
391 ds_put_c_format (&str, "LIMIT (%d)", fd->tables_opts_limit);
396 for (i = 0, ok = gtk_tree_model_get_iter_first (fd->stats, &iter); ok;
397 i++, ok = gtk_tree_model_iter_next (fd->stats, &iter))
400 gtk_tree_model_get (fd->stats, &iter,
401 CHECKBOX_COLUMN_SELECTED, &toggled, -1);
406 if (selected != B_FS_DEFAULT)
408 ds_put_cstr (&str, "\n\t/STATISTICS=");
409 if (selected == B_FS_ALL)
410 ds_put_cstr (&str, "ALL");
411 else if (selected == 0)
412 ds_put_cstr (&str, "NONE");
416 if ((selected & B_FS_DEFAULT) == B_FS_DEFAULT)
418 ds_put_cstr (&str, "DEFAULT");
419 selected &= ~B_FS_DEFAULT;
422 for (i = 0; i < N_FREQUENCY_STATS; i++)
423 if (selected & (1u << i))
426 ds_put_cstr (&str, " ");
427 ds_put_cstr (&str, stats[i].name);
432 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (fd->include_missing)))
433 ds_put_cstr (&str, "\n\t/MISSING=INCLUDE");
436 if (fd->charts_opts_draw_hist)
438 ds_put_cstr (&str, "\n\t/HISTOGRAM=");
440 fd->charts_opts_draw_normal ? "NORMAL" : "NONORMAL");
442 if (fd->charts_opts_scale == FRQ_PERCENT)
443 ds_put_cstr (&str, " PERCENT");
445 if (fd->charts_opts_use_min)
446 ds_put_c_format (&str, " MIN(%.15g)", fd->charts_opts_min);
447 if (fd->charts_opts_use_max)
448 ds_put_c_format (&str, " MAX(%.15g)", fd->charts_opts_max);
451 if (fd->charts_opts_draw_pie)
453 ds_put_cstr (&str, "\n\t/PIECHART=");
455 if (fd->charts_opts_pie_include_missing)
456 ds_put_cstr (&str, " MISSING");
458 ds_put_cstr (&str, " NOMISSING");
460 if (fd->charts_opts_use_min)
461 ds_put_c_format (&str, " MIN(%.15g)", fd->charts_opts_min);
462 if (fd->charts_opts_use_max)
463 ds_put_c_format (&str, " MAX(%.15g)", fd->charts_opts_max);
467 if (fd->charts_opts_draw_bar)
469 ds_put_cstr (&str, "\n\t/BARCHART=");
471 if (fd->charts_opts_scale == FRQ_PERCENT)
472 ds_put_cstr (&str, " PERCENT");
474 if (fd->charts_opts_use_min)
475 ds_put_c_format (&str, " MIN(%.15g)", fd->charts_opts_min);
476 if (fd->charts_opts_use_max)
477 ds_put_c_format (&str, " MAX(%.15g)", fd->charts_opts_max);
481 ds_put_cstr (&str, ".\n");
483 text = ds_steal_cstr (&str);
491 psppire_dialog_action_frequencies_class_init (PsppireDialogActionFrequenciesClass *class)
493 PSPPIRE_DIALOG_ACTION_CLASS (class)->initial_activate = psppire_dialog_action_frequencies_activate;
494 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
499 psppire_dialog_action_frequencies_init (PsppireDialogActionFrequencies *act)