1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014, 2016 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 "psppire-var-view.h"
21 #include "psppire-dialog-action-recode-different.h"
22 #include "builder-wrapper.h"
23 #include <ui/gui/dialog-common.h>
25 #include "psppire-acr.h"
27 #include "psppire-selector.h"
28 #include "psppire-val-chooser.h"
31 #include <ui/syntax-gen.h>
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
40 difx_variable_treeview_is_populated (PsppireDialogActionRecode *rd)
42 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
43 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
45 if (g_hash_table_size (rdd->varmap) != gtk_tree_model_iter_n_children (model, NULL))
52 /* Dialog is valid iff at least one variable has been selected,
53 AND the list of mappings is not empty.
56 dialog_state_valid (gpointer data)
58 PsppireDialogActionRecode *rd = data;
64 if (! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
69 return difx_variable_treeview_is_populated (rd);
76 psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class);
78 G_DEFINE_TYPE (PsppireDialogActionRecodeDifferent, psppire_dialog_action_recode_different, PSPPIRE_TYPE_DIALOG_ACTION_RECODE);
81 refresh (PsppireDialogAction *act)
83 PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (act);
84 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
86 psppire_dialog_action_recode_refresh (act);
89 g_hash_table_remove_all (rdd->varmap);
94 on_old_new_show (PsppireDialogActionRecode *rd)
96 gtk_toggle_button_set_active
97 (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE);
99 g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled");
101 gtk_widget_show (rd->toggle[BUTTON_NEW_COPY]);
102 gtk_widget_show (rd->new_copy_label);
103 gtk_widget_show (rd->strings_box);
108 /* Name-Label pair */
117 nlp_create (const char *name, const char *label)
119 struct nlp *nlp = xmalloc (sizeof *nlp);
121 nlp->name = g_strdup (name);
125 if (0 != strcmp ("", label))
126 nlp->label = g_strdup (label);
132 nlp_destroy (gpointer data)
134 struct nlp *nlp = data ;
146 render_new_var_name (GtkTreeViewColumn *tree_column,
147 GtkCellRenderer *cell,
148 GtkTreeModel *tree_model,
152 struct nlp *nlp = NULL;
153 PsppireDialogActionRecode *rd = data;
154 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
156 struct variable *var = NULL;
158 gtk_tree_model_get (tree_model, iter,
162 nlp = g_hash_table_lookup (rdd->varmap, var);
165 g_object_set (cell, "text", nlp->name, NULL);
167 g_object_set (cell, "text", "", NULL);
173 on_change_clicked (GObject *obj, gpointer data)
175 PsppireDialogActionRecode *rd = data;
176 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
178 struct variable *var = NULL;
181 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
184 GtkTreeSelection *selection =
185 gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->variable_treeview));
187 GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
189 const gchar *dest_var_name =
190 gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
192 const gchar *dest_var_label =
193 gtk_entry_get_text (GTK_ENTRY (rd->new_label_entry));
195 if (NULL == rows || rows->next != NULL)
198 gtk_tree_model_get_iter (model, &iter, rows->data);
200 gtk_tree_model_get (model, &iter, 0, &var, -1);
202 g_hash_table_remove (rdd->varmap, var);
204 nlp = nlp_create (dest_var_name, dest_var_label);
206 g_hash_table_insert (rdd->varmap, var, nlp);
208 gtk_tree_model_row_changed (model, rows->data, &iter);
211 g_list_foreach (rows, GFUNC_COMPAT_CAST (gtk_tree_path_free), NULL);
217 /* Callback which gets called when a new row is selected
218 in the variable treeview.
219 It sets the name and label entry widgets to reflect the
220 currently selected row.
223 on_selection_change (GtkTreeSelection *selection, gpointer data)
225 PsppireDialogActionRecode *rd = data;
226 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
228 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
230 GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
232 if (rows && !rows->next)
234 /* Exactly one row is selected */
236 struct variable *var;
240 gtk_widget_set_sensitive (rd->change_button, TRUE);
241 gtk_widget_set_sensitive (rd->new_name_entry, TRUE);
242 gtk_widget_set_sensitive (rd->new_label_entry, TRUE);
244 ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
245 g_return_if_fail (ok);
247 gtk_tree_model_get (model, &iter,
251 nlp = g_hash_table_lookup (rdd->varmap, var);
255 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), nlp->name ? nlp->name : "");
256 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), nlp->label ? nlp->label : "");
260 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
261 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
266 gtk_widget_set_sensitive (rd->change_button, FALSE);
267 gtk_widget_set_sensitive (rd->new_name_entry, FALSE);
268 gtk_widget_set_sensitive (rd->new_label_entry, FALSE);
270 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
271 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
275 g_list_foreach (rows, GFUNC_COMPAT_CAST (gtk_tree_path_free), NULL);
283 populate_treeview (PsppireDialogActionRecode *act)
285 GtkTreeSelection *sel;
286 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (act);
287 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
288 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"),
293 gtk_tree_view_column_set_cell_data_func (col, renderer,
297 gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col);
299 col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0);
301 g_object_set (col, "title", _("Old"), NULL);
303 g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL);
305 rdd->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
307 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview));
309 g_signal_connect (sel, "changed",
310 G_CALLBACK (on_selection_change), act);
312 g_signal_connect (act->change_button, "clicked",
313 G_CALLBACK (on_change_clicked), act);
318 psppire_dialog_action_recode_different_activate (PsppireDialogAction *a, GVariant *param)
320 PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
321 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
323 GtkBuilder *xml = psppire_dialog_action_recode_pre_activate (act,
326 gtk_window_set_title (GTK_WINDOW (pda->dialog),
327 _("Recode into Different Variables"));
329 gtk_window_set_title (GTK_WINDOW (act->old_and_new_dialog),
330 _("Recode into Different Variables: Old and New Values "));
332 gtk_widget_show (act->output_variable_box);
334 g_signal_connect_swapped (act->old_and_new_dialog, "show",
335 G_CALLBACK (on_old_new_show), act);
337 psppire_dialog_action_set_refresh (pda, refresh);
339 psppire_dialog_action_set_valid_predicate (pda,
345 append_into_clause (const PsppireDialogActionRecode *rd, struct string *dds)
347 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
349 /* If applicable set the INTO clause which determines into which variables the new values go */
351 ds_put_cstr (dds, "\n\tINTO ");
354 for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
356 ok = psppire_var_view_get_iter_next (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter))
358 struct nlp *nlp = NULL;
359 const struct variable *var = psppire_var_view_get_variable (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &iter);
361 nlp = g_hash_table_lookup (rdd->varmap, var);
363 ds_put_cstr (dds, nlp->name);
364 ds_put_cstr (dds, " ");
369 append_string_declarations (const PsppireDialogActionRecode *rd, struct string *dds)
371 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
373 /* Declare new string variables if applicable */
374 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button)))
378 struct variable *var = NULL;
379 struct nlp *nlp = NULL;
381 g_hash_table_iter_init (&iter, rdd->varmap);
382 while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
384 ds_put_cstr (dds, "\nSTRING ");
385 ds_put_cstr (dds, nlp->name);
386 ds_put_c_format (dds, " (A%d).",
388 gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry)));
394 append_new_value_labels (const PsppireDialogActionRecode *rd, struct string *dds)
396 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
398 /* If applicable, set labels for the new variables. */
401 struct variable *var = NULL;
402 struct nlp *nlp = NULL;
404 g_hash_table_iter_init (&iter, rdd->varmap);
405 while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
411 syntax_gen_string (&sl, ss_cstr (nlp->label));
412 ds_put_c_format (dds, "\nVARIABLE LABELS %s %s.",
413 nlp->name, ds_cstr (&sl));
421 diff_generate_syntax (const PsppireDialogAction *act)
423 return psppire_dialog_action_recode_generate_syntax (act,
424 append_string_declarations,
426 append_new_value_labels);
430 target_is_string (const PsppireDialogActionRecode *rd)
432 return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button));
436 psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class)
438 PSPPIRE_DIALOG_ACTION_CLASS (class)->initial_activate = psppire_dialog_action_recode_different_activate;
440 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = diff_generate_syntax;
441 PSPPIRE_DIALOG_ACTION_RECODE_CLASS (class)->target_is_string = target_is_string;
446 psppire_dialog_action_recode_different_init (PsppireDialogActionRecodeDifferent *act)