Whitespace changes only
[pspp-builds.git] / src / ui / gui / val-labs-dialog.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2005  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20
21 /*  This module describes the behaviour of the Value Labels dialog box,
22     used for input of the value labels in the variable sheet */
23
24 #include <config.h>
25
26 #include <string.h>
27
28 #include "helper.h"
29 #include "val-labs-dialog.h"
30 #include <data/value-labels.h>
31
32 /* This callback occurs when the text in the label entry box
33    is changed */
34 static void
35 on_label_entry_change (GtkEntry *entry, gpointer data)
36 {
37   union value v;
38   const gchar *text ;
39   struct val_labs_dialog *dialog = data;
40   g_assert (dialog->labs);
41
42   text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
43
44   text_to_value (text, &v,
45                 *var_get_write_format (dialog->pv));
46
47
48   if ( val_labs_find (dialog->labs, v) )
49     {
50       gtk_widget_set_sensitive (dialog->change_button, TRUE);
51       gtk_widget_set_sensitive (dialog->add_button, FALSE);
52     }
53   else
54     {
55       gtk_widget_set_sensitive (dialog->change_button, FALSE);
56       gtk_widget_set_sensitive (dialog->add_button, TRUE);
57     }
58 }
59
60
61 /* Set the TREEVIEW list cursor to the item which has the value VAL */
62 static void
63 select_treeview_from_value (GtkTreeView *treeview, union value *val)
64 {
65   GtkTreePath *path ;
66
67   /*
68     We do this with a linear search through the model --- hardly
69     efficient, but the list is short ... */
70   GtkTreeIter iter;
71
72   GtkTreeModel * model  = gtk_tree_view_get_model (treeview);
73
74   gboolean success;
75   for (success = gtk_tree_model_get_iter_first (model, &iter);
76        success;
77        success = gtk_tree_model_iter_next (model, &iter))
78     {
79       union value v;
80       GValue gvalue = {0};
81
82       gtk_tree_model_get_value (model, &iter, 1, &gvalue);
83
84       v.f = g_value_get_double (&gvalue);
85
86       if ( 0 == memcmp (&v, val, sizeof (union value)))
87         {
88           break;
89         }
90     }
91
92   path = gtk_tree_model_get_path (model, &iter);
93   if ( path )
94     {
95       gtk_tree_view_set_cursor (treeview, path, 0, 0);
96       gtk_tree_path_free (path);
97     }
98
99 }
100
101
102 /* This callback occurs when the text in the value entry box is
103    changed */
104 static void
105 on_value_entry_change (GtkEntry *entry, gpointer data)
106 {
107   char *s;
108
109   struct val_labs_dialog *dialog = data;
110
111   const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
112
113   union value v;
114   text_to_value (text, &v,
115                 *var_get_write_format (dialog->pv));
116
117
118   g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
119                          dialog->change_handler_id);
120
121   gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),"");
122
123
124   if ( (s = val_labs_find (dialog->labs, v)) )
125     {
126       gtk_entry_set_text (GTK_ENTRY (dialog->label_entry), s);
127       gtk_widget_set_sensitive (dialog->add_button, FALSE);
128       gtk_widget_set_sensitive (dialog->remove_button, TRUE);
129       select_treeview_from_value (GTK_TREE_VIEW (dialog->treeview), &v);
130     }
131   else
132     {
133       gtk_widget_set_sensitive (dialog->remove_button, FALSE);
134       gtk_widget_set_sensitive (dialog->add_button, TRUE);
135     }
136
137   g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
138                          dialog->change_handler_id);
139 }
140
141
142 /* Callback for when the Value Labels dialog is closed using
143    the OK button.*/
144 static gint
145 val_labs_ok (GtkWidget *w, gpointer data)
146 {
147   struct val_labs_dialog *dialog = data;
148
149   var_set_value_labels (dialog->pv, dialog->labs);
150
151   val_labs_destroy (dialog->labs);
152
153   dialog->labs = 0;
154
155   return FALSE;
156 }
157
158 /* Callback for when the Value Labels dialog is closed using
159    the Cancel button.*/
160 static gint
161 val_labs_cancel (GtkWidget *w, gpointer data)
162 {
163   struct val_labs_dialog *dialog = data;
164
165   val_labs_destroy (dialog->labs);
166   dialog->labs = 0;
167
168   return FALSE;
169 }
170
171
172 /* Return the value-label pair currently selected in the dialog box  */
173 static struct val_lab *
174 get_selected_tuple (struct val_labs_dialog *dialog)
175 {
176   GtkTreeView *treeview = GTK_TREE_VIEW (dialog->treeview);
177   static struct val_lab vl;
178
179   GtkTreeIter iter ;
180   GValue the_value = {0};
181
182   GtkTreeSelection* sel =  gtk_tree_view_get_selection (treeview);
183
184   GtkTreeModel * model  = gtk_tree_view_get_model (treeview);
185
186   gtk_tree_selection_get_selected (sel, &model, &iter);
187
188   gtk_tree_model_get_value (model, &iter, 1, &the_value);
189
190   vl.value.f = g_value_get_double (&the_value);
191   g_value_unset (&the_value);
192
193   vl.label = val_labs_find (dialog->labs, vl.value);
194
195   return &vl;
196 }
197
198
199 static void repopulate_dialog (struct val_labs_dialog *dialog);
200
201 /* Callback which occurs when the "Change" button is clicked */
202 static gint
203 on_change (GtkWidget *w, gpointer data)
204 {
205   struct val_labs_dialog *dialog = data;
206
207   const gchar *val_text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
208
209   union value v;
210
211   text_to_value (val_text, &v,
212                 *var_get_write_format (dialog->pv));
213
214   val_labs_replace (dialog->labs, v,
215                     gtk_entry_get_text (GTK_ENTRY (dialog->label_entry)));
216
217   gtk_widget_set_sensitive (dialog->change_button, FALSE);
218
219   repopulate_dialog (dialog);
220
221   return FALSE;
222 }
223
224 /* Callback which occurs when the "Add" button is clicked */
225 static gint
226 on_add (GtkWidget *w, gpointer data)
227 {
228   struct val_labs_dialog *dialog = data;
229
230   union value v;
231
232   const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
233
234   text_to_value (text, &v,
235                 *var_get_write_format (dialog->pv));
236
237
238   if ( ! val_labs_add (dialog->labs, v,
239                        gtk_entry_get_text
240                        ( GTK_ENTRY (dialog->label_entry)) ) )
241     return FALSE;
242
243   gtk_widget_set_sensitive (dialog->add_button, FALSE);
244
245   repopulate_dialog (dialog);
246
247   return FALSE;
248 }
249
250 /* Callback which occurs when the "Remove" button is clicked */
251 static gint
252 on_remove (GtkWidget *w, gpointer data)
253 {
254   struct val_labs_dialog *dialog = data;
255
256   struct val_lab *vl = get_selected_tuple (dialog);
257
258   val_labs_remove (dialog->labs, vl->value);
259
260   repopulate_dialog (dialog);
261
262   gtk_widget_set_sensitive (dialog->remove_button, FALSE);
263
264   return FALSE;
265 }
266
267
268
269 /* Callback which occurs when a line item is selected in the list of
270    value--label pairs.*/
271 static void
272 on_select_row                  (GtkTreeView *treeview,
273                                 gpointer data)
274 {
275   gchar *labeltext;
276   struct val_labs_dialog *dialog = data;
277
278   struct val_lab * vl  = get_selected_tuple (dialog);
279
280   gchar *const text = value_to_text (vl->value,
281                                     *var_get_write_format (dialog->pv));
282
283   g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
284                          dialog->value_handler_id);
285
286   gtk_entry_set_text (GTK_ENTRY (dialog->value_entry), text);
287
288   g_signal_handler_unblock (GTK_ENTRY (dialog->value_entry),
289                          dialog->value_handler_id);
290   g_free (text);
291
292   g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
293                          dialog->change_handler_id);
294
295   labeltext = pspp_locale_to_utf8 (vl->label, -1, 0);
296   gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),
297                      labeltext);
298   g_free (labeltext);
299
300   g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
301                          dialog->change_handler_id);
302
303   gtk_widget_set_sensitive (dialog->remove_button, TRUE);
304   gtk_widget_set_sensitive (dialog->change_button, FALSE);
305 }
306
307
308 /* Create a new dialog box
309    (there should  normally be only one)*/
310 struct val_labs_dialog *
311 val_labs_dialog_create (GladeXML *xml)
312 {
313   GtkTreeViewColumn *column;
314
315   GtkCellRenderer *renderer ;
316
317   struct val_labs_dialog *dialog = g_malloc (sizeof (*dialog));
318
319   dialog->window = get_widget_assert (xml,"val_labs_dialog");
320   dialog->value_entry = get_widget_assert (xml,"value_entry");
321   dialog->label_entry = get_widget_assert (xml,"label_entry");
322
323   gtk_window_set_transient_for
324     (GTK_WINDOW (dialog->window),
325      GTK_WINDOW (get_widget_assert (xml, "data_editor")));
326
327   dialog->ok = get_widget_assert (xml, "val_labs_ok");
328   dialog->add_button = get_widget_assert (xml, "val_labs_add");
329   dialog->remove_button = get_widget_assert (xml, "val_labs_remove");
330   dialog->change_button = get_widget_assert (xml, "val_labs_change");
331
332   dialog->treeview = get_widget_assert (xml,"treeview1");
333
334   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->treeview), FALSE);
335
336   renderer = gtk_cell_renderer_text_new ();
337
338   column = gtk_tree_view_column_new_with_attributes ("Title",
339                                                      renderer,
340                                                      "text",
341                                                      0,
342                                                      NULL);
343
344   gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->treeview), column);
345
346   g_signal_connect (GTK_OBJECT (get_widget_assert (xml, "val_labs_cancel")),
347                    "clicked",
348                    GTK_SIGNAL_FUNC (val_labs_cancel), dialog);
349
350   dialog->change_handler_id =
351     g_signal_connect (GTK_OBJECT (dialog->label_entry),
352                      "changed",
353                      GTK_SIGNAL_FUNC (on_label_entry_change), dialog);
354
355   dialog->value_handler_id  =
356     g_signal_connect (GTK_OBJECT (dialog->value_entry),
357                      "changed",
358                      GTK_SIGNAL_FUNC (on_value_entry_change), dialog);
359
360   g_signal_connect (GTK_OBJECT (dialog->change_button),
361                    "clicked",
362                    GTK_SIGNAL_FUNC (on_change), dialog);
363
364
365   g_signal_connect (GTK_OBJECT (get_widget_assert (xml, "val_labs_ok")),
366                    "clicked",
367                    GTK_SIGNAL_FUNC (val_labs_ok), dialog);
368
369
370   g_signal_connect (GTK_OBJECT (dialog->treeview), "cursor-changed",
371                    GTK_SIGNAL_FUNC (on_select_row), dialog);
372
373
374   g_signal_connect (GTK_OBJECT (dialog->remove_button), "clicked",
375                    GTK_SIGNAL_FUNC (on_remove), dialog);
376
377
378   g_signal_connect (GTK_OBJECT (dialog->add_button), "clicked",
379                    GTK_SIGNAL_FUNC (on_add), dialog);
380
381   dialog->labs = 0;
382
383   return dialog;
384 }
385
386
387 /* Populate the components of the dialog box, from the 'labs' member
388    variable */
389 static void
390 repopulate_dialog (struct val_labs_dialog *dialog)
391 {
392   struct val_labs_iterator *vli = 0;
393   struct val_lab *vl;
394
395   GtkTreeIter iter;
396
397   GtkListStore *list_store = gtk_list_store_new (2,
398                                                  G_TYPE_STRING,
399                                                  G_TYPE_DOUBLE);
400
401   g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
402                          dialog->change_handler_id);
403   g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
404                          dialog->value_handler_id);
405
406   gtk_entry_set_text (GTK_ENTRY (dialog->value_entry), "");
407   gtk_entry_set_text (GTK_ENTRY (dialog->label_entry), "");
408
409   g_signal_handler_unblock (GTK_ENTRY (dialog->value_entry),
410                          dialog->value_handler_id);
411   g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
412                            dialog->change_handler_id);
413
414
415   for (vl = val_labs_first_sorted (dialog->labs, &vli);
416       vl;
417       vl = val_labs_next (dialog->labs, &vli))
418     {
419
420       gchar *const vstr  =
421         value_to_text (vl->value,
422                       *var_get_write_format (dialog->pv));
423
424       gchar *labeltext =
425         pspp_locale_to_utf8 (vl->label, -1, 0);
426
427       gchar *const text = g_strdup_printf ("%s = \"%s\"",
428                                           vstr, labeltext);
429
430
431       gtk_list_store_append (list_store, &iter);
432       gtk_list_store_set (list_store, &iter,
433                           0, text,
434                           1, vl->value.f,
435                           -1);
436
437       g_free (labeltext);
438       g_free (text);
439       g_free (vstr);
440     }
441
442   gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
443                           GTK_TREE_MODEL (list_store));
444
445   g_object_unref (list_store);
446
447 }
448
449 /* Initialise and display the dialog box */
450 void
451 val_labs_dialog_show (struct val_labs_dialog *dialog)
452 {
453   const struct val_labs *value_labels;
454
455   g_assert (!dialog->labs);
456
457   value_labels = var_get_value_labels (dialog->pv);
458
459   if (value_labels)
460     dialog->labs = val_labs_copy ( value_labels );
461   else
462     dialog->labs = val_labs_create ( var_get_width (dialog->pv));
463
464   gtk_widget_set_sensitive (dialog->remove_button, FALSE);
465   gtk_widget_set_sensitive (dialog->change_button, FALSE);
466   gtk_widget_set_sensitive (dialog->add_button, FALSE);
467
468   repopulate_dialog (dialog);
469   gtk_widget_show (dialog->window);
470 }
471