/* PSPPIRE - a graphical user interface for PSPP. Copyright (C) 2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "psppire-value-entry.h" #include "data/data-in.h" #include "data/value-labels.h" #include "data/variable.h" #include "libpspp/cast.h" #include "libpspp/i18n.h" #include "ui/gui/helper.h" #include "ui/gui/psppire-format.h" static void psppire_value_entry_finalize (GObject *); G_DEFINE_TYPE (PsppireValueEntry, psppire_value_entry, GTK_TYPE_COMBO_BOX); enum { COL_LABEL, /* Value label string. */ COL_VALUE, /* union value *. */ N_COLUMNS }; enum { PROP_0, PROP_SHOW_VALUE_LABEL, PROP_VARIABLE, PROP_VALUE_LABELS, PROP_FORMAT, PROP_ENCODING, PROP_WIDTH }; enum {EDIT_DONE, /* Emitted when the entry has changed and is ready to be fetched */ n_SIGNALS}; static guint signals [n_SIGNALS]; static void psppire_value_entry_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (object); switch (prop_id) { case PROP_SHOW_VALUE_LABEL: psppire_value_entry_set_show_value_label (obj, g_value_get_boolean (value)); break; case PROP_VARIABLE: psppire_value_entry_set_variable (obj, g_value_get_pointer (value)); break; case PROP_VALUE_LABELS: psppire_value_entry_set_value_labels (obj, g_value_get_pointer (value)); break; case PROP_FORMAT: { const struct fmt_spec *f = g_value_get_boxed (value); psppire_value_entry_set_format (obj, *f); } break; case PROP_ENCODING: psppire_value_entry_set_encoding (obj, g_value_get_string (value)); break; case PROP_WIDTH: psppire_value_entry_set_width (obj, g_value_get_int (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void psppire_value_entry_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (object); switch (prop_id) { case PROP_SHOW_VALUE_LABEL: g_value_set_boolean (value, psppire_value_entry_get_show_value_label (obj)); break; case PROP_VARIABLE: g_return_if_reached (); case PROP_VALUE_LABELS: g_value_set_pointer (value, obj->val_labs); break; case PROP_FORMAT: g_value_set_boxed (value, &obj->format); break; case PROP_ENCODING: g_value_set_string (value, psppire_value_entry_get_encoding (obj)); break; case PROP_WIDTH: g_value_set_int (value, psppire_value_entry_get_width (obj)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void psppire_value_entry_text_changed (GtkEntryBuffer *buffer, GParamSpec *pspec, PsppireValueEntry *obj) { obj->cur_value = NULL; } static void on_entry_activate (GtkWidget *w) { g_signal_emit (w, signals [EDIT_DONE], 0); } static void on_realize (GtkWidget *w) { GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (w))); GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry); gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (w), COL_LABEL); g_signal_connect (buffer, "notify::text", G_CALLBACK (psppire_value_entry_text_changed), w); g_signal_connect_swapped (entry, "activate", G_CALLBACK (on_entry_activate), w); gtk_widget_set_can_focus (GTK_WIDGET (entry), TRUE); GTK_WIDGET_CLASS (psppire_value_entry_parent_class)->realize (w); } /* The "has-entry" property for the parent class (GTK_COMBO_BOX) is a) Construct-only ; and b) defaults to FALSE. We want it to default to TRUE. So we override it here. */ static GObject* my_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *o = G_OBJECT_CLASS (psppire_value_entry_parent_class)->constructor (type, n_construct_properties, construct_properties); g_object_set (o, "has-entry", TRUE, NULL); return o; } static void psppire_value_entry_class_init (PsppireValueEntryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); gobject_class->finalize = psppire_value_entry_finalize; gobject_class->set_property = psppire_value_entry_set_property; gobject_class->get_property = psppire_value_entry_get_property; gobject_class->constructor = my_constructor; widget_class->realize = on_realize; g_object_class_install_property ( gobject_class, PROP_SHOW_VALUE_LABEL, g_param_spec_boolean ("show-value-label", "Show Value Label", "If true, a value that has a value label is shown " "as the label. If false, all values are shown " "literally.", TRUE, G_PARAM_WRITABLE | G_PARAM_READABLE)); g_object_class_install_property ( gobject_class, PROP_VARIABLE, g_param_spec_pointer ("variable", "Variable", "Set to configure the PsppireValueEntry according " "to the specified variable's value labels, format, " "width, and encoding.", G_PARAM_WRITABLE)); g_object_class_install_property ( gobject_class, PROP_VALUE_LABELS, g_param_spec_pointer ("value-labels", "Value Labels", "The set of value labels from which the user may " "choose and which is used to display the value (if " "value labels are to be displayed)", G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property ( gobject_class, PROP_FORMAT, g_param_spec_boxed ("format", "Format", "The format used to display values (that are not " "displayed as value labels) and to interpret values " "entered.", PSPPIRE_TYPE_FORMAT, G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property ( gobject_class, PROP_ENCODING, g_param_spec_string ("encoding", "Encoding", "The encoding (e.g. \"UTF-8\") for string values. " "For numeric values this setting has no effect.", "UTF-8", G_PARAM_READABLE | G_PARAM_WRITABLE)); g_object_class_install_property ( gobject_class, PROP_WIDTH, g_param_spec_int ("width", "Width", "Width of the value, either 0 for a numeric value or " "a positive integer count of bytes for string values.", 0, MAX_STRING, 0, G_PARAM_READABLE | G_PARAM_WRITABLE)); signals [EDIT_DONE] = g_signal_new ("edit-done", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void psppire_value_entry_init (PsppireValueEntry *obj) { obj->show_value_label = true; obj->val_labs = NULL; obj->format = F_8_0; obj->encoding = NULL; obj->cur_value = NULL; } static void psppire_value_entry_finalize (GObject *gobject) { PsppireValueEntry *obj = PSPPIRE_VALUE_ENTRY (gobject); val_labs_destroy (obj->val_labs); g_free (obj->encoding); G_OBJECT_CLASS (psppire_value_entry_parent_class)->finalize (gobject); } GtkWidget * psppire_value_entry_new (void) { return GTK_WIDGET (g_object_new (PSPPIRE_TYPE_VALUE_ENTRY, NULL)); } static void psppire_value_entry_refresh_model (PsppireValueEntry *obj) { GtkTreeModel *model; GtkTreeModel *old_model; if (val_labs_count (obj->val_labs)> 0) { const struct val_lab **vls = val_labs_sorted (obj->val_labs); size_t n_vls = val_labs_count (obj->val_labs); GtkListStore *list_store; size_t i; list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); model = GTK_TREE_MODEL (list_store); for (i = 0; i < n_vls; i++) { const struct val_lab *vl = vls[i]; GtkTreeIter iter; gtk_list_store_append (list_store, &iter); gtk_list_store_set (list_store, &iter, COL_LABEL, val_lab_get_label (vl), COL_VALUE, val_lab_get_value (vl), -1); } free (vls); } else model = NULL; old_model = gtk_combo_box_get_model (GTK_COMBO_BOX (obj)); if (old_model != model) { GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj))); gtk_entry_set_text (entry, ""); } gtk_combo_box_set_model (GTK_COMBO_BOX (obj), model); if (model != NULL) g_object_unref (model); } void psppire_value_entry_set_show_value_label (PsppireValueEntry *obj, gboolean show_value_label) { if (obj->show_value_label != show_value_label) { obj->show_value_label = show_value_label; g_object_notify (G_OBJECT (obj), "show-value-label"); } } gboolean psppire_value_entry_get_show_value_label (const PsppireValueEntry *obj) { return obj->show_value_label; } void psppire_value_entry_set_variable (PsppireValueEntry *obj, const struct variable *var) { if (var != NULL) { psppire_value_entry_set_value_labels (obj, var_get_value_labels (var)); obj->format = var_get_print_format (var); psppire_value_entry_set_encoding (obj, var_get_encoding (var)); } else psppire_value_entry_set_value_labels (obj, NULL); } void psppire_value_entry_set_value_labels (PsppireValueEntry *obj, const struct val_labs *val_labs) { if (!val_labs_equal (obj->val_labs, val_labs)) { obj->cur_value = NULL; val_labs_destroy (obj->val_labs); obj->val_labs = val_labs_clone (val_labs); if (val_labs != NULL) { int width = val_labs_get_width (val_labs); if (width != fmt_var_width (obj->format)) obj->format = fmt_default_for_width (width); } psppire_value_entry_refresh_model (obj); g_object_notify (G_OBJECT (obj), "value-labels"); } } const struct val_labs * psppire_value_entry_get_value_labels (const PsppireValueEntry *obj) { return obj->val_labs; } void psppire_value_entry_set_format (PsppireValueEntry *obj, struct fmt_spec format) { if (!fmt_equal (format, obj->format)) { obj->cur_value = NULL; obj->format = format; if (obj->val_labs && val_labs_get_width (obj->val_labs) != fmt_var_width (format)) psppire_value_entry_set_value_labels (obj, NULL); g_object_notify (G_OBJECT (obj), "format"); } } struct fmt_spec psppire_value_entry_get_format (const PsppireValueEntry *obj) { return obj->format; } void psppire_value_entry_set_encoding (PsppireValueEntry *obj, const gchar *encoding) { g_free (obj->encoding); obj->encoding = encoding != NULL ? g_strdup (encoding) : NULL; g_object_notify (G_OBJECT (obj), "encoding"); } const gchar * psppire_value_entry_get_encoding (const PsppireValueEntry *obj) { return obj->encoding ? obj->encoding : UTF8; } void psppire_value_entry_set_width (PsppireValueEntry *obj, int width) { if (width != fmt_var_width (obj->format)) { struct fmt_spec format = fmt_default_for_width (width); psppire_value_entry_set_format (obj, format); } } int psppire_value_entry_get_width (const PsppireValueEntry *obj) { return fmt_var_width (obj->format); } void psppire_value_entry_set_value (PsppireValueEntry *obj, const union value *value, int width) { GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj))); gchar *string; obj->cur_value = NULL; if (value == NULL) return; if (obj->show_value_label) { struct val_lab *vl = val_labs_lookup (obj->val_labs, value); if (vl != NULL) { gtk_entry_set_text (entry, val_lab_get_label (vl)); obj->cur_value = val_lab_get_value (vl); return; } } string = value_to_text__ (*value, obj->format, obj->encoding); gtk_entry_set_text (entry, string); g_free (string); } gboolean psppire_value_entry_get_value (PsppireValueEntry *obj, union value *value, int width) { GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj))); GtkTreeIter iter; g_return_val_if_fail (fmt_var_width (obj->format) == width, FALSE); if (obj->cur_value) { value_copy (value, obj->cur_value, width); return TRUE; } else if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (obj), &iter)) { union value *v; gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (obj)), &iter, COL_VALUE, &v, -1); value_copy (value, v, width); return TRUE; } else { const gchar *new_text; new_text = gtk_entry_get_text (entry); return data_in_msg (ss_cstr (new_text), UTF8, obj->format.type, settings_get_fmt_settings (), value, width, obj->encoding); } } AltStyle によって変換されたページ (->オリジナル) / アドレス: モード: デフォルト 音声ブラウザ ルビ付き 配色反転 文字拡大 モバイル
AltStyle によって変換されたページ (->オリジナル) / アドレス: モード: デフォルト 音声ブラウザ ルビ付き 配色反転 文字拡大 モバイル