1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2005, 2009, 2010, 2011, 2012 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/>. */
18 /* This module describes the behaviour of the Value Labels dialog box,
19 used for input of the value labels in the variable sheet */
23 #include "ui/gui/val-labs-dialog.h"
27 #include "data/value-labels.h"
28 #include "data/format.h"
29 #include "libpspp/i18n.h"
30 #include "ui/gui/builder-wrapper.h"
31 #include "ui/gui/helper.h"
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
37 static GObject *psppire_val_labs_dialog_constructor (GType type, guint,
38 GObjectConstructParam *);
39 static void psppire_val_labs_dialog_finalize (GObject *);
41 G_DEFINE_TYPE (PsppireValLabsDialog,
42 psppire_val_labs_dialog,
52 psppire_val_labs_dialog_set_property (GObject *object,
57 PsppireValLabsDialog *obj = PSPPIRE_VAL_LABS_DIALOG (object);
62 psppire_val_labs_dialog_set_variable (obj, g_value_get_pointer (value));
64 case PROP_VALUE_LABELS:
66 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
72 psppire_val_labs_dialog_get_property (GObject *object,
77 PsppireValLabsDialog *obj = PSPPIRE_VAL_LABS_DIALOG (object);
81 case PROP_VALUE_LABELS:
82 g_value_set_pointer (value, obj->labs);
86 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 psppire_val_labs_dialog_class_init (PsppireValLabsDialogClass *class)
94 GObjectClass *gobject_class;
95 gobject_class = G_OBJECT_CLASS (class);
97 gobject_class->constructor = psppire_val_labs_dialog_constructor;
98 gobject_class->finalize = psppire_val_labs_dialog_finalize;
99 gobject_class->set_property = psppire_val_labs_dialog_set_property;
100 gobject_class->get_property = psppire_val_labs_dialog_get_property;
102 g_object_class_install_property (
103 gobject_class, PROP_VARIABLE,
104 g_param_spec_pointer ("variable",
106 "Variable whose value labels are to be edited. The "
107 "variable's print format and encoding are also used "
111 g_object_class_install_property (
112 gobject_class, PROP_VALUE_LABELS,
113 g_param_spec_pointer ("value-labels",
115 "Edited value labels.",
120 psppire_val_labs_dialog_init (PsppireValLabsDialog *obj)
122 /* We do all of our work on widgets in the constructor function, because that
123 runs after the construction properties have been set. Otherwise
124 PsppireDialog's "orientation" property hasn't been set and therefore we
125 have no box to populate. */
126 obj->labs = val_labs_create (0);
130 psppire_val_labs_dialog_finalize (GObject *obj)
132 PsppireValLabsDialog *dialog = PSPPIRE_VAL_LABS_DIALOG (obj);
134 val_labs_destroy (dialog->labs);
135 g_free (dialog->encoding);
137 G_OBJECT_CLASS (psppire_val_labs_dialog_parent_class)->finalize (obj);
140 PsppireValLabsDialog *
141 psppire_val_labs_dialog_new (const struct variable *var)
143 return PSPPIRE_VAL_LABS_DIALOG (
144 g_object_new (PSPPIRE_TYPE_VAL_LABS_DIALOG,
145 "orientation", PSPPIRE_HORIZONTAL,
151 psppire_val_labs_dialog_run (GtkWindow *parent_window,
152 const struct variable *var)
154 PsppireValLabsDialog *dialog;
155 struct val_labs *labs;
157 dialog = psppire_val_labs_dialog_new (var);
158 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
159 gtk_widget_show (GTK_WIDGET (dialog));
161 labs = (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK
162 ? val_labs_clone (psppire_val_labs_dialog_get_value_labels (dialog))
165 gtk_widget_destroy (GTK_WIDGET (dialog));
170 /* This callback occurs when the text in the label entry box
173 on_label_entry_change (GtkEntry *entry, gpointer data)
177 PsppireValLabsDialog *dialog = data;
178 g_assert (dialog->labs);
180 text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
182 text_to_value__ (text, &dialog->format, dialog->encoding, &v);
184 if (val_labs_find (dialog->labs, &v))
186 gtk_widget_set_sensitive (dialog->change_button, TRUE);
187 gtk_widget_set_sensitive (dialog->add_button, FALSE);
191 gtk_widget_set_sensitive (dialog->change_button, FALSE);
192 gtk_widget_set_sensitive (dialog->add_button, TRUE);
195 value_destroy (&v, val_labs_get_width (dialog->labs));
199 /* Set the TREEVIEW list cursor to the item which has the value VAL */
201 select_treeview_from_value (GtkTreeView *treeview, union value *val)
206 We do this with a linear search through the model --- hardly
207 efficient, but the list is short ... */
210 GtkTreeModel * model = gtk_tree_view_get_model (treeview);
213 for (success = gtk_tree_model_get_iter_first (model, &iter);
215 success = gtk_tree_model_iter_next (model, &iter))
220 gtk_tree_model_get_value (model, &iter, 1, &gvalue);
222 v.f = g_value_get_double (&gvalue);
224 if ( 0 == memcmp (&v, val, sizeof (union value)))
230 path = gtk_tree_model_get_path (model, &iter);
233 gtk_tree_view_set_cursor (treeview, path, 0, 0);
234 gtk_tree_path_free (path);
240 /* This callback occurs when the text in the value entry box is
243 on_value_entry_change (GtkEntry *entry, gpointer data)
247 PsppireValLabsDialog *dialog = data;
249 const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
252 text_to_value__ (text, &dialog->format, dialog->encoding, &v);
254 g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
255 dialog->change_handler_id);
257 gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),"");
260 if ( (s = val_labs_find (dialog->labs, &v)) )
262 gtk_entry_set_text (GTK_ENTRY (dialog->label_entry), s);
263 gtk_widget_set_sensitive (dialog->add_button, FALSE);
264 gtk_widget_set_sensitive (dialog->remove_button, TRUE);
265 select_treeview_from_value (GTK_TREE_VIEW (dialog->treeview), &v);
269 gtk_widget_set_sensitive (dialog->remove_button, FALSE);
270 gtk_widget_set_sensitive (dialog->add_button, TRUE);
273 g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
274 dialog->change_handler_id);
276 value_destroy (&v, val_labs_get_width (dialog->labs));
280 /* Return the value-label pair currently selected in the dialog box */
282 get_selected_tuple (PsppireValLabsDialog *dialog,
283 union value *valuep, const char **label)
285 GtkTreeView *treeview = GTK_TREE_VIEW (dialog->treeview);
288 GValue the_value = {0};
291 GtkTreeSelection* sel = gtk_tree_view_get_selection (treeview);
293 GtkTreeModel * model = gtk_tree_view_get_model (treeview);
295 gtk_tree_selection_get_selected (sel, &model, &iter);
297 gtk_tree_model_get_value (model, &iter, 1, &the_value);
299 value.f = g_value_get_double (&the_value);
300 g_value_unset (&the_value);
306 struct val_lab *vl = val_labs_lookup (dialog->labs, &value);
308 *label = val_lab_get_escaped_label (vl);
313 static void repopulate_dialog (PsppireValLabsDialog *dialog);
315 /* Callback which occurs when the "Change" button is clicked */
317 on_change (GtkWidget *w, gpointer data)
319 PsppireValLabsDialog *dialog = data;
321 const gchar *val_text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
325 text_to_value__ (val_text, &dialog->format, dialog->encoding, &v);
327 val_labs_replace (dialog->labs, &v,
328 gtk_entry_get_text (GTK_ENTRY (dialog->label_entry)));
330 gtk_widget_set_sensitive (dialog->change_button, FALSE);
332 repopulate_dialog (dialog);
333 gtk_widget_grab_focus (dialog->value_entry);
335 value_destroy (&v, val_labs_get_width (dialog->labs));
338 /* Callback which occurs when the "Add" button is clicked */
340 on_add (GtkWidget *w, gpointer data)
342 PsppireValLabsDialog *dialog = data;
346 const gchar *text = gtk_entry_get_text (GTK_ENTRY (dialog->value_entry));
348 text_to_value__ (text, &dialog->format, dialog->encoding, &v);
350 if (val_labs_add (dialog->labs, &v,
352 ( GTK_ENTRY (dialog->label_entry)) ) )
354 gtk_widget_set_sensitive (dialog->add_button, FALSE);
356 repopulate_dialog (dialog);
357 gtk_widget_grab_focus (dialog->value_entry);
360 value_destroy (&v, val_labs_get_width (dialog->labs));
363 /* Callback which occurs when the "Remove" button is clicked */
365 on_remove (GtkWidget *w, gpointer data)
367 PsppireValLabsDialog *dialog = data;
372 get_selected_tuple (dialog, &value, NULL);
373 vl = val_labs_lookup (dialog->labs, &value);
375 val_labs_remove (dialog->labs, vl);
377 repopulate_dialog (dialog);
378 gtk_widget_grab_focus (dialog->value_entry);
380 gtk_widget_set_sensitive (dialog->remove_button, FALSE);
385 /* Callback which occurs when a line item is selected in the list of
386 value--label pairs.*/
388 on_select_row (GtkTreeView *treeview, gpointer data)
390 PsppireValLabsDialog *dialog = data;
393 const char *label = NULL;
397 get_selected_tuple (dialog, &value, &label);
398 text = value_to_text__ (value, &dialog->format, dialog->encoding);
400 g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
401 dialog->value_handler_id);
403 gtk_entry_set_text (GTK_ENTRY (dialog->value_entry), text);
405 g_signal_handler_unblock (GTK_ENTRY (dialog->value_entry),
406 dialog->value_handler_id);
409 g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
410 dialog->change_handler_id);
413 gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),
416 g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
417 dialog->change_handler_id);
419 gtk_widget_set_sensitive (dialog->remove_button, TRUE);
420 gtk_widget_set_sensitive (dialog->change_button, FALSE);
424 /* Create a new dialog box
425 (there should normally be only one)*/
427 psppire_val_labs_dialog_constructor (GType type,
429 GObjectConstructParam *properties)
431 PsppireValLabsDialog *dialog;
432 GtkTreeViewColumn *column;
434 GtkCellRenderer *renderer ;
436 GtkBuilder *xml = builder_new ("val-labs-dialog.ui");
438 GtkContainer *content_area;
441 obj = G_OBJECT_CLASS (psppire_val_labs_dialog_parent_class)->constructor (
442 type, n_properties, properties);
443 dialog = PSPPIRE_VAL_LABS_DIALOG (obj);
445 content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog)->box);
446 gtk_container_add (GTK_CONTAINER (content_area),
447 get_widget_assert (xml, "val-labs-dialog"));
449 dialog->value_entry = get_widget_assert (xml,"value_entry");
450 dialog->label_entry = get_widget_assert (xml,"label_entry");
452 dialog->add_button = get_widget_assert (xml, "val_labs_add");
453 dialog->remove_button = get_widget_assert (xml, "val_labs_remove");
454 dialog->change_button = get_widget_assert (xml, "val_labs_change");
456 dialog->treeview = get_widget_assert (xml,"treeview1");
458 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dialog->treeview), FALSE);
460 renderer = gtk_cell_renderer_text_new ();
462 column = gtk_tree_view_column_new_with_attributes ("Title",
468 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->treeview), column);
470 dialog->change_handler_id =
471 g_signal_connect (dialog->label_entry,
473 G_CALLBACK (on_label_entry_change), dialog);
475 dialog->value_handler_id =
476 g_signal_connect (dialog->value_entry,
478 G_CALLBACK (on_value_entry_change), dialog);
480 g_signal_connect (dialog->change_button,
482 G_CALLBACK (on_change), dialog);
485 g_signal_connect (dialog->treeview, "cursor-changed",
486 G_CALLBACK (on_select_row), dialog);
488 g_signal_connect (dialog->remove_button, "clicked",
489 G_CALLBACK (on_remove), dialog);
491 g_signal_connect (dialog->add_button, "clicked",
492 G_CALLBACK (on_add), dialog);
496 g_object_unref (xml);
502 /* Populate the components of the dialog box, from the 'labs' member
505 repopulate_dialog (PsppireValLabsDialog *dialog)
507 const struct val_lab **labels;
513 GtkListStore *list_store = gtk_list_store_new (2,
517 g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
518 dialog->change_handler_id);
519 g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
520 dialog->value_handler_id);
522 gtk_entry_set_text (GTK_ENTRY (dialog->value_entry), "");
523 gtk_entry_set_text (GTK_ENTRY (dialog->label_entry), "");
525 g_signal_handler_unblock (GTK_ENTRY (dialog->value_entry),
526 dialog->value_handler_id);
527 g_signal_handler_unblock (GTK_ENTRY (dialog->label_entry),
528 dialog->change_handler_id);
530 labels = val_labs_sorted (dialog->labs);
531 n_labels = val_labs_count (dialog->labs);
532 for (i = 0; i < n_labels; i++)
534 const struct val_lab *vl = labels[i];
537 value_to_text__ (vl->value, &dialog->format, dialog->encoding);
539 gchar *const text = g_strdup_printf (_("%s = `%s'"), vstr,
540 val_lab_get_escaped_label (vl));
542 gtk_list_store_append (list_store, &iter);
543 gtk_list_store_set (list_store, &iter,
553 gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
554 GTK_TREE_MODEL (list_store));
556 g_object_unref (list_store);
561 psppire_val_labs_dialog_set_variable (PsppireValLabsDialog *dialog,
562 const struct variable *var)
564 val_labs_destroy (dialog->labs);
567 g_free (dialog->encoding);
568 dialog->encoding = NULL;
572 dialog->labs = val_labs_clone (var_get_value_labels (var));
573 dialog->encoding = g_strdup (var_get_encoding (var));
574 dialog->format = *var_get_print_format (var);
577 dialog->format = F_8_0;
579 if (dialog->labs == NULL)
580 dialog->labs = val_labs_create (var_get_width (var));
582 repopulate_dialog (dialog);
585 const struct val_labs *
586 psppire_val_labs_dialog_get_value_labels (const PsppireValLabsDialog *dialog)