pspp-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 3/4] gui: New widget PsppireValueEntry for editing a "union value


From: Ben Pfaff
Subject: [PATCH 3/4] gui: New widget PsppireValueEntry for editing a "union value".
Date: Fri, 20 Apr 2012 22:11:54 -0700

This is intended to be a convenenient way to allow the user to
view and edit a "union value" that includes the ability to see
and select values by value label.
---
 src/ui/gui/automake.mk           |    2 +
 src/ui/gui/psppire-value-entry.c |  455 ++++++++++++++++++++++++++++++++++++++
 src/ui/gui/psppire-value-entry.h |  104 +++++++++
 3 files changed, 561 insertions(+), 0 deletions(-)
 create mode 100644 src/ui/gui/psppire-value-entry.c
 create mode 100644 src/ui/gui/psppire-value-entry.h

diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk
index ac61a29..3016723 100644
--- a/src/ui/gui/automake.mk
+++ b/src/ui/gui/automake.mk
@@ -255,6 +255,8 @@ src_ui_gui_psppire_SOURCES = \
        src/ui/gui/psppire-syntax-window.h \
        src/ui/gui/psppire-val-chooser.c \
        src/ui/gui/psppire-val-chooser.h \
+       src/ui/gui/psppire-value-entry.c \
+       src/ui/gui/psppire-value-entry.h \
        src/ui/gui/psppire-var-ptr.c \
        src/ui/gui/psppire-var-ptr.h \
        src/ui/gui/psppire-var-sheet.c \
diff --git a/src/ui/gui/psppire-value-entry.c b/src/ui/gui/psppire-value-entry.c
new file mode 100644
index 0000000..675df83
--- /dev/null
+++ b/src/ui/gui/psppire-value-entry.c
@@ -0,0 +1,455 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#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_ENTRY);
+
+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
+  };
+
+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:
+      psppire_value_entry_set_format (obj, g_value_get_boxed (value));
+      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_class_init (PsppireValueEntryClass *class)
+{
+  GObjectClass *gobject_class;
+  gobject_class = G_OBJECT_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;
+
+  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));
+}
+
+static void
+psppire_value_entry_text_changed (GtkEntryBuffer *buffer,
+                                  GParamSpec *pspec,
+                                  PsppireValueEntry *obj)
+{
+  obj->cur_value = NULL;
+}
+
+static void
+psppire_value_entry_init (PsppireValueEntry *obj)
+{
+  GtkEntry *entry = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (obj)));
+  GtkEntryBuffer *buffer = gtk_entry_get_buffer (entry);
+
+  obj->show_value_label = true;
+  obj->val_labs = NULL;
+  obj->format = F_8_0;
+  obj->encoding = NULL;
+  obj->cur_value = NULL;
+
+  g_signal_connect (buffer, "notify::text",
+                    G_CALLBACK (psppire_value_entry_text_changed), obj);
+}
+
+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)
+{
+  GtkWidget *entry = gtk_bin_get_child (GTK_BIN (obj));
+  GtkTreeModel *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;
+
+  gtk_combo_box_set_model (GTK_COMBO_BOX (obj), model);
+  gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (obj), COL_LABEL);
+  gtk_widget_set_sensitive (entry, model != NULL);
+}
+
+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 != NULL
+      ? obj->val_labs == NULL || !val_labs_equal (obj->val_labs, val_labs)
+      : obj->val_labs != NULL)
+    {
+      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,
+                                const 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");
+    }
+}
+
+const 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 (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,
+                          value, width, obj->encoding);
+    }
+}
diff --git a/src/ui/gui/psppire-value-entry.h b/src/ui/gui/psppire-value-entry.h
new file mode 100644
index 0000000..42821f3
--- /dev/null
+++ b/src/ui/gui/psppire-value-entry.h
@@ -0,0 +1,104 @@
+/* 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef PSPPIRE_VALUE_ENTRY_H
+#define PSPPIRE_VALUE_ENTRY_H 1
+
+#include <gtk/gtk.h>
+#include "data/format.h"
+
+/* PsppireValueEntry is a subclass of GtkComboBoxEntry that is specialized for
+   displaying and entering "union value"s.  Its main advantage over a plain
+   GtkEntry is that, when value labels are supplied, it (optionally) displays
+   the value label instead of the value.  It also allows the user to choose a
+   new value by label from the drop-down list.
+
+   The easiest way to use a PsppireValueEntry is to hand it a particular
+   variable whose values are to be displayed, using
+   psppire_value_entry_set_variable().  If you do that, you don't need any of
+   the other functions to set value labels, format, encoding, width, etc.,
+   because all of those are determined from the variable.  The other functions
+   are useful if no variable is available. */
+
+G_BEGIN_DECLS
+
+union value;
+struct fmt_spec;
+struct val_labs;
+struct variable;
+
+#define PSPPIRE_TYPE_VALUE_ENTRY             (psppire_value_entry_get_type())
+#define PSPPIRE_VALUE_ENTRY(obj)             (G_TYPE_CHECK_INSTANCE_CAST 
((obj),PSPPIRE_TYPE_VALUE_ENTRY,PsppireValueEntry))
+#define PSPPIRE_VALUE_ENTRY_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST 
((class),PSPPIRE_TYPE_VALUE_ENTRY,PsppireValueEntryClass))
+#define PSPPIRE_IS_VALUE_ENTRY(obj)          (G_TYPE_CHECK_INSTANCE_TYPE 
((obj),PSPPIRE_TYPE_VALUE_ENTRY))
+#define PSPPIRE_IS_VALUE_ENTRY_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE 
((class),PSPPIRE_TYPE_VALUE_ENTRY))
+#define PSPPIRE_VALUE_ENTRY_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS 
((obj),PSPPIRE_TYPE_VALUE_ENTRY,PsppireValueEntryClass))
+
+typedef struct _PsppireValueEntry      PsppireValueEntry;
+typedef struct _PsppireValueEntryClass PsppireValueEntryClass;
+
+struct _PsppireValueEntry {
+  GtkComboBoxEntry parent;
+
+  gboolean show_value_label;
+
+  struct val_labs *val_labs;
+  struct fmt_spec format;
+  gchar *encoding;
+
+  const union value *cur_value;
+};
+
+struct _PsppireValueEntryClass {
+  GtkComboBoxEntryClass parent_class;
+};
+
+GType psppire_value_entry_get_type (void) G_GNUC_CONST;
+GtkWidget *psppire_value_entry_new (void);
+
+void psppire_value_entry_set_show_value_label (PsppireValueEntry *,
+                                               gboolean show_value_label);
+gboolean psppire_value_entry_get_show_value_label (const PsppireValueEntry *);
+
+void psppire_value_entry_set_variable (PsppireValueEntry *,
+                                       const struct variable *);
+
+void psppire_value_entry_set_value_labels (PsppireValueEntry *,
+                                           const struct val_labs *);
+const struct val_labs *
+psppire_value_entry_get_value_labels (const PsppireValueEntry *);
+
+void psppire_value_entry_set_format (PsppireValueEntry *,
+                                     const struct fmt_spec *);
+const struct fmt_spec *
+psppire_value_entry_get_format (const PsppireValueEntry *);
+
+void psppire_value_entry_set_encoding (PsppireValueEntry *, const gchar *);
+const gchar *psppire_value_entry_get_encoding (const PsppireValueEntry *);
+
+void psppire_value_entry_set_width (PsppireValueEntry *, int width);
+int psppire_value_entry_get_width (const PsppireValueEntry *);
+
+void psppire_value_entry_set_value (PsppireValueEntry *,
+                                    const union value *,
+                                    int width);
+gboolean psppire_value_entry_get_value (PsppireValueEntry *,
+                                        union value *,
+                                        int width);
+
+G_END_DECLS
+
+#endif /* PSPPIRE_VALUE_ENTRY_H */
-- 
1.7.2.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]