From: John Darrington Date: Fri, 1 Jul 2011 16:39:10 +0000 (+0200) Subject: New widget PsppireValChooser. X-Git-Tag: v0.7.9~236 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4233ff9b1569035a8b748b3695cb865e6412e5b2;p=pspp-builds.git New widget PsppireValChooser. This widget provides a user interface allowing the user to input the a value, or range of values. This was previously done "by hand" in the recode dialog, but was awkward to maintain, and clumsy. Upcoming dialogs will need something very similar. So now seemed like a good time to encapsulate it. --- diff --git a/src/ui/gui/automake.mk b/src/ui/gui/automake.mk index 31253dbd..5eccb206 100644 --- a/src/ui/gui/automake.mk +++ b/src/ui/gui/automake.mk @@ -198,6 +198,8 @@ src_ui_gui_psppire_SOURCES = \ src/ui/gui/psppire-select-dest.h \ src/ui/gui/psppire-syntax-window.c \ 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-var-ptr.c \ src/ui/gui/psppire-var-ptr.h \ src/ui/gui/psppire-var-sheet.c \ diff --git a/src/ui/gui/psppire-val-chooser.c b/src/ui/gui/psppire-val-chooser.c new file mode 100644 index 00000000..368eea32 --- /dev/null +++ b/src/ui/gui/psppire-val-chooser.c @@ -0,0 +1,676 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2011 Free Software Foundation + + 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 +#include "psppire-val-chooser.h" + +#include "libpspp/str.h" + + +#include "ui/syntax-gen.h" + +#include +#define _(msgid) gettext (msgid) +#define N_(msgid) msgid + +static void psppire_val_chooser_base_finalize (PsppireValChooserClass *, gpointer); +static void psppire_val_chooser_base_init (PsppireValChooserClass *class); +static void psppire_val_chooser_class_init (PsppireValChooserClass *class); +static void psppire_val_chooser_init (PsppireValChooser *vc); + +static void psppire_val_chooser_realize (GtkWidget *w); + + + +GType +psppire_val_chooser_get_type (void) +{ + static GType psppire_val_chooser_type = 0; + + if (!psppire_val_chooser_type) + { + static const GTypeInfo psppire_val_chooser_info = + { + sizeof (PsppireValChooserClass), + (GBaseInitFunc) psppire_val_chooser_base_init, + (GBaseFinalizeFunc) psppire_val_chooser_base_finalize, + (GClassInitFunc)psppire_val_chooser_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (PsppireValChooser), + 0, + (GInstanceInitFunc) psppire_val_chooser_init, + }; + + psppire_val_chooser_type = + g_type_register_static (GTK_TYPE_FRAME, "PsppireValChooser", + &psppire_val_chooser_info, 0); + } + + return psppire_val_chooser_type; +} + + +static void +psppire_val_chooser_finalize (GObject *object) +{ + +} + +/* Properties */ +enum +{ + PROP_0, + PROP_IS_STRING, +}; + + +static void +psppire_val_chooser_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + PsppireValChooser *vr = PSPPIRE_VAL_CHOOSER (object); + + switch (prop_id) + { + case PROP_IS_STRING: + vr->input_var_is_string = g_value_get_boolean (value); + + gtk_widget_set_sensitive (GTK_WIDGET (vr->rw[1].rb), !vr->input_var_is_string); + gtk_widget_set_sensitive (GTK_WIDGET (vr->rw[2].rb), !vr->input_var_is_string); + gtk_widget_set_sensitive (GTK_WIDGET (vr->rw[3].rb), !vr->input_var_is_string); + gtk_widget_set_sensitive (GTK_WIDGET (vr->rw[4].rb), !vr->input_var_is_string); + gtk_widget_set_sensitive (GTK_WIDGET (vr->rw[5].rb), !vr->input_var_is_string); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + }; +} + + +static void +psppire_val_chooser_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + PsppireValChooser *vr = PSPPIRE_VAL_CHOOSER (object); + + switch (prop_id) + { + case PROP_IS_STRING: + g_value_set_boolean (value, vr->input_var_is_string); + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + }; +} + + +static GObjectClass * parent_class = NULL; + +static void +psppire_val_chooser_class_init (PsppireValChooserClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + GParamSpec *is_string_spec = + g_param_spec_boolean ("is-string", + "String Value", + "Should the value range be a string value", + FALSE, + G_PARAM_READWRITE); + + parent_class = g_type_class_peek_parent (class); + + object_class->set_property = psppire_val_chooser_set_property; + object_class->get_property = psppire_val_chooser_get_property; + + widget_class->realize = psppire_val_chooser_realize; + + g_object_class_install_property (object_class, + PROP_IS_STRING, + is_string_spec); +} + + +static void +psppire_val_chooser_base_init (PsppireValChooserClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = psppire_val_chooser_finalize; +} + + + +static void +psppire_val_chooser_base_finalize (PsppireValChooserClass *class, + gpointer class_data) +{ + +} + + +/* Set the focus of B to follow the sensitivity of A */ +static void +focus_follows_sensitivity (GtkWidget *a, GParamSpec *pspec, GtkWidget *b) +{ + gboolean sens = gtk_widget_get_sensitive (a); + + g_object_set (b, "has-focus", sens, NULL); +} + + +struct layout; +typedef GtkWidget *filler_f (struct layout *, struct range_widgets *); +typedef void set_f (PsppireValChooser *, struct old_value *, const struct range_widgets *); + +struct layout +{ + const gchar *label; + filler_f *fill; + set_f *set; +}; + + + +static void simple_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *rw) +{ + const gchar *text = gtk_entry_get_text (rw->e1); + + if ( vr->input_var_is_string) + { + ov->type = OV_STRING; + ov->v.s = g_strdup (text); + } + else + { + ov->type = OV_NUMERIC; + ov->v.v = g_strtod (text, 0); + } +} + +static void lo_up_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *rw) +{ + const gchar *text = gtk_entry_get_text (rw->e1); + + ov->type = OV_LOW_UP; + ov->v.range[1] = g_strtod (text, 0); +} + + +static void hi_down_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *rw) +{ + const gchar *text = gtk_entry_get_text (rw->e1); + + ov->type = OV_HIGH_DOWN; + ov->v.range[0] = g_strtod (text, 0); +} + +static void missing_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *l) +{ + ov->type = OV_MISSING; +} + + +static void sysmis_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *l) +{ + ov->type = OV_SYSMIS; +} + +static void else_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *l) +{ + ov->type = OV_ELSE; +} + + +static void range_set (PsppireValChooser *vr, struct old_value *ov, const struct range_widgets *rw) +{ + const gchar *text = gtk_entry_get_text (rw->e1); + + ov->type = OV_RANGE; + ov->v.range[0] = g_strtod (text, 0); + + text = gtk_entry_get_text (rw->e2); + ov->v.range[1] = g_strtod (text, 0); +} + +static GtkWidget * range_entry (struct layout *l, struct range_widgets *rw) +{ + GtkWidget *vbox = gtk_vbox_new (3, FALSE); + GtkWidget *entrylo = gtk_entry_new (); + GtkWidget *label = gtk_label_new (_("through")); + GtkWidget *entryhi = gtk_entry_new (); + + rw->e1 = GTK_ENTRY (entrylo); + rw->e2 = GTK_ENTRY (entryhi); + + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + g_signal_connect (vbox, "notify::sensitive", G_CALLBACK (focus_follows_sensitivity), entrylo); + + gtk_box_pack_start (GTK_BOX (vbox), entrylo, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (vbox), entryhi, TRUE, TRUE, 0); + return vbox; +} + +static GtkWidget * simple_entry (struct layout *l, struct range_widgets *rw) +{ + GtkWidget *entry = gtk_entry_new (); + + rw->e1 = GTK_ENTRY (entry); + + g_signal_connect (entry, "notify::sensitive", G_CALLBACK (focus_follows_sensitivity), entry); + return entry; +} + + +static struct layout range_opt[n_VAL_CHOOSER_BUTTONS]= + { + {N_("Value:"), simple_entry, simple_set }, + {N_("System Missing"), NULL, sysmis_set }, + {N_("System or User Missing"), NULL, missing_set}, + {N_("Range:"), range_entry, range_set }, + {N_("Range, LOWEST thru value"), simple_entry, lo_up_set }, + {N_("Range, value thru HIGHEST"), simple_entry, hi_down_set}, + {N_("All other values"), NULL, else_set } + }; + +static void +set_sensitivity_from_toggle (GtkToggleButton *togglebutton, GtkWidget *w) +{ + gboolean active = gtk_toggle_button_get_active (togglebutton); + + gtk_widget_set_sensitive (w, active); +} + +static void +psppire_val_chooser_init (PsppireValChooser *vr) +{ + gint i; + GtkWidget *aln = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); + GtkWidget *table = gtk_table_new (11, 2, FALSE); + GSList *group = NULL; + gint row = 0; + + gtk_alignment_set_padding (GTK_ALIGNMENT (aln), 0, 0, 5, 5); + + vr->input_var_is_string = FALSE; + + for (i = 0; i < n_VAL_CHOOSER_BUTTONS; ++i) + { + struct layout *l = &range_opt[i]; + GtkWidget *label = gtk_label_new (gettext (l->label)); + vr->rw[i].rb = GTK_TOGGLE_BUTTON (gtk_radio_button_new (group)); + + gtk_widget_set_sensitive (label, FALSE); + g_signal_connect (vr->rw[i].rb, "toggled", G_CALLBACK (set_sensitivity_from_toggle), label); + + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); + + group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (vr->rw[i].rb)); + + gtk_table_attach_defaults (GTK_TABLE (table), GTK_WIDGET (vr->rw[i].rb), 0, 1, + row, row + 1); + + + gtk_table_attach_defaults (GTK_TABLE (table), label, 1, 2, + row, row + 1); + ++row; + + if (l->fill) + { + GtkWidget *fill = l->fill (l, &vr->rw[i]); + + gtk_widget_set_sensitive (fill, FALSE); + + gtk_table_attach_defaults (GTK_TABLE (table), fill, 1, 2, + row, row + 1); + ++row; + + g_signal_connect (vr->rw[i].rb, "toggled", G_CALLBACK (set_sensitivity_from_toggle), fill); + } + } + + gtk_frame_set_shadow_type (GTK_FRAME (vr), GTK_SHADOW_ETCHED_IN); + + gtk_container_add (GTK_CONTAINER (aln), table); + gtk_container_add (GTK_CONTAINER (vr), aln); + + gtk_widget_show_all (aln); +} + + +GtkWidget* +psppire_val_chooser_new (void) +{ + return GTK_WIDGET (g_object_new (psppire_val_chooser_get_type (), NULL)); +} + + + +static void +psppire_val_chooser_realize (GtkWidget *w) +{ + PsppireValChooser *vr = PSPPIRE_VAL_CHOOSER (w); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(vr->rw[0].rb), TRUE); + gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON (vr->rw[0].rb)); + + /* Chain up to the parent class */ + GTK_WIDGET_CLASS (parent_class)->realize (w); +} + + + + +/* A boxed type representing a value, or a range of values which may + potentially be replaced by something */ + + +static struct old_value * +old_value_copy (struct old_value *ov) +{ + struct old_value *copy = g_memdup (ov, sizeof (*copy)); + + if ( ov->type == OV_STRING ) + copy->v.s = g_strdup (ov->v.s); + + return copy; +} + + +static void +old_value_free (struct old_value *ov) +{ + if (ov->type == OV_STRING) + g_free (ov->v.s); + g_free (ov); +} + +static void +old_value_to_string (const GValue *src, GValue *dest) +{ + const struct old_value *ov = g_value_get_boxed (src); + + switch (ov->type) + { + case OV_NUMERIC: + { + gchar *text = g_strdup_printf ("%g", ov->v.v); + g_value_set_string (dest, text); + g_free (text); + } + break; + case OV_STRING: + g_value_set_string (dest, ov->v.s); + break; + case OV_MISSING: + g_value_set_string (dest, "MISSING"); + break; + case OV_SYSMIS: + g_value_set_string (dest, "SYSMIS"); + break; + case OV_ELSE: + g_value_set_string (dest, "ELSE"); + break; + case OV_RANGE: + { + gchar *text; + char en_dash[6] = {0,0,0,0,0,0}; + + g_unichar_to_utf8 (0x2013, en_dash); + + text = g_strdup_printf ("%g %s %g", + ov->v.range[0], + en_dash, + ov->v.range[1]); + g_value_set_string (dest, text); + g_free (text); + } + break; + case OV_LOW_UP: + { + gchar *text; + char en_dash[6] = {0,0,0,0,0,0}; + + g_unichar_to_utf8 (0x2013, en_dash); + + text = g_strdup_printf ("LOWEST %s %g", + en_dash, + ov->v.range[1]); + + g_value_set_string (dest, text); + g_free (text); + } + break; + case OV_HIGH_DOWN: + { + gchar *text; + char en_dash[6] = {0,0,0,0,0,0}; + + g_unichar_to_utf8 (0x2013, en_dash); + + text = g_strdup_printf ("%g %s HIGHEST", + ov->v.range[0], + en_dash); + + g_value_set_string (dest, text); + g_free (text); + } + break; + default: + g_warning ("Invalid type in old recode value"); + g_value_set_string (dest, "???"); + break; + }; +} + +GType +old_value_get_type (void) +{ + static GType t = 0; + + if (t == 0 ) + { + t = g_boxed_type_register_static ("psppire-recode-old-values", + (GBoxedCopyFunc) old_value_copy, + (GBoxedFreeFunc) old_value_free); + + g_value_register_transform_func (t, G_TYPE_STRING, + old_value_to_string); + } + + return t; +} + + + +/* Generate a syntax fragment for NV and append it to STR */ +void +old_value_append_syntax (GString *str, const struct old_value *ov) +{ + switch (ov->type) + { + case OV_NUMERIC: + g_string_append_printf (str, "%g", ov->v.v); + break; + case OV_STRING: + { + struct string ds = DS_EMPTY_INITIALIZER; + syntax_gen_string (&ds, ss_cstr (ov->v.s)); + g_string_append (str, ds_cstr (&ds)); + ds_destroy (&ds); + } + break; + case OV_MISSING: + g_string_append (str, "MISSING"); + break; + case OV_SYSMIS: + g_string_append (str, "SYSMIS"); + break; + case OV_ELSE: + g_string_append (str, "ELSE"); + break; + case OV_RANGE: + g_string_append_printf (str, "%g THRU %g", + ov->v.range[0], + ov->v.range[1]); + break; + case OV_LOW_UP: + g_string_append_printf (str, "LOWEST THRU %g", + ov->v.range[1]); + break; + case OV_HIGH_DOWN: + g_string_append_printf (str, "%g THRU HIGHEST", + ov->v.range[0]); + break; + default: + g_warning ("Invalid type in old recode value"); + g_string_append (str, "???"); + break; + }; +} + + + +/* Set OV according to the current state of VR */ +void +psppire_val_chooser_get_status (PsppireValChooser *vr, struct old_value *ov) +{ + int i; + + for (i = 0; i < n_VAL_CHOOSER_BUTTONS; ++i) + { + if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (vr->rw[i].rb))) + { + break; + } + } + + range_opt[i].set (vr, ov, &vr->rw[i]); +} + +/* This might need to be changed to something less naive. + In particular, what happends with dates, etc? + */ +static gchar * +num_to_string (gdouble x) +{ + return g_strdup_printf ("%g", x); +} + + +/* Set VR according to the value of OV */ +void +psppire_val_chooser_set_status (PsppireValChooser *vr, const struct old_value *ov) +{ + gint i; + if ( !ov ) + return; + + for (i = 0; i < n_VAL_CHOOSER_BUTTONS; ++i) + { + if (vr->rw[i].e1) + gtk_entry_set_text (vr->rw[i].e1, ""); + + if (vr->rw[i].e2) + gtk_entry_set_text (vr->rw[i].e2, ""); + } + + switch (ov->type) + { + case OV_STRING: + gtk_toggle_button_set_active (vr->rw[0].rb, TRUE); + gtk_entry_set_text (vr->rw[0].e1, ov->v.s); + break; + + case OV_NUMERIC: + { + gchar *str; + gtk_toggle_button_set_active (vr->rw[0].rb, TRUE); + + str = num_to_string (ov->v.v); + + gtk_entry_set_text (vr->rw[0].e1, str); + g_free (str); + } + break; + + case OV_SYSMIS: + gtk_toggle_button_set_active (vr->rw[1].rb, TRUE); + break; + + case OV_MISSING: + gtk_toggle_button_set_active (vr->rw[2].rb, TRUE); + break; + + case OV_RANGE: + { + gchar *str = num_to_string (ov->v.range[0]); + gtk_toggle_button_set_active (vr->rw[3].rb, TRUE); + gtk_entry_set_text (vr->rw[3].e1, str); + + g_free (str); + + str = num_to_string (ov->v.range[1]); + gtk_entry_set_text (vr->rw[3].e2, str); + g_free (str); + } + break; + + case OV_LOW_UP: + { + gchar *str = num_to_string (ov->v.range[1]); + + gtk_toggle_button_set_active (vr->rw[4].rb, TRUE); + + gtk_entry_set_text (vr->rw[4].e1, str); + + g_free (str); + } + break; + + + case OV_HIGH_DOWN: + { + gchar *str = num_to_string (ov->v.range[0]); + + gtk_toggle_button_set_active (vr->rw[5].rb, TRUE); + + gtk_entry_set_text (vr->rw[5].e1, str); + + g_free (str); + } + break; + + case OV_ELSE: + gtk_toggle_button_set_active (vr->rw[6].rb, TRUE); + break; + + default: + g_warning ("Unknown old value type"); + break; + }; +} diff --git a/src/ui/gui/psppire-val-chooser.h b/src/ui/gui/psppire-val-chooser.h new file mode 100644 index 00000000..6ef546ee --- /dev/null +++ b/src/ui/gui/psppire-val-chooser.h @@ -0,0 +1,104 @@ +/* PSPPIRE - a graphical user interface for PSPP. + Copyright (C) 2011 Free Software Foundation + + 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 . */ + + +#ifndef __PSPPIRE_VAL_CHOOSER_H__ +#define __PSPPIRE_VAL_CHOOSER_H__ + + +#include +#include +#include + + +G_BEGIN_DECLS + +#define PSPPIRE_VAL_CHOOSER_TYPE (psppire_val_chooser_get_type ()) +#define PSPPIRE_VAL_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PSPPIRE_VAL_CHOOSER_TYPE, PsppireValChooser)) +#define PSPPIRE_VAL_CHOOSER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ + PSPPIRE_VAL_CHOOSER_TYPE, PsppireValChooserClass)) +#define PSPPIRE_IS_VAL_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + PSPPIRE_VAL_CHOOSER_TYPE)) +#define PSPPIRE_IS_VAL_CHOOSER_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ + PSPPIRE_VAL_CHOOSER_TYPE)) + + +typedef struct _PsppireValChooser PsppireValChooser; +typedef struct _PsppireValChooserClass PsppireValChooserClass; + +#define n_VAL_CHOOSER_BUTTONS 7 + +struct range_widgets +{ + GtkToggleButton *rb; + GtkEntry *e1; + GtkEntry *e2; +}; + +struct _PsppireValChooser +{ + GtkFrame parent; + + struct range_widgets rw [n_VAL_CHOOSER_BUTTONS]; + gboolean input_var_is_string; +}; + +struct _PsppireValChooserClass +{ + GtkTreeViewClass parent_class; + +}; + +GType psppire_val_chooser_get_type (void); + + +G_END_DECLS + + + + +enum old_value_type + { + OV_NUMERIC, + OV_STRING, + OV_SYSMIS, + OV_MISSING, + OV_RANGE, + OV_LOW_UP, + OV_HIGH_DOWN, + OV_ELSE + }; + +struct old_value + { + enum old_value_type type; + union { + double v; + gchar *s; + double range[2]; + } v; + }; + +GType old_value_get_type (void); + +void old_value_append_syntax (GString *str, const struct old_value *ov); + +void psppire_val_chooser_get_status (PsppireValChooser *vr, struct old_value *ov); +void psppire_val_chooser_set_status (PsppireValChooser *vr, const struct old_value *ov); + + + +#endif /* __PSPPIRE_VAL_CHOOSER_H__ */ diff --git a/src/ui/gui/recode-dialog.c b/src/ui/gui/recode-dialog.c index 5d97c156..d92517c7 100644 --- a/src/ui/gui/recode-dialog.c +++ b/src/ui/gui/recode-dialog.c @@ -38,6 +38,8 @@ #include #include +#include "psppire-val-chooser.h" + #include #include "psppire-acr.h" @@ -143,151 +145,6 @@ new_value_get_type (void) } - - - -/* A boxed type representing a value, or a range of values which may - potentially be replaced by something */ - -enum old_value_type - { - OV_NUMERIC, - OV_STRING, - OV_SYSMIS, - OV_MISSING, - OV_RANGE, - OV_LOW_UP, - OV_HIGH_DOWN, - OV_ELSE - }; - -struct old_value - { - enum old_value_type type; - union { - double v; - gchar *s; - double range[2]; - } v; - }; - - -static struct old_value * -old_value_copy (struct old_value *ov) -{ - struct old_value *copy = g_memdup (ov, sizeof (*copy)); - - if ( ov->type == OV_STRING ) - copy->v.s = g_strdup (ov->v.s); - - return copy; -} - - -static void -old_value_free (struct old_value *ov) -{ - if (ov->type == OV_STRING) - g_free (ov->v.s); - g_free (ov); -} - -static void -old_value_to_string (const GValue *src, GValue *dest) -{ - const struct old_value *ov = g_value_get_boxed (src); - - switch (ov->type) - { - case OV_NUMERIC: - { - gchar *text = g_strdup_printf ("%g", ov->v.v); - g_value_set_string (dest, text); - g_free (text); - } - break; - case OV_STRING: - g_value_set_string (dest, ov->v.s); - break; - case OV_MISSING: - g_value_set_string (dest, "MISSING"); - break; - case OV_SYSMIS: - g_value_set_string (dest, "SYSMIS"); - break; - case OV_ELSE: - g_value_set_string (dest, "ELSE"); - break; - case OV_RANGE: - { - gchar *text; - char en_dash[6] = {0,0,0,0,0,0}; - - g_unichar_to_utf8 (0x2013, en_dash); - - text = g_strdup_printf ("%g %s %g", - ov->v.range[0], - en_dash, - ov->v.range[1]); - g_value_set_string (dest, text); - g_free (text); - } - break; - case OV_LOW_UP: - { - gchar *text; - char en_dash[6] = {0,0,0,0,0,0}; - - g_unichar_to_utf8 (0x2013, en_dash); - - text = g_strdup_printf ("LOWEST %s %g", - en_dash, - ov->v.range[1]); - - g_value_set_string (dest, text); - g_free (text); - } - break; - case OV_HIGH_DOWN: - { - gchar *text; - char en_dash[6] = {0,0,0,0,0,0}; - - g_unichar_to_utf8 (0x2013, en_dash); - - text = g_strdup_printf ("%g %s HIGHEST", - ov->v.range[0], - en_dash); - - g_value_set_string (dest, text); - g_free (text); - } - break; - default: - g_warning ("Invalid type in old recode value"); - g_value_set_string (dest, "???"); - break; - }; -} - -static GType -old_value_get_type (void) -{ - static GType t = 0; - - if (t == 0 ) - { - t = g_boxed_type_register_static ("psppire-recode-old-values", - (GBoxedCopyFunc) old_value_copy, - (GBoxedFreeFunc) old_value_free); - - g_value_register_transform_func (t, G_TYPE_STRING, - old_value_to_string); - } - - return t; -} - enum @@ -295,13 +152,6 @@ enum BUTTON_NEW_VALUE, BUTTON_NEW_COPY, BUTTON_NEW_SYSMIS, - BUTTON_OLD_VALUE, - BUTTON_OLD_SYSMIS, - BUTTON_OLD_MISSING, - BUTTON_OLD_RANGE, - BUTTON_OLD_LOW_UP, - BUTTON_OLD_HIGH_DOWN, - BUTTON_OLD_ELSE, n_BUTTONS }; @@ -320,13 +170,9 @@ struct recode_dialog GtkWidget *convert_button; GtkWidget *new_copy_label; - GtkWidget *ov_value_entry; GtkWidget *new_value_entry; - GtkWidget *ov_range_lower_entry; - GtkWidget *ov_range_upper_entry; - GtkWidget *ov_low_up_entry; - GtkWidget *ov_high_down_entry; + GtkWidget *old_value_chooser; GtkListStore *value_map; @@ -416,11 +262,6 @@ dialog_state_valid (gpointer data) static void on_old_new_show (struct recode_dialog *rd) { - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_OLD_VALUE]), TRUE); - - g_signal_emit_by_name (rd->toggle[BUTTON_OLD_VALUE], "toggled"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rd->toggle[BUTTON_NEW_VALUE]), TRUE); @@ -545,101 +386,7 @@ on_acr_selection_change (GtkTreeSelection *selection, gpointer data) g_value_unset (&nv_value); } - if ( ov ) - { - switch (ov->type) - { - case OV_STRING: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_VALUE]), TRUE); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_value_entry), ov->v.s); - break; - - case OV_NUMERIC: - { - gchar *str; - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_VALUE]), TRUE); - - str = num_to_string (ov->v.v); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_value_entry), str); - - g_free (str); - } - break; - - case OV_SYSMIS: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_SYSMIS]), TRUE); - break; - - case OV_MISSING: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_MISSING]), TRUE); - break; - - case OV_RANGE: - { - gchar *str; - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_RANGE]), TRUE); - - str = num_to_string (ov->v.range[0]); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_range_lower_entry), str); - - g_free (str); - - - str = num_to_string (ov->v.range[1]); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_range_upper_entry), str); - - g_free (str); - } - break; - - case OV_LOW_UP: - { - gchar *str = num_to_string (ov->v.range[1]); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_LOW_UP]), TRUE); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_low_up_entry), str); - - g_free (str); - } - break; - - case OV_HIGH_DOWN: - { - gchar *str = num_to_string (ov->v.range[0]); - - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_HIGH_DOWN]), TRUE); - - gtk_entry_set_text (GTK_ENTRY (rd->ov_high_down_entry), str); - - g_free (str); - } - break; - - case OV_ELSE: - gtk_toggle_button_set_active - (GTK_TOGGLE_BUTTON (rd->toggle [BUTTON_OLD_ELSE]), TRUE); - break; - - default: - g_warning ("Unknown old value type"); - break; - }; - g_value_unset (&ov_value); - } + psppire_val_chooser_set_status (PSPPIRE_VAL_CHOOSER (rd->old_value_chooser), ov); } /* Name-Label pair */ @@ -929,10 +676,6 @@ recode_dialog (PsppireDataWindow *de, gboolean diff) g_signal_connect (rd.change_button, "clicked", G_CALLBACK (on_change_clicked), &rd); -#if 0 - g_signal_connect (model, "row-inserted", - G_CALLBACK (select_something), &rd); -#endif } psppire_selector_set_allow (PSPPIRE_SELECTOR (selector), homogeneous_types); @@ -944,24 +687,14 @@ recode_dialog (PsppireDataWindow *de, gboolean diff) rd.convert_button = get_widget_assert (builder, "checkbutton2"); - rd.ov_range_lower_entry = get_widget_assert (builder, "entry5"); - rd.ov_range_upper_entry = get_widget_assert (builder, "entry3"); - rd.ov_low_up_entry = get_widget_assert (builder, "entry6"); - rd.ov_high_down_entry = get_widget_assert (builder, "entry7"); + rd.old_value_chooser = get_widget_assert (builder, "val-chooser"); rd.new_value_entry = get_widget_assert (builder, "entry1"); - rd.ov_value_entry = get_widget_assert (builder, "entry2"); + rd.toggle[BUTTON_NEW_VALUE] = get_widget_assert (builder, "radiobutton1"); rd.toggle[BUTTON_NEW_SYSMIS] = get_widget_assert (builder, "radiobutton2"); rd.toggle[BUTTON_NEW_COPY] = get_widget_assert (builder, "radiobutton3"); - rd.toggle[BUTTON_OLD_VALUE] = get_widget_assert (builder, "radiobutton4"); - rd.toggle[BUTTON_OLD_SYSMIS] = get_widget_assert (builder, "radiobutton6"); - rd.toggle[BUTTON_OLD_MISSING]= get_widget_assert (builder, "radiobutton7"); - rd.toggle[BUTTON_OLD_RANGE] = get_widget_assert (builder, "radiobutton8"); - rd.toggle[BUTTON_OLD_LOW_UP] = get_widget_assert (builder, "radiobutton10"); - rd.toggle[BUTTON_OLD_HIGH_DOWN] = get_widget_assert (builder, "radiobutton5"); - rd.toggle[BUTTON_OLD_ELSE] = get_widget_assert (builder, "radiobutton11"); rd.new_copy_label = get_widget_assert (builder, "label3"); rd.strings_box = get_widget_assert (builder, "table3"); @@ -1018,23 +751,6 @@ recode_dialog (PsppireDataWindow *de, gboolean diff) g_signal_connect (rd.toggle[BUTTON_NEW_VALUE], "toggled", G_CALLBACK (toggle_sensitivity), rd.new_value_entry); - g_signal_connect (rd.toggle[BUTTON_OLD_VALUE], "toggled", - G_CALLBACK (toggle_sensitivity), rd.ov_value_entry); - - g_signal_connect (rd.toggle[BUTTON_OLD_RANGE], "toggled", - G_CALLBACK (toggle_sensitivity), - get_widget_assert (builder, "entry3")); - - g_signal_connect (rd.toggle[BUTTON_OLD_RANGE], "toggled", - G_CALLBACK (toggle_sensitivity), - get_widget_assert (builder, "entry5")); - - g_signal_connect (rd.toggle[BUTTON_OLD_LOW_UP], "toggled", - G_CALLBACK (toggle_sensitivity), rd.ov_low_up_entry); - - g_signal_connect (rd.toggle[BUTTON_OLD_HIGH_DOWN], "toggled", - G_CALLBACK (toggle_sensitivity), rd.ov_high_down_entry); - g_signal_connect (rd.string_button, "toggled", G_CALLBACK (toggle_sensitivity), rd.width_entry); @@ -1081,70 +797,11 @@ recode_dialog (PsppireDataWindow *de, gboolean diff) static gboolean set_old_value (GValue *val, const struct recode_dialog *rd) { - const gchar *text = NULL; - struct old_value ov; - if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_VALUE]))) - { - text = gtk_entry_get_text (GTK_ENTRY (rd->ov_value_entry)); - if ( rd->input_var_is_string ) - { - ov.type = OV_STRING; - ov.v.s = g_strdup (text); - } - else - { - ov.type = OV_NUMERIC; - ov.v.v = g_strtod (text, 0); - } - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_MISSING]))) - { - ov.type = OV_MISSING; - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_SYSMIS]))) - { - ov.type = OV_SYSMIS; - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_ELSE]))) - { - ov.type = OV_ELSE; - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_RANGE]))) - { - const gchar *text; - text = gtk_entry_get_text (GTK_ENTRY (rd->ov_range_lower_entry)); - - ov.type = OV_RANGE; - ov.v.range[0] = g_strtod (text, 0); + PsppireValChooser *vc = PSPPIRE_VAL_CHOOSER (rd->old_value_chooser); - text = gtk_entry_get_text (GTK_ENTRY (rd->ov_range_upper_entry)); - ov.v.range[1] = g_strtod (text, 0); - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_LOW_UP]))) - { - const gchar *text = - gtk_entry_get_text (GTK_ENTRY (rd->ov_low_up_entry)); + struct old_value ov; - ov.type = OV_LOW_UP; - ov.v.range[1] = g_strtod (text, 0); - } - else if ( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON - (rd->toggle [BUTTON_OLD_HIGH_DOWN]))) - { - const gchar *text = - gtk_entry_get_text (GTK_ENTRY (rd->ov_high_down_entry)); - - ov.type = OV_HIGH_DOWN; - ov.v.range[0] = g_strtod (text, 0); - } - else - return FALSE; + psppire_val_chooser_get_status (vc, &ov); g_value_init (val, old_value_get_type ()); g_value_set_boxed (val, &ov); @@ -1255,14 +912,8 @@ run_old_and_new_dialog (struct recode_dialog *rd) rd->input_var_is_string = var_is_alpha (v); - gtk_widget_set_sensitive (rd->toggle [BUTTON_OLD_SYSMIS], - var_is_numeric (v)); - gtk_widget_set_sensitive (rd->toggle [BUTTON_OLD_RANGE], - var_is_numeric (v)); - gtk_widget_set_sensitive (rd->toggle [BUTTON_OLD_LOW_UP], - var_is_numeric (v)); - gtk_widget_set_sensitive (rd->toggle [BUTTON_OLD_HIGH_DOWN], - var_is_numeric (v)); + g_object_set (rd->old_value_chooser, "is-string", rd->input_var_is_string, NULL); + gtk_widget_set_sensitive (rd->toggle [BUTTON_NEW_SYSMIS], var_is_numeric (v)); @@ -1319,54 +970,6 @@ new_value_append_syntax (GString *str, const struct new_value *nv) } -/* Generate a syntax fragment for NV and append it to STR */ -static void -old_value_append_syntax (GString *str, const struct old_value *ov) -{ - switch (ov->type) - { - case OV_NUMERIC: - g_string_append_printf (str, "%g", ov->v.v); - break; - case OV_STRING: - { - struct string ds = DS_EMPTY_INITIALIZER; - syntax_gen_string (&ds, ss_cstr (ov->v.s)); - g_string_append (str, ds_cstr (&ds)); - ds_destroy (&ds); - } - break; - case OV_MISSING: - g_string_append (str, "MISSING"); - break; - case OV_SYSMIS: - g_string_append (str, "SYSMIS"); - break; - case OV_ELSE: - g_string_append (str, "ELSE"); - break; - case OV_RANGE: - g_string_append_printf (str, "%g THRU %g", - ov->v.range[0], - ov->v.range[1]); - break; - case OV_LOW_UP: - g_string_append_printf (str, "LOWEST THRU %g", - ov->v.range[1]); - break; - case OV_HIGH_DOWN: - g_string_append_printf (str, "%g THRU HIGHEST", - ov->v.range[0]); - break; - default: - g_warning ("Invalid type in old recode value"); - g_string_append (str, "???"); - break; - }; -} - - - static char * generate_syntax (const struct recode_dialog *rd) { diff --git a/src/ui/gui/recode.ui b/src/ui/gui/recode.ui index 45a3a6cc..f9b75827 100644 --- a/src/ui/gui/recode.ui +++ b/src/ui/gui/recode.ui @@ -12,379 +12,9 @@ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 5 - + + Old Value True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 12 - 5 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 11 - 2 - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - 0 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - 1 - 2 - 9 - 10 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - 0 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - 1 - 2 - 7 - 8 - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - - - - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 2 - 3 - - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 3 - 4 - - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 4 - 5 - - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 6 - 7 - - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 8 - 9 - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Value: - - - 1 - 2 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - System Missing - - - 1 - 2 - 2 - 3 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - System or User Missing - - - 1 - 2 - 3 - 4 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - 0 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - 0 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - through - - - 1 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - 0 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - 2 - - - - - 1 - 2 - 5 - 6 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Range, LOWEST thru value - - - 1 - 2 - 6 - 7 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Range, value thru HIGHEST - - - 1 - 2 - 8 - 9 - - - - - True - True - False - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - True - True - radiobutton4 - - - 10 - 11 - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - All other values - - - 1 - 2 - 10 - 11 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - 0 - - - True - False - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - - - - - 1 - 2 - 1 - 2 - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - 0 - Range: - - - 1 - 2 - 4 - 5 - - - - - - - - - - - - - - - - - - - - - True - GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - Old Value - True - - 0 diff --git a/src/ui/gui/widgets.c b/src/ui/gui/widgets.c index a1a55d14..9a634f73 100644 --- a/src/ui/gui/widgets.c +++ b/src/ui/gui/widgets.c @@ -11,6 +11,7 @@ #include "psppire-acr.h" #include "psppire-dictview.h" #include "psppire-var-view.h" +#include "psppire-val-chooser.h" /* Any custom widgets which are to be used in GtkBuilder ui files @@ -19,6 +20,7 @@ void preregister_widgets (void) { + psppire_val_chooser_get_type (); psppire_dialog_get_type (); psppire_selector_get_type (); psppire_vbutton_box_get_type ();