1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2009, 2010, 2011, 2012 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"
22 #include "psppire-var-view.h"
23 #include "dialog-common.h"
24 #include "psppire-selector.h"
25 #include "psppire-dict.h"
26 #include "psppire-dialog.h"
27 #include "builder-wrapper.h"
28 #include "psppire-scanf.h"
29 #include <libpspp/str.h>
32 #define _(msgid) gettext (msgid)
33 #define N_(msgid) msgid
35 static void psppire_dialog_action_factor_class_init (PsppireDialogActionFactorClass *class);
37 G_DEFINE_TYPE (PsppireDialogActionFactor, psppire_dialog_action_factor, PSPPIRE_TYPE_DIALOG_ACTION);
39 static const char *rot_method_syntax[] =
48 on_extract_toggle (GtkToggleButton *button, PsppireDialogActionFactor *f)
50 gboolean active = gtk_toggle_button_get_active (button);
52 gtk_widget_set_sensitive (GTK_WIDGET (f->n_factors), active);
53 gtk_widget_set_sensitive (GTK_WIDGET (f->mineigen), ! active);
57 generate_syntax (PsppireDialogAction *act)
59 PsppireDialogActionFactor *rd = PSPPIRE_DIALOG_ACTION_FACTOR (act);
63 ds_init_cstr (&str, "FACTOR ");
65 ds_put_cstr (&str, "\n\t/VARIABLES=");
67 psppire_var_view_append_names_str (PSPPIRE_VAR_VIEW (rd->variables), 0, &str);
70 ds_put_cstr (&str, "\n\t/CRITERIA = ");
71 if ( rd->extraction.explicit_nfactors )
72 ds_put_c_format (&str, "FACTORS (%d)", rd->extraction.n_factors);
74 ds_put_c_format (&str, "MINEIGEN (%g)", rd->extraction.mineigen);
77 The CRITERIA = ITERATE subcommand is overloaded.
78 It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
80 ds_put_c_format (&str, " ITERATE (%d)", rd->extraction.n_iterations);
83 ds_put_cstr (&str, "\n\t/EXTRACTION =");
84 if ( rd->extraction.paf)
85 ds_put_cstr (&str, "PAF");
87 ds_put_cstr (&str, "PC");
90 ds_put_cstr (&str, "\n\t/METHOD = ");
91 if ( rd->extraction.covariance )
92 ds_put_cstr (&str, "COVARIANCE");
94 ds_put_cstr (&str, "CORRELATION");
96 if ( rd->extraction.scree )
98 ds_put_cstr (&str, "\n\t/PLOT = ");
99 ds_put_cstr (&str, "EIGEN");
102 ds_put_cstr (&str, "\n\t/PRINT = ");
103 ds_put_cstr (&str, "INITIAL ");
105 if ( rd->extraction.unrotated )
106 ds_put_cstr (&str, "EXTRACTION ");
108 if ( rd->rotation.rotated_solution )
109 ds_put_cstr (&str, "ROTATION");
112 /* The CRITERIA = ITERATE subcommand is overloaded.
113 It applies to the next /ROTATION and/or EXTRACTION command whatever comes first.
115 ds_put_c_format (&str, "\n\t/CRITERIA = ITERATE (%d)", rd->rotation.iterations );
117 ds_put_cstr (&str, "\n\t/ROTATION = ");
118 ds_put_cstr (&str, rot_method_syntax[rd->rotation.method]);
120 ds_put_cstr (&str, ".");
121 text = ds_steal_cstr (&str);
129 load_rotation_parameters (PsppireDialogActionFactor *fd, const struct rotation_parameters *p)
131 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->display_rotated_solution),
132 p->rotated_solution);
134 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->rotate_iterations),
140 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_none), TRUE);
143 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_varimax), TRUE);
146 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_quartimax), TRUE);
149 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->rotation_equimax), TRUE);
152 g_assert_not_reached ();
158 load_extraction_parameters (PsppireDialogActionFactor *fd, const struct extraction_parameters *p)
160 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->mineigen), p->mineigen);
161 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->n_factors), p->n_factors);
163 gtk_spin_button_set_value (GTK_SPIN_BUTTON (fd->extract_iterations), p->n_iterations);
166 if (p->explicit_nfactors)
167 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->nfactors_toggle), TRUE);
169 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->mineigen_toggle), TRUE);
172 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->covariance_toggle), TRUE);
174 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->correlation_toggle), TRUE);
177 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->scree_button), p->scree);
178 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fd->unrotated_button), p->unrotated);
181 gtk_combo_box_set_active (GTK_COMBO_BOX (fd->extraction_combo), 1);
183 gtk_combo_box_set_active (GTK_COMBO_BOX (fd->extraction_combo), 0);
188 dialog_state_valid (PsppireDialogActionFactor *da)
190 GtkTreeModel *liststore = gtk_tree_view_get_model (GTK_TREE_VIEW (da->variables));
192 if (gtk_tree_model_iter_n_children (liststore, NULL) < 2)
198 static const struct extraction_parameters default_extraction_parameters =
199 {1.0, 0, 25, FALSE, TRUE, FALSE, TRUE, FALSE};
201 static const struct rotation_parameters default_rotation_parameters =
202 {TRUE, 25, ROT_VARIMAX};
205 dialog_refresh (PsppireDialogAction *da)
207 PsppireDialogActionFactor *fd = PSPPIRE_DIALOG_ACTION_FACTOR (da);
208 GtkTreeModel *liststore =
209 gtk_tree_view_get_model (GTK_TREE_VIEW (fd->variables));
210 gtk_list_store_clear (GTK_LIST_STORE (liststore));
212 load_extraction_parameters (fd, &default_extraction_parameters);
213 load_rotation_parameters (fd, &default_rotation_parameters);
219 set_rotation_parameters (PsppireDialogActionFactor *act, struct rotation_parameters *p)
221 p->iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->rotate_iterations));
222 p->rotated_solution = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->display_rotated_solution));
225 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_none)))
226 p->method = ROT_NONE;
228 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_varimax)))
229 p->method = ROT_VARIMAX;
231 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_quartimax)))
232 p->method = ROT_QUARTIMAX;
234 if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->rotation_equimax)))
235 p->method = ROT_EQUIMAX;
239 set_extraction_parameters (PsppireDialogActionFactor *act, struct extraction_parameters *p)
241 p->mineigen = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->mineigen));
242 p->n_factors = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->n_factors));
243 p->n_iterations = gtk_spin_button_get_value (GTK_SPIN_BUTTON (act->extract_iterations));
245 p->explicit_nfactors = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->nfactors_toggle));
246 p->covariance = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->covariance_toggle));
248 p->scree = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->scree_button));
249 p->unrotated = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (act->unrotated_button));
251 p->paf = (gtk_combo_box_get_active (GTK_COMBO_BOX (act->extraction_combo)) == 1);
256 run_extractions_subdialog (PsppireDialogActionFactor *act)
258 struct extraction_parameters *ex = &act->extraction;
260 gint response = psppire_dialog_run (PSPPIRE_DIALOG (act->extraction_dialog));
262 if ( response == PSPPIRE_RESPONSE_CONTINUE )
264 /* Set the parameters from their respective widgets */
265 set_extraction_parameters (act, ex);
269 /* Cancelled. Reset the widgets to their old state */
270 load_extraction_parameters (act, ex);
275 run_rotations_subdialog (PsppireDialogActionFactor *act)
277 struct rotation_parameters *rot = &act->rotation;
279 gint response = psppire_dialog_run (PSPPIRE_DIALOG (act->rotation_dialog));
281 if ( response == PSPPIRE_RESPONSE_CONTINUE )
283 /* Set the parameters from their respective widgets */
284 set_rotation_parameters (act, rot);
288 /* Cancelled. Reset the widgets to their old state */
289 load_rotation_parameters (act, rot);
294 psppire_dialog_action_factor_activate (GtkAction *a)
296 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
297 PsppireDialogActionFactor *act = PSPPIRE_DIALOG_ACTION_FACTOR (a);
298 GtkWidget *extraction_button ;
299 GtkWidget *rotation_button ;
301 GtkBuilder *xml = builder_new ("factor.ui");
303 pda->dialog = get_widget_assert (xml, "factor-dialog");
304 pda->source = get_widget_assert (xml, "dict-view");
306 extraction_button = get_widget_assert (xml, "button-extractions");
307 rotation_button = get_widget_assert (xml, "button-rotations");
309 act->extraction_dialog = get_widget_assert (xml, "extractions-dialog");
310 act->rotation_dialog = get_widget_assert (xml, "rotations-dialog");
312 act->variables = get_widget_assert (xml, "psppire-var-view1");
315 GtkWidget *hbox = get_widget_assert (xml, "hbox6");
316 GtkWidget *eigenvalue_extraction ;
318 act->mineigen_toggle = get_widget_assert (xml, "mineigen-radiobutton");
320 eigenvalue_extraction = psppire_scanf_new (_("_Eigenvalues over %4.2f times the mean eigenvalue"), &act->mineigen);
322 g_object_set (eigenvalue_extraction,
323 "use-underline", TRUE,
324 "mnemonic-widget", act->mineigen_toggle,
327 act->nfactors_toggle = get_widget_assert (xml, "nfactors-radiobutton");
328 act->n_factors = get_widget_assert (xml, "spinbutton-nfactors");
329 act->extract_iterations = get_widget_assert (xml, "spinbutton-extract-iterations");
330 act->covariance_toggle = get_widget_assert (xml, "covariance-radiobutton");
331 act->correlation_toggle = get_widget_assert (xml, "correlations-radiobutton");
333 act->scree_button = get_widget_assert (xml, "scree-button");
334 act->unrotated_button = get_widget_assert (xml, "unrotated-button");
335 act->extraction_combo = get_widget_assert (xml, "combobox1");
337 gtk_container_add (GTK_CONTAINER (hbox), eigenvalue_extraction);
339 g_signal_connect (act->nfactors_toggle, "toggled", G_CALLBACK (on_extract_toggle), act);
341 gtk_widget_show_all (eigenvalue_extraction);
345 act->rotate_iterations = get_widget_assert (xml, "spinbutton-rot-iterations");
347 act->display_rotated_solution = get_widget_assert (xml, "checkbutton-rotated-solution");
349 act->rotation_none = get_widget_assert (xml, "radiobutton-none");
350 act->rotation_varimax = get_widget_assert (xml, "radiobutton-varimax");
351 act->rotation_quartimax = get_widget_assert (xml, "radiobutton-quartimax");
352 act->rotation_equimax = get_widget_assert (xml, "radiobutton-equimax");
355 g_signal_connect_swapped (extraction_button, "clicked",
356 G_CALLBACK (run_extractions_subdialog), act);
357 g_signal_connect_swapped (rotation_button, "clicked", G_CALLBACK (run_rotations_subdialog), act);
360 psppire_dialog_action_set_valid_predicate (pda, (void *) dialog_state_valid);
361 psppire_dialog_action_set_refresh (pda, dialog_refresh);
363 PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_factor_parent_class)->activate (pda);
365 g_object_unref (xml);
369 psppire_dialog_action_factor_class_init (PsppireDialogActionFactorClass *class)
371 GTK_ACTION_CLASS (class)->activate = psppire_dialog_action_factor_activate;
373 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
377 psppire_dialog_action_factor_init (PsppireDialogActionFactor *act)