1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2012 Free Software Foundation, Inc.
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 #include "psppire-value-entry.h"
19 #include "data/data-in.h"
20 #include "data/value-labels.h"
21 #include "data/variable.h"
22 #include "libpspp/cast.h"
23 #include "libpspp/i18n.h"
24 #include "ui/gui/helper.h"
25 #include "ui/gui/psppire-format.h"
27 static void psppire_value_entry_finalize (GObject *);
29 G_DEFINE_TYPE (PsppireValueEntry,
35 COL_LABEL, /* Value label string. */
36 COL_VALUE, /* union value *. */
43 PROP_SHOW_VALUE_LABEL,
52 psppire_value_entry_set_property (GObject *object,
57 PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (object);
61 case PROP_SHOW_VALUE_LABEL:
62 psppire_value_entry_set_show_value_label (obj,
63 g_value_get_boolean (value));
67 psppire_value_entry_set_variable (obj, g_value_get_pointer (value));
70 case PROP_VALUE_LABELS:
71 psppire_value_entry_set_value_labels (obj, g_value_get_pointer (value));
75 psppire_value_entry_set_format (obj, g_value_get_boxed (value));
79 psppire_value_entry_set_encoding (obj, g_value_get_string (value));
83 psppire_value_entry_set_width (obj, g_value_get_int (value));
87 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
93 psppire_value_entry_get_property (GObject *object,
98 PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (object);
102 case PROP_SHOW_VALUE_LABEL:
103 g_value_set_boolean (value,
104 psppire_value_entry_get_show_value_label (obj));
108 g_return_if_reached ();
110 case PROP_VALUE_LABELS:
111 g_value_set_pointer (value, obj->val_labs);
115 g_value_set_boxed (value, &obj->format);
119 g_value_set_string (value, psppire_value_entry_get_encoding (obj));
123 g_value_set_int (value, psppire_value_entry_get_width (obj));
127 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
133 psppire_value_entry_text_changed (GtkEntryBuffer *buffer,
135 PsppireValueEntry *obj)
137 obj->cur_value = NULL;
142 on_realize (GtkWidget *w)
144 GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (w)));
145 GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry);
147 gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (w), COL_LABEL);
149 g_signal_connect (buffer, "notify::text",
150 G_CALLBACK (psppire_value_entry_text_changed), w);
152 gtk_widget_set_can_focus (GTK_WIDGET (entry), TRUE);
154 GTK_WIDGET_CLASS (psppire_value_entry_parent_class)->realize (w);
159 The "has-entry" property for the parent class (GTK_COMBO_BOX) is
160 a) Construct-only ; and b) defaults to FALSE.
161 We want it to default to TRUE. So we override it here.
164 my_constructor (GType type,
165 guint n_construct_properties,
166 GObjectConstructParam *construct_properties)
169 G_OBJECT_CLASS (psppire_value_entry_parent_class)->constructor
170 (type, n_construct_properties, construct_properties);
172 g_object_set (o, "has-entry", TRUE, NULL);
178 psppire_value_entry_class_init (PsppireValueEntryClass *class)
180 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
181 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
184 gobject_class->finalize = psppire_value_entry_finalize;
185 gobject_class->set_property = psppire_value_entry_set_property;
186 gobject_class->get_property = psppire_value_entry_get_property;
187 gobject_class->constructor = my_constructor;
188 widget_class->realize = on_realize;
190 g_object_class_install_property (
191 gobject_class, PROP_SHOW_VALUE_LABEL,
192 g_param_spec_boolean ("show-value-label",
194 "If true, a value that has a value label is shown "
195 "as the label. If false, all values are shown "
198 G_PARAM_WRITABLE | G_PARAM_READABLE));
200 g_object_class_install_property (
201 gobject_class, PROP_VARIABLE,
202 g_param_spec_pointer ("variable",
204 "Set to configure the PsppireValueEntry according "
205 "to the specified variable's value labels, format, "
206 "width, and encoding.",
209 g_object_class_install_property (
210 gobject_class, PROP_VALUE_LABELS,
211 g_param_spec_pointer ("value-labels",
213 "The set of value labels from which the user may "
214 "choose and which is used to display the value (if "
215 "value labels are to be displayed)",
216 G_PARAM_READABLE | G_PARAM_WRITABLE));
218 g_object_class_install_property (
219 gobject_class, PROP_FORMAT,
220 g_param_spec_boxed ("format",
222 "The format used to display values (that are not "
223 "displayed as value labels) and to interpret values "
226 G_PARAM_READABLE | G_PARAM_WRITABLE));
228 g_object_class_install_property (
229 gobject_class, PROP_ENCODING,
230 g_param_spec_string ("encoding",
232 "The encoding (e.g. \"UTF-8\") for string values. "
233 "For numeric values this setting has no effect.",
235 G_PARAM_READABLE | G_PARAM_WRITABLE));
237 g_object_class_install_property (
238 gobject_class, PROP_WIDTH,
239 g_param_spec_int ("width",
241 "Width of the value, either 0 for a numeric value or "
242 "a positive integer count of bytes for string values.",
245 G_PARAM_READABLE | G_PARAM_WRITABLE));
249 psppire_value_entry_init (PsppireValueEntry *obj)
251 obj->show_value_label = true;
252 obj->val_labs = NULL;
254 obj->encoding = NULL;
255 obj->cur_value = NULL;
259 psppire_value_entry_finalize (GObject *gobject)
261 PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (gobject);
263 val_labs_destroy (obj->val_labs);
264 g_free (obj->encoding);
266 G_OBJECT_CLASS (psppire_value_entry_parent_class)->finalize (gobject);
270 psppire_value_entry_new (void)
272 return GTK_WIDGET (g_object_new (PSPPIRE_TYPE_VALUE_ENTRY, NULL));
276 psppire_value_entry_refresh_model (PsppireValueEntry *obj)
279 GtkTreeModel *old_model;
281 if (val_labs_count (obj->val_labs) > 0)
283 const struct val_lab **vls = val_labs_sorted (obj->val_labs);
284 size_t n_vls = val_labs_count (obj->val_labs);
286 GtkListStore *list_store;
289 list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
290 model = GTK_TREE_MODEL (list_store);
291 for (i = 0; i < n_vls; i++)
293 const struct val_lab *vl = vls[i];
296 gtk_list_store_append (list_store, &iter);
297 gtk_list_store_set (list_store, &iter,
298 COL_LABEL, val_lab_get_label (vl),
299 COL_VALUE, val_lab_get_value (vl),
307 old_model = gtk_combo_box_get_model (GTK_COMBO_BOX (obj));
309 if (old_model != model)
311 GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj)));
312 gtk_entry_set_text (entry, "");
315 gtk_combo_box_set_model (GTK_COMBO_BOX (obj), model);
317 g_object_unref (model);
321 psppire_value_entry_set_show_value_label (PsppireValueEntry *obj,
322 gboolean show_value_label)
324 if (obj->show_value_label != show_value_label)
326 obj->show_value_label = show_value_label;
327 g_object_notify (G_OBJECT (obj), "show-value-label");
332 psppire_value_entry_get_show_value_label (const PsppireValueEntry *obj)
334 return obj->show_value_label;
338 psppire_value_entry_set_variable (PsppireValueEntry *obj,
339 const struct variable *var)
343 psppire_value_entry_set_value_labels (obj, var_get_value_labels (var));
344 obj->format = *var_get_print_format (var);
345 psppire_value_entry_set_encoding (obj, var_get_encoding (var));
348 psppire_value_entry_set_value_labels (obj, NULL);
352 psppire_value_entry_set_value_labels (PsppireValueEntry *obj,
353 const struct val_labs *val_labs)
355 if (!val_labs_equal (obj->val_labs, val_labs))
357 obj->cur_value = NULL;
359 val_labs_destroy (obj->val_labs);
360 obj->val_labs = val_labs_clone (val_labs);
362 if (val_labs != NULL)
364 int width = val_labs_get_width (val_labs);
365 if (width != fmt_var_width (&obj->format))
366 obj->format = fmt_default_for_width (width);
369 psppire_value_entry_refresh_model (obj);
371 g_object_notify (G_OBJECT (obj), "value-labels");
375 const struct val_labs *
376 psppire_value_entry_get_value_labels (const PsppireValueEntry *obj)
378 return obj->val_labs;
382 psppire_value_entry_set_format (PsppireValueEntry *obj,
383 const struct fmt_spec *format)
385 if (!fmt_equal (format, &obj->format))
387 obj->cur_value = NULL;
388 obj->format = *format;
391 && val_labs_get_width (obj->val_labs) != fmt_var_width (format))
392 psppire_value_entry_set_value_labels (obj, NULL);
394 g_object_notify (G_OBJECT (obj), "format");
398 const struct fmt_spec *
399 psppire_value_entry_get_format (const PsppireValueEntry *obj)
405 psppire_value_entry_set_encoding (PsppireValueEntry *obj,
406 const gchar *encoding)
408 g_free (obj->encoding);
409 obj->encoding = encoding != NULL ? g_strdup (encoding) : NULL;
411 g_object_notify (G_OBJECT (obj), "encoding");
415 psppire_value_entry_get_encoding (const PsppireValueEntry *obj)
417 return obj->encoding ? obj->encoding : UTF8;
421 psppire_value_entry_set_width (PsppireValueEntry *obj, int width)
423 if (width != fmt_var_width (&obj->format))
425 struct fmt_spec format = fmt_default_for_width (width);
426 psppire_value_entry_set_format (obj, &format);
431 psppire_value_entry_get_width (const PsppireValueEntry *obj)
433 return fmt_var_width (&obj->format);
437 psppire_value_entry_set_value (PsppireValueEntry *obj,
438 const union value *value,
441 GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj)));
444 obj->cur_value = NULL;
449 if (obj->show_value_label)
451 struct val_lab *vl = val_labs_lookup (obj->val_labs, value);
454 gtk_entry_set_text (entry, val_lab_get_label (vl));
455 obj->cur_value = val_lab_get_value (vl);
460 string = value_to_text__ (*value, &obj->format, obj->encoding);
461 gtk_entry_set_text (entry, string);
466 psppire_value_entry_get_value (PsppireValueEntry *obj,
470 GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj)));
473 g_return_val_if_fail (fmt_var_width (&obj->format) == width, FALSE);
477 value_copy (value, obj->cur_value, width);
480 else if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (obj), &iter))
484 gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (obj)), &iter,
487 value_copy (value, v, width);
492 const gchar *new_text;
494 new_text = gtk_entry_get_text (entry);
495 return data_in_msg (ss_cstr (new_text), UTF8,
497 value, width, obj->encoding);