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