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;
61 if ( ! rd->value_map )
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);
171 on_change_clicked (GObject *obj, gpointer data)
173 PsppireDialogActionRecode *rd = data;
174 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
176 struct variable *var = NULL;
179 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
182 GtkTreeSelection *selection =
183 gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->variable_treeview));
185 GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
187 const gchar *dest_var_name =
188 gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
190 const gchar *dest_var_label =
191 gtk_entry_get_text (GTK_ENTRY (rd->new_label_entry));
193 if ( NULL == rows || rows->next != NULL)
196 gtk_tree_model_get_iter (model, &iter, rows->data);
198 gtk_tree_model_get (model, &iter, 0, &var, -1);
200 g_hash_table_remove (rdd->varmap, var);
202 nlp = nlp_create (dest_var_name, dest_var_label);
204 g_hash_table_insert (rdd->varmap, var, nlp);
206 gtk_tree_model_row_changed (model, rows->data, &iter);
209 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
215 /* Callback which gets called when a new row is selected
216 in the variable treeview.
217 It sets the name and label entry widgets to reflect the
218 currently selected row.
221 on_selection_change (GtkTreeSelection *selection, gpointer data)
223 PsppireDialogActionRecode *rd = data;
224 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
226 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
228 GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
230 if ( rows && !rows->next)
232 /* Exactly one row is selected */
234 struct variable *var;
238 gtk_widget_set_sensitive (rd->change_button, TRUE);
239 gtk_widget_set_sensitive (rd->new_name_entry, TRUE);
240 gtk_widget_set_sensitive (rd->new_label_entry, TRUE);
242 ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
243 g_return_if_fail (ok);
245 gtk_tree_model_get (model, &iter,
249 nlp = g_hash_table_lookup (rdd->varmap, var);
253 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), nlp->name ? nlp->name : "");
254 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), nlp->label ? nlp->label : "");
258 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
259 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
264 gtk_widget_set_sensitive (rd->change_button, FALSE);
265 gtk_widget_set_sensitive (rd->new_name_entry, FALSE);
266 gtk_widget_set_sensitive (rd->new_label_entry, FALSE);
268 gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
269 gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
273 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
281 populate_treeview (PsppireDialogActionRecode *act)
283 GtkTreeSelection *sel;
284 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (act);
285 GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
286 GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"),
291 gtk_tree_view_column_set_cell_data_func (col, renderer,
295 gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col);
297 col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0);
299 g_object_set (col, "title", _("Old"), NULL);
301 g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL);
303 rdd->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
305 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview));
307 g_signal_connect (sel, "changed",
308 G_CALLBACK (on_selection_change), act);
310 g_signal_connect (act->change_button, "clicked",
311 G_CALLBACK (on_change_clicked), act);
316 psppire_dialog_action_recode_different_activate (PsppireDialogAction *a)
318 PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
319 PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
321 psppire_dialog_action_recode_pre_activate (act, populate_treeview);
323 gtk_window_set_title (GTK_WINDOW (pda->dialog),
324 _("Recode into Different Variables"));
326 gtk_window_set_title (GTK_WINDOW (act->old_and_new_dialog),
327 _("Recode into Different Variables: Old and New Values "));
329 gtk_widget_show (act->output_variable_box);
331 g_signal_connect_swapped (act->old_and_new_dialog, "show",
332 G_CALLBACK (on_old_new_show), act);
334 psppire_dialog_action_set_refresh (pda, refresh);
336 psppire_dialog_action_set_valid_predicate (pda,
341 append_into_clause (const PsppireDialogActionRecode *rd, struct string *dds)
343 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
345 /* If applicable set the INTO clause which determines into which variables the new values go */
347 ds_put_cstr (dds, "\n\tINTO ");
350 for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
352 ok = psppire_var_view_get_iter_next (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter))
354 struct nlp *nlp = NULL;
355 const struct variable *var = psppire_var_view_get_variable (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &iter);
357 nlp = g_hash_table_lookup (rdd->varmap, var);
359 ds_put_cstr (dds, nlp->name);
360 ds_put_cstr (dds, " ");
365 append_string_declarations (const PsppireDialogActionRecode *rd, struct string *dds)
367 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
369 /* Declare new string variables if applicable */
370 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button)))
374 struct variable *var = NULL;
375 struct nlp *nlp = NULL;
377 g_hash_table_iter_init (&iter, rdd->varmap);
378 while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
380 ds_put_cstr (dds, "\nSTRING ");
381 ds_put_cstr (dds, nlp->name);
382 ds_put_c_format (dds, " (A%d).",
384 gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry)));
390 append_new_value_labels (const PsppireDialogActionRecode *rd, struct string *dds)
392 PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
394 /* If applicable, set labels for the new variables. */
397 struct variable *var = NULL;
398 struct nlp *nlp = NULL;
400 g_hash_table_iter_init (&iter, rdd->varmap);
401 while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
407 syntax_gen_string (&sl, ss_cstr (nlp->label));
408 ds_put_c_format (dds, "\nVARIABLE LABELS %s %s.",
409 nlp->name, ds_cstr (&sl));
417 diff_generate_syntax (const PsppireDialogAction *act)
419 return psppire_dialog_action_recode_generate_syntax (act,
420 append_string_declarations,
422 append_new_value_labels);
426 target_is_string (const PsppireDialogActionRecode *rd)
428 return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button));
432 psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class)
434 psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_different_activate);
436 PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = diff_generate_syntax;
437 PSPPIRE_DIALOG_ACTION_RECODE_CLASS (class)->target_is_string = target_is_string;
442 psppire_dialog_action_recode_different_init (PsppireDialogActionRecodeDifferent *act)