1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2009, 2010, 2011, 2012, 2014 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-factor.h"
24 #include "psppire-var-view.h"
25 #include "dialog-common.h"
26 #include "psppire-selector.h"
27 #include "psppire-dict.h"
28 #include "psppire-dialog.h"
29 #include "builder-wrapper.h"
30 #include "psppire-scanf.h"
31 #include <libpspp/str.h>
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
37 static void psppire_dialog_action_factor_class_init (PsppireDialogActionFactorClass *class);
39 G_DEFINE_TYPE (PsppireDialogActionFactor, psppire_dialog_action_factor, PSPPIRE_TYPE_DIALOG_ACTION);
41 static const char *rot_method_syntax[] =
50 on_extract_toggle (GtkToggleButton *button, PsppireDialogActionFactor *f)
52 gboolean active = gtk_toggle_button_get_active (button);
54 gtk_widget_set_sensitive (GTK_WIDGET (f->n_factors), active);
55 gtk_widget_set_sensitive (GTK_WIDGET (f->mineigen), ! active);
59 generate_syntax (PsppireDialogAction *act)
61 PsppireDialogActionFactor *rd = PSPPIRE_DIALOG_ACTION_FACTOR (act);
65 ds_init_cstr (&str, "FACTOR ");
67 ds_put_cstr (&str, "\n\t/VARIABLES=");
69 psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->variables), 0, &str);
72 ds_put_cstr (&str, "\n\t/CRITERIA = ");
73 if ( rd->extraction.explicit_nfactors )
74 ds_put_c_format (&str, "FACTORS (%d)", rd->extraction.n_factors);
76 ds_put_c_format (&str, "MINEIGEN (%.*g)",
77 DBL_DIG + 1, rd->extraction.mineigen);
80 The CRITERIA = ITERATE subcommand is overloaded.
81 It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
83 ds_put_c_format (&str, " ITERATE (%d)", rd->extraction.n_iterations);
86 ds_put_cstr (&str, "\n\t/EXTRACTION =");
87 if ( rd->extraction.paf)
88 ds_put_cstr (&str, "PAF");
90 ds_put_cstr (&str, "PC");
93 ds_put_cstr (&str, "\n\t/METHOD = ");
94 if ( rd->extraction.covariance )
95 ds_put_cstr (&str, "COVARIANCE");
97 ds_put_cstr (&str, "CORRELATION");
99 if ( rd->extraction.scree )
101 ds_put_cstr (&str, "\n\t/PLOT = ");
102 ds_put_cstr (&str, "EIGEN");
105 ds_put_cstr (&str, "\n\t/PRINT = ");
106 ds_put_cstr (&str, "INITIAL ");
108 if ( rd->extraction.unrotated )
109 ds_put_cstr (&str, "EXTRACTION ");
111 if ( rd->rotation.rotated_solution )
112 ds_put_cstr (&str, "ROTATION");
115 /* The CRITERIA = ITERATE subcommand is overloaded.
116 It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
118 ds_put_c_format (&str, "\n\t/CRITERIA = ITERATE (%d)", rd->rotation.iterations );
120 ds_put_cstr (&str, "\n\t/ROTATION = ");
121 ds_put_cstr (&str, rot_method_syntax[rd->rotation.method]);
123 ds_put_cstr (&str, ".");
124 text = ds_steal_cstr (&str);
132 load_rotation_parameters (PsppireDialogActionFactor *fd, const struct rotation_parameters *p)
134 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->display_rotated_solution),
135 p->rotated_solution);
137 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->rotate_iterations),
143 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_none), TRUE);
146 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_varimax), TRUE);
149 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_quartimax), TRUE);
152 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_equimax), TRUE);
155 g_assert_not_reached ();
161 load_extraction_parameters (PsppireDialogActionFactor *fd, const struct extraction_parameters *p)
163 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->mineigen), p->mineigen);
164 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->n_factors), p->n_factors);
166 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->extract_iterations), p->n_iterations);
169 if (p->explicit_nfactors)
170 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->nfactors_toggle), TRUE);
172 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->mineigen_toggle), TRUE);
175 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->covariance_toggle), TRUE);
177 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->correlation_toggle), TRUE);
180 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->scree_button), p->scree);
181 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->unrotated_button), p->unrotated);
184 gtk_combo_box_set_active (GTK_COMBO_BOX (fd->extraction_combo), 1);
186 gtk_combo_box_set_active (GTK_COMBO_BOX (fd->extraction_combo), 0);
191 dialog_state_valid (PsppireDialogActionFactor *da)
193 GtkTreeModel *liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (da->variables));
195 if (gtk_tree_model_iter_n_children (liststore, NULL) < 2)
201 static const struct extraction_parameters default_extraction_parameters =
202 {1.0, 0, 25, FALSE, TRUE, FALSE, TRUE, FALSE};
204 static const struct rotation_parameters default_rotation_parameters =
205 {TRUE, 25, ROT_VARIMAX};
208 dialog_refresh (PsppireDialogAction *da)
210 PsppireDialogActionFactor *fd = PSPPIRE_DIALOG_ACTION_FACTOR (da);
211 GtkTreeModel *liststore =
212 gtk_tree_view_get_model (GTK_TREE_VIEW (fd->variables));
213 gtk_list_store_clear (GTK_LIST_STORE (liststore));
215 load_extraction_parameters (fd, &default_extraction_parameters);
216 load_rotation_parameters (fd, &default_rotation_parameters);
222 set_rotation_parameters (PsppireDialogActionFactor *act, struct rotation_parameters *p)
224 p->iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->rotate_iterations));
225 p->rotated_solution = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->display_rotated_solution));
228 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_none)))
229 p->method = ROT_NONE;
231 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_varimax)))
232 p->method = ROT_VARIMAX;
234 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_quartimax)))
235 p->method = ROT_QUARTIMAX;
237 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_equimax)))
238 p->method = ROT_EQUIMAX;
242 set_extraction_parameters (PsppireDialogActionFactor *act, struct extraction_parameters *p)
244 p->mineigen = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->mineigen));
245 p->n_factors = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->n_factors));
246 p->n_iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->extract_iterations));
248 p->explicit_nfactors = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->nfactors_toggle));
249 p->covariance = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->covariance_toggle));
251 p->scree = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->scree_button));
252 p->unrotated = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->unrotated_button));
254 p->paf = (gtk_combo_box_get_active (GTK_COMBO_BOX (act->extraction_combo)) == 1);
259 run_extractions_subdialog (PsppireDialogActionFactor *act)
261 struct extraction_parameters *ex = &act->extraction;
263 gint response = psppire_dialog_run (PSPPIRE_DIALOG (act->extraction_dialog));
265 if ( response == PSPPIRE_RESPONSE_CONTINUE )
267 /* Set the parameters from their respective widgets */
268 set_extraction_parameters (act, ex);
272 /* Cancelled. Reset the widgets to their old state */
273 load_extraction_parameters (act, ex);
278 run_rotations_subdialog (PsppireDialogActionFactor *act)
280 struct rotation_parameters *rot = &act->rotation;
282 gint response = psppire_dialog_run (PSPPIRE_DIALOG (act->rotation_dialog));
284 if ( response == PSPPIRE_RESPONSE_CONTINUE )
286 /* Set the parameters from their respective widgets */
287 set_rotation_parameters (act, rot);
291 /* Cancelled. Reset the widgets to their old state */
292 load_rotation_parameters (act, rot);
297 psppire_dialog_action_factor_activate (GtkAction *a)
299 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
300 PsppireDialogActionFactor *act = PSPPIRE_DIALOG_ACTION_FACTOR (a);
301 GtkWidget *extraction_button ;
302 GtkWidget *rotation_button ;
304 GHashTable *thing = psppire_dialog_action_get_pointer (pda);
305 GtkBuilder *xml = g_hash_table_lookup (thing, a);
308 xml = builder_new ("factor.ui");
309 g_hash_table_insert (thing, a, xml);
312 pda->dialog = get_widget_assert (xml, "factor-dialog");
313 pda->source = get_widget_assert (xml, "dict-view");
315 extraction_button = get_widget_assert (xml, "button-extractions");
316 rotation_button = get_widget_assert (xml, "button-rotations");
318 act->extraction_dialog = get_widget_assert (xml, "extractions-dialog");
319 act->rotation_dialog = get_widget_assert (xml, "rotations-dialog");
321 act->variables = get_widget_assert (xml, "psppire-var-view1");
324 GtkWidget *hbox = get_widget_assert (xml, "hbox6");
325 GtkWidget *eigenvalue_extraction ;
327 act->mineigen_toggle = get_widget_assert (xml, "mineigen-radiobutton");
329 eigenvalue_extraction = psppire_scanf_new (_("_Eigenvalues over %4.2f times the mean eigenvalue"), &act->mineigen);
331 g_object_set (eigenvalue_extraction,
332 "use-underline", TRUE,
333 "mnemonic-widget", act->mineigen_toggle,
336 act->nfactors_toggle = get_widget_assert (xml, "nfactors-radiobutton");
337 act->n_factors = get_widget_assert (xml, "spinbutton-nfactors");
338 act->extract_iterations = get_widget_assert (xml, "spinbutton-extract-iterations");
339 act->covariance_toggle = get_widget_assert (xml, "covariance-radiobutton");
340 act->correlation_toggle = get_widget_assert (xml, "correlations-radiobutton");
342 act->scree_button = get_widget_assert (xml, "scree-button");
343 act->unrotated_button = get_widget_assert (xml, "unrotated-button");
344 act->extraction_combo = get_widget_assert (xml, "combobox1");
346 gtk_container_add (GTK_CONTAINER (hbox), eigenvalue_extraction);
348 g_signal_connect (act->nfactors_toggle, "toggled", G_CALLBACK (on_extract_toggle), act);
350 gtk_widget_show_all (eigenvalue_extraction);
354 act->rotate_iterations = get_widget_assert (xml, "spinbutton-rot-iterations");
356 act->display_rotated_solution = get_widget_assert (xml, "checkbutton-rotated-solution");
358 act->rotation_none = get_widget_assert (xml, "radiobutton-none");
359 act->rotation_varimax = get_widget_assert (xml, "radiobutton-varimax");
360 act->rotation_quartimax = get_widget_assert (xml, "radiobutton-quartimax");
361 act->rotation_equimax = get_widget_assert (xml, "radiobutton-equimax");
364 g_signal_connect_swapped (extraction_button, "clicked",
365 G_CALLBACK (run_extractions_subdialog), act);
366 g_signal_connect_swapped (rotation_button, "clicked", G_CALLBACK (run_rotations_subdialog), act);
369 psppire_dialog_action_set_valid_predicate (pda, (void *) dialog_state_valid);
370 psppire_dialog_action_set_refresh (pda, dialog_refresh);
372 PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_factor_parent_class)->activate (pda);
376 psppire_dialog_action_factor_class_init (PsppireDialogActionFactorClass *class)
378 psppire_dialog_action_set_activation (class, psppire_dialog_action_factor_activate);
380 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
384 psppire_dialog_action_factor_init (PsppireDialogActionFactor *act)