Change some instances of GtkAction to PsppireDialogAction
[pspp] / src / ui / gui / psppire-dialog-action-autorecode.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2015  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
18 #include <config.h>
19
20 #include "psppire-dialog-action-autorecode.h"
21
22 #include "psppire-var-view.h"
23 #include <stdlib.h>
24 #include "psppire-dialog.h"
25 #include "builder-wrapper.h"
26
27 #include "gettext.h"
28 #define _(msgid) gettext (msgid)
29 #define N_(msgid) msgid
30
31
32 static void psppire_dialog_action_autorecode_init            (PsppireDialogActionAutorecode      *act);
33 static void psppire_dialog_action_autorecode_class_init      (PsppireDialogActionAutorecodeClass *class);
34
35
36 G_DEFINE_TYPE (PsppireDialogActionAutorecode, psppire_dialog_action_autorecode, PSPPIRE_TYPE_DIALOG_ACTION);
37
38
39 static gboolean
40 dialog_state_valid (gpointer pda)
41 {
42   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (pda);
43   
44   GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->var_view));
45   const gint n_vars = gtk_tree_model_iter_n_children (model, NULL);
46
47   if (n_vars == 0)
48     return FALSE;
49   
50   if (g_hash_table_size (rd->varmap) != n_vars)
51     return FALSE;
52
53   return TRUE;
54 }
55
56 static void
57 refresh (PsppireDialogAction *pda)
58 {
59   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (pda);
60
61   GtkTreeModel *target_list = gtk_tree_view_get_model (GTK_TREE_VIEW (rd->var_view));
62
63   gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
64   gtk_widget_set_sensitive  (rd->new_name_entry, FALSE);
65   gtk_widget_set_sensitive  (rd->change_button, FALSE);
66
67   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->ascending), TRUE);
68   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->group), FALSE);
69   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->blank), FALSE);
70
71   if (rd->varmap )
72     g_hash_table_remove_all (rd->varmap);
73
74   gtk_list_store_clear (GTK_LIST_STORE (target_list));
75
76   
77 }
78
79 /* Name-Label pair */
80 struct nlp
81 {
82   char *name;
83   char *label;
84 };
85
86 static struct nlp *
87 nlp_create (const char *name, const char *label)
88 {
89   struct nlp *nlp = xmalloc (sizeof *nlp);
90
91   nlp->name = g_strdup (name);
92
93   nlp->label = NULL;
94
95   if ( label != NULL && 0 != strcmp ("", label))
96     nlp->label = g_strdup (label);
97
98   return nlp;
99 }
100
101 static void
102 nlp_destroy (gpointer data)
103 {
104   struct nlp *nlp = data ;
105   if ( ! nlp )
106     return;
107
108   g_free (nlp->name);
109   g_free (nlp->label);
110   g_free (nlp);
111 }
112
113
114 static char *
115 generate_syntax (PsppireDialogAction *act)
116 {
117   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (act);
118   
119   GHashTableIter iter;
120   gpointer key, value;
121   gchar *text;
122
123   GString *string = g_string_new ("AUTORECODE");
124
125   g_string_append (string, "\n\tVARIABLES =");
126
127   g_hash_table_iter_init (&iter, rd->varmap);
128   while (g_hash_table_iter_next (&iter, &key, &value)) 
129   {
130     struct variable *var = key;
131     g_string_append (string, " ");
132     g_string_append (string, var_get_name (var));
133   }
134
135   g_string_append (string, " INTO");
136
137   g_hash_table_iter_init (&iter, rd->varmap);
138   while (g_hash_table_iter_next (&iter, &key, &value)) 
139   {
140     struct nlp *nlp  = value;
141     g_string_append (string, " ");
142     g_string_append (string, nlp->name);
143   }
144
145   if ( ! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->ascending)))
146     g_string_append (string, "\n\t/DESCENDING");
147
148   if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->group)))
149     g_string_append (string, "\n\t/GROUP");
150
151   if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (rd->blank)))
152     g_string_append (string, "\n\t/BLANK");
153
154   g_string_append (string, ".\n");
155
156   text = string->str;
157
158   g_string_free (string, FALSE);
159
160   return text;
161 }
162
163 static void
164 on_change_clicked (GObject *obj, gpointer data)
165 {
166   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (data);
167   struct variable *var = NULL;
168   struct nlp *nlp;
169   GtkTreeModel *model = psppire_var_view_get_current_model (PSPPIRE_VAR_VIEW (rd->var_view));
170   GtkTreeIter iter;
171   GtkTreeSelection *selection =
172     gtk_tree_view_get_selection (GTK_TREE_VIEW (rd->var_view));
173
174   GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
175
176   const gchar *dest_var_name =
177     gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
178
179   if ( NULL == rows || rows->next != NULL)
180     goto finish;
181
182   gtk_tree_model_get_iter (model, &iter, rows->data);
183
184   gtk_tree_model_get (model, &iter, 0, &var, -1);
185
186   g_hash_table_remove (rd->varmap, var);
187
188   nlp = nlp_create (dest_var_name, NULL);
189
190   g_hash_table_insert (rd->varmap, var, nlp);
191
192   gtk_tree_model_row_changed (model, rows->data, &iter);
193
194  finish:
195   g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
196   g_list_free (rows);
197 }
198
199
200 static void
201 on_entry_change (PsppireDialogActionAutorecode *rd)
202 {
203   gboolean valid = TRUE;
204   const char *text = gtk_entry_get_text (GTK_ENTRY (rd->new_name_entry));
205
206   if ( 0 == strcmp ("", text))
207     valid = FALSE;
208   else if (psppire_dict_lookup_var (rd->dict, text))
209     valid = FALSE;
210   else
211     {
212       GHashTableIter iter;
213       gpointer key, value;
214
215       g_hash_table_iter_init (&iter, rd->varmap);
216       while (g_hash_table_iter_next (&iter, &key, &value)) 
217         {
218           struct nlp *nlp = value;
219           
220           if ( 0 == strcmp (nlp->name, text))
221             {
222               valid = FALSE;
223               break;
224             }
225         }
226     }
227
228   gtk_widget_set_sensitive  (rd->change_button, valid);
229 }
230
231
232 /* Callback which gets called when a new row is selected
233    in the variable treeview.
234    It sets the name and label entry widgets to reflect the
235    currently selected row.
236 */
237 static void
238 on_selection_change (GtkTreeSelection *selection, gpointer data)
239 {
240   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (data);
241
242   GtkTreeModel *model = psppire_var_view_get_current_model (PSPPIRE_VAR_VIEW (rd->var_view));
243
244   GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
245
246   if ( rows && !rows->next)
247     {
248       /* Exactly one row is selected */
249       struct nlp *nlp;
250       struct variable *var;
251       gboolean ok;
252       GtkTreeIter iter;
253
254       gtk_widget_set_sensitive  (rd->new_name_entry, TRUE);
255       gtk_widget_set_sensitive  (rd->change_button, TRUE);      
256
257
258       ok = gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) rows->data);
259       g_return_if_fail (ok);
260
261       gtk_tree_model_get (model, &iter, 0, &var, -1);
262
263       nlp = g_hash_table_lookup (rd->varmap, var);
264
265       if (nlp)
266         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), nlp->name ? nlp->name : "");
267       else
268         gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
269     }
270   else
271     {
272       gtk_entry_set_text (GTK_ENTRY (rd->new_name_entry), "");
273       gtk_widget_set_sensitive  (rd->new_name_entry, FALSE);
274       gtk_widget_set_sensitive  (rd->change_button, FALSE);
275     }
276
277   g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
278   g_list_free (rows);
279 }
280
281
282
283 static void
284 render_new_var_name (GtkTreeViewColumn *tree_column,
285                      GtkCellRenderer *cell,
286                      GtkTreeModel *tree_model,
287                      GtkTreeIter *iter,
288                      gpointer data)
289 {
290   struct nlp *nlp = NULL;
291
292   PsppireDialogActionAutorecode *rd = PSPPIRE_DIALOG_ACTION_AUTORECODE (data);
293
294
295   
296   struct variable *var = NULL;
297
298   gtk_tree_model_get (tree_model, iter, 
299                       0, &var,
300                       -1);
301
302   nlp = g_hash_table_lookup (rd->varmap, var);
303
304   if ( nlp )
305     g_object_set (cell, "text", nlp->name, NULL);
306   else
307     g_object_set (cell, "text", "", NULL);
308 }
309
310
311 static void
312 psppire_dialog_action_autorecode_activate (PsppireDialogAction *a)
313 {
314   PsppireDialogActionAutorecode *act = PSPPIRE_DIALOG_ACTION_AUTORECODE (a);
315   PsppireDialogAction *pda = PSPPIRE_DIALOG_ACTION (a);
316
317   GHashTable *thing = psppire_dialog_action_get_hash_table (pda);
318   GtkBuilder *xml = g_hash_table_lookup (thing, a);
319   if (!xml)
320     {
321       xml = builder_new ("autorecode.ui");
322       g_hash_table_insert (thing, a, xml);
323
324       pda->dialog = get_widget_assert   (xml, "autorecode-dialog");
325       pda->source = get_widget_assert   (xml, "dict-view");
326
327
328
329
330       act->var_view = get_widget_assert   (xml, "var-view");
331
332       act->new_name_entry = get_widget_assert (xml, "entry1");
333       act->change_button = get_widget_assert (xml, "button1");
334       act->ascending = get_widget_assert (xml, "radiobutton1");
335       act->group = get_widget_assert (xml, "checkbutton1");
336       act->blank = get_widget_assert (xml, "checkbutton2");
337
338       {
339         GtkTreeSelection *sel;
340
341         GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
342
343         GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (_("New"),
344                                                                            renderer,
345                                                                            "text", NULL,
346                                                                            NULL);
347
348         gtk_tree_view_column_set_cell_data_func (col, renderer,
349                                                  render_new_var_name,
350                                                  act, NULL);
351
352         gtk_tree_view_append_column (GTK_TREE_VIEW (act->var_view), col);
353
354
355         col = gtk_tree_view_get_column (GTK_TREE_VIEW (act->var_view), 0);
356
357         g_object_set (col, "title", _("Old"), NULL);
358
359         g_object_set (act->var_view, "headers-visible", TRUE, NULL);
360
361         act->varmap = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, nlp_destroy);
362
363
364         sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (act->var_view));
365
366
367         g_signal_connect (sel, "changed",
368                           G_CALLBACK (on_selection_change), act);
369
370         g_signal_connect (act->change_button, "clicked",
371                           G_CALLBACK (on_change_clicked),  act);
372
373         g_signal_connect_swapped (act->new_name_entry, "changed",
374                                   G_CALLBACK (on_entry_change),  act);
375
376       }
377
378     }
379   
380   psppire_dialog_action_set_refresh (pda, refresh);
381   psppire_dialog_action_set_valid_predicate (pda, dialog_state_valid);
382
383   if (PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_autorecode_parent_class)->activate)
384     PSPPIRE_DIALOG_ACTION_CLASS (psppire_dialog_action_autorecode_parent_class)->activate (pda);
385 }
386
387 static void
388 psppire_dialog_action_autorecode_class_init (PsppireDialogActionAutorecodeClass *class)
389 {
390   psppire_dialog_action_set_activation (class, psppire_dialog_action_autorecode_activate);
391   PSPPIRE_DIALOG_ACTION_CLASS (class)->generate_syntax = generate_syntax;
392 }
393
394
395 static void
396 psppire_dialog_action_autorecode_init (PsppireDialogActionAutorecode *act)
397 {
398 }