Remove deprecated objects GtkAction and GtkUIManager
[pspp] / src / ui / gui / psppire-dialog-action-recode-different.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2009, 2010, 2011, 2012, 2014, 2016  Free Software Foundation
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "psppire-var-view.h"
20
21 #include "psppire-dialog-action-recode-different.h"
22 #include "builder-wrapper.h"
23 #include <ui/gui/dialog-common.h>
24
25 #include "psppire-acr.h"
26
27 #include "psppire-selector.h"
28 #include "psppire-val-chooser.h"
29
30 #include "helper.h"
31 #include <ui/syntax-gen.h>
32
33 #include "gettext.h"
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
36
37
38
39 static gboolean
40 difx_variable_treeview_is_populated (PsppireDialogActionRecode *rd)
41 {
42   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
43   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
44   
45   if (g_hash_table_size (rdd->varmap) != gtk_tree_model_iter_n_children (model, NULL) )
46     return FALSE;
47
48   return TRUE;
49 }
50
51
52 /* Dialog is valid iff at least one variable has been selected,
53    AND the list of mappings is not empty.
54 */
55 static gboolean
56 dialog_state_valid (gpointer data)
57 {
58   PsppireDialogActionRecode *rd = data;
59   GtkTreeIter not_used;
60       
61   if ( ! rd->value_map )
62     return FALSE;
63
64   if ( ! gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rd->value_map),
65                                         &not_used) )
66     return FALSE;
67
68
69   return difx_variable_treeview_is_populated (rd);
70 }
71
72
73 \f
74
75 static void
76 psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class);
77
78 G_DEFINE_TYPE (PsppireDialogActionRecodeDifferent, psppire_dialog_action_recode_different, PSPPIRE_TYPE_DIALOG_ACTION_RECODE);
79
80 static void
81 refresh (PsppireDialogAction *act)
82 {
83   PsppireDialogActionRecode *rd = PSPPIRE_DIALOG_ACTION_RECODE (act);
84   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
85
86   psppire_dialog_action_recode_refresh (act);
87
88   if (rdd->varmap)
89     g_hash_table_remove_all (rdd->varmap);
90 }
91
92
93 static void
94 on_old_new_show (PsppireDialogActionRecode *rd)
95 {
96   gtk_toggle_button_set_active
97     (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE);
98
99   g_signal_emit_by_name (rd->toggle[BUTTON_NEW_VALUE], "toggled");
100
101   gtk_widget_show (rd->toggle[BUTTON_NEW_COPY]);
102   gtk_widget_show (rd->new_copy_label);
103   gtk_widget_show (rd->strings_box);
104 }
105
106 \f
107
108 /* Name-Label pair */
109 struct nlp
110 {
111   char *name;
112   char *label;
113 };
114
115
116 static struct nlp *
117 nlp_create (const char *name, const char *label)
118 {
119   struct nlp *nlp = xmalloc (sizeof *nlp);
120
121   nlp->name = g_strdup (name);
122
123   nlp->label = NULL;
124
125   if ( 0 != strcmp ("", label))
126     nlp->label = g_strdup (label);
127
128   return nlp;
129 }
130
131 static void
132 nlp_destroy (gpointer data)
133 {
134   struct nlp *nlp = data ;
135   if ( ! nlp )
136     return;
137
138   g_free (nlp->name);
139   g_free (nlp->label);
140   g_free (nlp);
141 }
142
143 \f
144
145 static void
146 render_new_var_name (GtkTreeViewColumn *tree_column,
147                      GtkCellRenderer *cell,
148                      GtkTreeModel *tree_model,
149                      GtkTreeIter *iter,
150                      gpointer data)
151 {
152   struct nlp *nlp = NULL;
153   PsppireDialogActionRecode *rd = data;
154   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
155
156   struct variable *var = NULL;
157
158   gtk_tree_model_get (tree_model, iter, 
159                       0, &var,
160                       -1);
161
162   nlp = g_hash_table_lookup (rdd->varmap, var);
163
164   if ( nlp )
165     g_object_set (cell, "text", nlp->name, NULL);
166   else
167     g_object_set (cell, "text", "", NULL);
168 }
169
170 static void
171 on_change_clicked (GObject *obj, gpointer data)
172 {
173   PsppireDialogActionRecode *rd = data;
174   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
175
176   struct variable *var = NULL;
177   struct nlp *nlp;
178
179   GtkTreeModel *model =  gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
180
181   GtkTreeIter iter;
182   GtkTreeSelection *selection =
183     gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->variable_treeview));
184
185   GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
186
187   const gchar *dest_var_name =
188     gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
189
190   const gchar *dest_var_label =
191     gtk_entry_get_text (GTK_ENTRY (rd->new_label_entry));
192
193   if ( NULL == rows || rows->next != NULL)
194     goto finish;
195
196   gtk_tree_model_get_iter (model, &iter, rows->data);
197
198   gtk_tree_model_get (model, &iter, 0, &var, -1);
199
200   g_hash_table_remove (rdd->varmap, var);
201
202   nlp = nlp_create (dest_var_name, dest_var_label);
203
204   g_hash_table_insert (rdd->varmap, var, nlp);
205
206   gtk_tree_model_row_changed (model, rows->data, &iter);
207
208  finish:
209   g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
210   g_list_free (rows);
211 }
212
213
214
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.
219 */
220 static void
221 on_selection_change (GtkTreeSelection *selection, gpointer data)
222 {
223   PsppireDialogActionRecode *rd = data;
224   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
225
226   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->variable_treeview));
227
228   GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
229
230   if ( rows && !rows->next)
231     {
232       /* Exactly one row is selected */
233       struct nlp *nlp;
234       struct variable *var;
235       gboolean ok;
236       GtkTreeIter iter;
237
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);
241
242       ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
243       g_return_if_fail (ok);
244
245       gtk_tree_model_get (model, &iter,
246                           0, &var, 
247                           -1);
248
249       nlp = g_hash_table_lookup (rdd->varmap, var);
250
251       if (nlp)
252         {
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 : "");
255         }
256       else
257         {
258           gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
259           gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
260         }
261     }
262   else
263     {
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);
267
268       gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
269       gtk_entry_set_text (GTK_ENTRY (rd->new_label_entry), "");
270     }
271
272
273   g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
274   g_list_free (rows);
275 }
276
277
278
279
280 static void
281 populate_treeview (PsppireDialogActionRecode *act)
282 {
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"),
287                                                                      renderer,
288                                                                      "text", NULL,
289                                                                      NULL);
290
291   gtk_tree_view_column_set_cell_data_func (col, renderer,
292                                            render_new_var_name,
293                                            act, NULL);
294
295   gtk_tree_view_append_column (GTK_TREE_VIEW (act->variable_treeview), col);
296
297   col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->variable_treeview), 0);
298
299   g_object_set (col, "title", _("Old"), NULL);
300
301   g_object_set (act->variable_treeview, "headers-visible", TRUE, NULL);
302
303   rdd->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
304
305   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->variable_treeview));
306
307   g_signal_connect (sel, "changed",
308                     G_CALLBACK (on_selection_change), act);
309
310   g_signal_connect (act->change_button, "clicked",
311                     G_CALLBACK (on_change_clicked),  act);
312 }
313
314
315 static void
316 psppire_dialog_action_recode_different_activate (PsppireDialogAction *a)
317 {
318   PsppireDialogActionRecode *act = PSPPIRE_DIALOG_ACTION_RECODE (a);
319   PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
320
321   psppire_dialog_action_recode_pre_activate (act, populate_treeview);
322
323   gtk_window_set_title (GTK_WINDOW (pda->dialog),
324                         _("Recode into Different Variables"));
325
326   gtk_window_set_title (GTK_WINDOW (act->old_and_new_dialog),
327                         _("Recode into Different Variables: Old and New Values "));
328
329   gtk_widget_show (act->output_variable_box);
330   
331   g_signal_connect_swapped (act->old_and_new_dialog, "show",
332                             G_CALLBACK (on_old_new_show), act);
333
334   psppire_dialog_action_set_refresh (pda, refresh);
335
336   psppire_dialog_action_set_valid_predicate (pda,
337                                              dialog_state_valid);
338 }
339
340 static void
341 append_into_clause (const PsppireDialogActionRecode *rd, struct string *dds)
342 {
343   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
344
345   /* If applicable set the INTO clause which determines into which variables the new values go */
346   GtkTreeIter iter;
347   ds_put_cstr (dds, "\n\tINTO ");
348   gboolean ok;
349       
350   for (ok = psppire_var_view_get_iter_first (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter);
351        ok;
352        ok = psppire_var_view_get_iter_next (PSPPIRE_VAR_VIEW (rd->variable_treeview), &iter))
353     {
354       struct nlp *nlp = NULL;
355       const struct variable *var = psppire_var_view_get_variable (PSPPIRE_VAR_VIEW (rd->variable_treeview), 0, &iter);
356
357       nlp = g_hash_table_lookup (rdd->varmap, var);
358             
359       ds_put_cstr (dds, nlp->name);
360       ds_put_cstr (dds, " ");
361     }
362 }
363
364 static void
365 append_string_declarations (const PsppireDialogActionRecode *rd, struct string *dds)
366 {
367   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
368
369   /* Declare new string variables if applicable */
370   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button)))
371     {
372       GHashTableIter iter;
373
374       struct variable *var = NULL;
375       struct nlp *nlp = NULL;
376
377       g_hash_table_iter_init (&iter, rdd->varmap);
378       while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
379         {
380           ds_put_cstr (dds, "\nSTRING ");
381           ds_put_cstr (dds, nlp->name);
382           ds_put_c_format (dds, " (A%d).",
383                            (int)
384                            gtk_spin_button_get_value (GTK_SPIN_BUTTON (rd->width_entry)));
385         }
386     }
387 }
388
389 static void
390 append_new_value_labels (const PsppireDialogActionRecode *rd, struct string *dds)
391 {
392   PsppireDialogActionRecodeDifferent *rdd = PSPPIRE_DIALOG_ACTION_RECODE_DIFFERENT (rd);
393
394   /* If applicable, set labels for the new variables. */
395   GHashTableIter iter;
396
397   struct variable *var = NULL;
398   struct nlp *nlp = NULL;
399
400   g_hash_table_iter_init (&iter, rdd->varmap);
401   while (g_hash_table_iter_next (&iter, (void**) &var, (void**) &nlp))
402     {
403       if (nlp->label)
404         {
405           struct string sl;
406           ds_init_empty (&sl);
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));
410
411           ds_destroy (&sl);
412         }
413     }
414 }
415
416 static char *
417 diff_generate_syntax (const PsppireDialogAction *act)
418 {
419   return psppire_dialog_action_recode_generate_syntax (act,
420                                                        append_string_declarations,
421                                                        append_into_clause,
422                                                        append_new_value_labels);
423 }
424
425 static gboolean
426 target_is_string (const PsppireDialogActionRecode *rd)
427 {
428   return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->string_button));
429 }
430
431 static void
432 psppire_dialog_action_recode_different_class_init (PsppireDialogActionRecodeDifferentClass *class)
433 {
434   psppire_dialog_action_set_activation (class, psppire_dialog_action_recode_different_activate);
435
436   PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = diff_generate_syntax;
437   PSPPIRE_DIALOG_ACTION_RECODE_CLASS (class)->target_is_string = target_is_string;
438 }
439
440
441 static void
442 psppire_dialog_action_recode_different_init (PsppireDialogActionRecodeDifferent *act)
443 {
444 }
445