X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=inline;f=src%2Fui%2Fgui%2Fmissing-val-dialog.c;h=d6f38a2d8f8e0dc3d8213ac62c78367f5fcb4050;hb=c4bc3574d974d3aaf4d291097c995a31515a308a;hp=58ff43dafbab326d3d709188d75a9a15b3b7dbc4;hpb=356c1209257f91eb08791e6b9ca72393fca6fcd0;p=pspp
diff --git a/src/ui/gui/missing-val-dialog.c b/src/ui/gui/missing-val-dialog.c
index 58ff43dafb..d6f38a2d8f 100644
--- a/src/ui/gui/missing-val-dialog.c
+++ b/src/ui/gui/missing-val-dialog.c
@@ -1,181 +1,334 @@
-/*
- PSPPIRE --- A Graphical User Interface for PSPP
- Copyright (C) 2005, 2006 Free Software Foundation
+/* PSPPIRE - a graphical user interface for PSPP.
+ Copyright (C) 2005, 2006, 2009, 2011, 2012, 2015, 2016,
+ 2020 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 2 of the License, or
- (at your option) any later version.
+ 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.
+ 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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
/* This module describes the behaviour of the Missing Values dialog box,
used for input of the missing values in the variable sheet */
#include
-#include
-#define _(msgid) gettext (msgid)
-#define N_(msgid) msgid
+#include "ui/gui/missing-val-dialog.h"
+#include "builder-wrapper.h"
#include "helper.h"
+#include
#include "missing-val-dialog.h"
#include
#include
#include
-
#include
-#include
#include
+#include
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+static GObject *psppire_missing_val_dialog_constructor (
+ GType type, guint, GObjectConstructParam *);
+static void psppire_missing_val_dialog_finalize (GObject *);
+
+G_DEFINE_TYPE (PsppireMissingValDialog,
+ psppire_missing_val_dialog,
+ PSPPIRE_TYPE_DIALOG);
+enum
+ {
+ PROP_0,
+ PROP_VARIABLE,
+ PROP_MISSING_VALUES
+ };
-/* A simple (sub) dialog box for displaying user input errors */
static void
-err_dialog (const gchar *msg, GtkWindow *window)
+psppire_missing_val_dialog_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GtkWidget *hbox ;
- GtkWidget *label = gtk_label_new (msg);
+ PsppireMissingValDialog *obj = PSPPIRE_MISSING_VAL_DIALOG (object);
- GtkWidget *dialog =
- gtk_dialog_new_with_buttons ("PSPP",
- window,
- GTK_DIALOG_MODAL |
- GTK_DIALOG_DESTROY_WITH_PARENT |
- GTK_DIALOG_NO_SEPARATOR,
- GTK_STOCK_OK,
- GTK_RESPONSE_ACCEPT,
- NULL);
+ switch (prop_id)
+ {
+ case PROP_VARIABLE:
+ psppire_missing_val_dialog_set_variable (obj,
+ g_value_get_pointer (value));
+ break;
+ case PROP_MISSING_VALUES:
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+static void
+psppire_missing_val_dialog_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PsppireMissingValDialog *obj = PSPPIRE_MISSING_VAL_DIALOG (object);
- GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
- GTK_ICON_SIZE_DIALOG);
+ switch (prop_id)
+ {
+ case PROP_MISSING_VALUES:
+ g_value_set_pointer (value, &obj->mvl);
+ break;
+ case PROP_VARIABLE:
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
- g_signal_connect_swapped (dialog,
- "response",
- G_CALLBACK (gtk_widget_destroy),
- dialog);
+static void
+psppire_missing_val_dialog_class_init (PsppireMissingValDialogClass *class)
+{
+ GObjectClass *gobject_class;
+ gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->constructor = psppire_missing_val_dialog_constructor;
+ gobject_class->finalize = psppire_missing_val_dialog_finalize;
+ gobject_class->set_property = psppire_missing_val_dialog_set_property;
+ gobject_class->get_property = psppire_missing_val_dialog_get_property;
+
+ g_object_class_install_property (
+ gobject_class, PROP_VARIABLE,
+ g_param_spec_pointer ("variable",
+ "Variable",
+ "Variable whose missing values are to be edited. "
+ "The variable's print format and encoding are also "
+ "used for editing.",
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property (
+ gobject_class, PROP_MISSING_VALUES,
+ g_param_spec_pointer ("missing-values",
+ "Missing Values",
+ "Edited missing values.",
+ G_PARAM_READABLE));
+}
- hbox = gtk_hbox_new (FALSE, 10);
+static void
+psppire_missing_val_dialog_init (PsppireMissingValDialog *dialog)
+{
+ /* We do all of our work on widgets in the constructor function, because that
+ runs after the construction properties have been set. Otherwise
+ PsppireDialog's "orientation" property hasn't been set and therefore we
+ have no box to populate. */
+ mv_init (&dialog->mvl, 0);
+ dialog->encoding = NULL;
+}
- gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
- hbox);
+static void
+psppire_missing_val_dialog_finalize (GObject *obj)
+{
+ PsppireMissingValDialog *dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
- gtk_box_pack_start (GTK_BOX (hbox), icon, TRUE, FALSE, 10);
- gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
+ mv_destroy (&dialog->mvl);
+ g_free (dialog->encoding);
- gtk_widget_show_all (dialog);
+ G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->finalize (obj);
}
+PsppireMissingValDialog *
+psppire_missing_val_dialog_new (const struct variable *var)
+{
+ return PSPPIRE_MISSING_VAL_DIALOG (
+ g_object_new (PSPPIRE_TYPE_MISSING_VAL_DIALOG,
+ "variable", var,
+ NULL));
+}
+
+gint
+psppire_missing_val_dialog_run (GtkWindow *parent_window,
+ const struct variable *var,
+ struct missing_values *mv)
+{
+ PsppireMissingValDialog *dialog;
+
+ dialog = psppire_missing_val_dialog_new (var);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_widget_show (GTK_WIDGET (dialog));
-/* Callback which occurs when the OK button is clicked */
+ gint result = psppire_dialog_run (PSPPIRE_DIALOG (dialog));
+ if (result == GTK_RESPONSE_OK)
+ mv_copy (mv, psppire_missing_val_dialog_get_missing_values (dialog));
+ else
+ mv_copy (mv, var_get_missing_values (var));
+
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ return result;
+}
+
+
+/* A simple (sub) dialog box for displaying user input errors */
static void
-missing_val_dialog_accept (GtkWidget *w, gpointer data)
+err_dialog (const gchar *msg, GtkWindow *window)
{
- struct missing_val_dialog *dialog = data;
+ GtkWidget *dialog =
+ gtk_message_dialog_new (window,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s",msg);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
- const struct fmt_spec *write_spec = var_get_write_format (dialog->pv);
+/* Interpret text, display error dialog
+ If parsing is o.k., the value is initialized and it is the responsibility of
+ the caller to destroy the variable. */
+static gboolean
+try_missing_value(const PsppireMissingValDialog *dialog, const gchar *text, union value *vp)
+{
+ const int var_width = fmt_var_width (&dialog->format);
+ char *error_txt = NULL;
+
+ value_init(vp, var_width);
+ error_txt = data_in (ss_cstr(text), "UTF-8", dialog->format.type,
+ settings_get_fmt_settings (), vp, var_width,
+ dialog->encoding);
+ if (error_txt)
+ {
+ err_dialog (error_txt, GTK_WINDOW (dialog));
+ free (error_txt);
+ goto error;
+ }
+ else
+ {
+ if (mv_is_acceptable (vp, var_width))
+ return TRUE;
+ else
+ {
+ err_dialog (_("The maximum length of a missing value"
+ " for a string variable is 8 in UTF-8."),
+ GTK_WINDOW (dialog));
+ goto error;
+ }
+ }
+ error:
+ value_destroy (vp, var_width);
+ return FALSE;
+}
+
+/* Acceptability predicate for PsppireMissingValDialog.
- if ( gtk_toggle_button_get_active (dialog->button_discrete))
+ This function is also the only place that dialog->mvl gets updated. */
+static gboolean
+missing_val_dialog_acceptable (gpointer data)
+{
+ PsppireMissingValDialog *dialog = data;
+ int var_width = fmt_var_width (&dialog->format);
+
+ if (gtk_toggle_button_get_active (dialog->button_discrete))
{
gint nvals = 0;
- gint badvals = 0;
gint i;
- mv_clear (&dialog->mvl);
- for (i = 0 ; i < 3 ; ++i )
+
+ mv_clear(&dialog->mvl);
+ for(i = 0 ; i < 3 ; ++i)
{
gchar *text =
g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
union value v;
- if ( !text || strlen (g_strstrip (text)) == 0 )
+ if (!text || strlen (g_strstrip (text)) == 0)
{
g_free (text);
continue;
}
- if ( text_to_value (text, &v, *write_spec))
+ if (!try_missing_value (dialog, text, &v))
{
- nvals++;
- mv_add_value (&dialog->mvl, &v);
+ g_free (text);
+ gtk_widget_grab_focus (dialog->mv[i]);
+ return FALSE;
}
- else
- badvals++;
+ mv_add_value (&dialog->mvl, &v);
+ nvals++;
g_free (text);
+ value_destroy (&v, var_width);
}
- if ( nvals == 0 || badvals > 0 )
+ if (nvals == 0)
{
- err_dialog (_("Incorrect value for variable type"),
- GTK_WINDOW (dialog->window));
- return ;
+ err_dialog (_("At least one value must be specified"),
+ GTK_WINDOW (dialog));
+ gtk_widget_grab_focus (dialog->mv[0]);
+ return FALSE;
}
}
if (gtk_toggle_button_get_active (dialog->button_range))
{
- gchar *discrete_text ;
-
+ gchar *discrete_text;
union value low_val ;
union value high_val;
const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
- if ( text_to_value (low_text, &low_val, *write_spec)
- &&
- text_to_value (high_text, &high_val, *write_spec) )
+ assert (var_width == 0); /* Ranges are only for numeric variables */
+
+ if (!try_missing_value(dialog, low_text, &low_val))
{
- if ( low_val.f > high_val.f )
- {
- err_dialog (_("Incorrect range specification"),
- GTK_WINDOW (dialog->window));
- return ;
- }
+ gtk_widget_grab_focus (dialog->low);
+ return FALSE;
}
- else
+ if (!try_missing_value (dialog, high_text, &high_val))
+ {
+ gtk_widget_grab_focus (dialog->high);
+ value_destroy (&low_val, var_width);
+ return FALSE;
+ }
+ if (low_val.f > high_val.f)
{
err_dialog (_("Incorrect range specification"),
- GTK_WINDOW (dialog->window));
- return;
+ GTK_WINDOW (dialog));
+ value_destroy (&low_val, var_width);
+ value_destroy (&high_val, var_width);
+ gtk_widget_grab_focus (dialog->low);
+ return FALSE;
}
-
- discrete_text =
- g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
-
mv_clear (&dialog->mvl);
- mv_add_num_range (&dialog->mvl, low_val.f, high_val.f);
+ mv_add_range (&dialog->mvl, low_val.f, high_val.f);
+ value_destroy (&low_val, var_width);
+ value_destroy (&high_val, var_width);
+
+ discrete_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
- if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
+ if (discrete_text && strlen (g_strstrip (discrete_text)) > 0)
{
union value discrete_val;
- if ( !text_to_value (discrete_text, &discrete_val,
- *write_spec))
+ if (!try_missing_value (dialog, discrete_text, &discrete_val))
{
- err_dialog (_("Incorrect value for variable type"),
- GTK_WINDOW (dialog->window) );
g_free (discrete_text);
- return;
+ gtk_widget_grab_focus (dialog->discrete);
+ return FALSE;
}
mv_add_value (&dialog->mvl, &discrete_val);
+ value_destroy (&discrete_val, var_width);
}
g_free (discrete_text);
}
-
if (gtk_toggle_button_get_active (dialog->button_none))
mv_clear (&dialog->mvl);
- var_set_missing_values (dialog->pv, &dialog->mvl);
-
- gtk_widget_hide (dialog->window);
+ return TRUE;
}
@@ -184,9 +337,9 @@ static void
discrete (GtkToggleButton *button, gpointer data)
{
gint i;
- struct missing_val_dialog *dialog = data;
+ PsppireMissingValDialog *dialog = data;
- for (i = 0 ; i < 3 ; ++i )
+ for (i = 0 ; i < 3 ; ++i)
{
gtk_widget_set_sensitive (dialog->mv[i],
gtk_toggle_button_get_active (button));
@@ -197,7 +350,7 @@ discrete (GtkToggleButton *button, gpointer data)
static void
range (GtkToggleButton *button, gpointer data)
{
- struct missing_val_dialog *dialog = data;
+ PsppireMissingValDialog *dialog = data;
const gboolean active = gtk_toggle_button_get_active (button);
@@ -207,27 +360,29 @@ range (GtkToggleButton *button, gpointer data)
}
-/* Creates the dialog structure from the xml */
-struct missing_val_dialog *
-missing_val_dialog_create (GladeXML *xml)
-{
- struct missing_val_dialog *dialog = g_malloc (sizeof (*dialog));
-
- connect_help (xml);
-
- dialog->window = get_widget_assert (xml, "missing_values_dialog");
-
- gtk_window_set_transient_for
- (GTK_WINDOW (dialog->window),
- GTK_WINDOW (get_widget_assert (xml, "data_editor")));
+/* Shows the dialog box and sets default values */
+static GObject *
+psppire_missing_val_dialog_constructor (GType type,
+ guint n_properties,
+ GObjectConstructParam *properties)
+{
+ PsppireMissingValDialog *dialog;
+ GtkContainer *content_area;
+ GtkBuilder *xml;
+ GObject *obj;
- g_signal_connect_swapped (get_widget_assert (xml, "missing_val_cancel"),
- "clicked", G_CALLBACK (gtk_widget_hide), dialog->window);
+ obj = G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->constructor (
+ type, n_properties, properties);
+ dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
- g_signal_connect (get_widget_assert (xml, "missing_val_ok"),
- "clicked", G_CALLBACK (missing_val_dialog_accept), dialog);
+ g_object_set (dialog, "help-page", "Missing-Observations",
+ "title", _("Missing Values"), NULL);
+ content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog));
+ xml = builder_new ("missing-val-dialog.ui");
+ gtk_container_add (GTK_CONTAINER (content_area),
+ get_widget_assert (xml, "missing-values-dialog"));
dialog->mv[0] = get_widget_assert (xml, "mv0");
dialog->mv[1] = get_widget_assert (xml, "mv1");
@@ -247,29 +402,47 @@ missing_val_dialog_create (GladeXML *xml)
dialog->button_range =
GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
+ psppire_dialog_set_accept_predicate (PSPPIRE_DIALOG (dialog),
+ missing_val_dialog_acceptable,
+ dialog);
- g_signal_connect (G_OBJECT (dialog->button_discrete), "toggled",
+ g_signal_connect (dialog->button_discrete, "toggled",
G_CALLBACK (discrete), dialog);
- g_signal_connect (G_OBJECT (dialog->button_range), "toggled",
+ g_signal_connect (dialog->button_range, "toggled",
G_CALLBACK (range), dialog);
- return dialog;
+ g_object_unref (xml);
+
+ return obj;
}
-/* Shows the dialog box and sets default values */
void
-missing_val_dialog_show (struct missing_val_dialog *dialog)
+psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *dialog,
+ const struct variable *var)
{
- const struct fmt_spec *write_spec ;
-
+ enum val_type var_type;
gint i;
- g_return_if_fail (dialog);
- g_return_if_fail (dialog->pv);
- mv_copy (&dialog->mvl, var_get_missing_values (dialog->pv));
+ mv_destroy (&dialog->mvl);
+ g_free (dialog->encoding);
- write_spec = var_get_write_format (dialog->pv);
+ if (var != NULL)
+ {
+ const struct missing_values *vmv = var_get_missing_values (var);
+ if (mv_is_empty(vmv))
+ mv_init (&dialog->mvl, var_get_width(var));
+ else
+ mv_copy (&dialog->mvl, vmv);
+ dialog->encoding = g_strdup (var_get_encoding (var));
+ dialog->format = *var_get_print_format (var);
+ }
+ else
+ {
+ mv_init (&dialog->mvl, 0);
+ dialog->encoding = NULL;
+ dialog->format = F_8_0;
+ }
/* Blank all entry boxes and make them insensitive */
gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
@@ -279,37 +452,40 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
gtk_widget_set_sensitive (dialog->high, FALSE);
gtk_widget_set_sensitive (dialog->discrete, FALSE);
+ var_type = val_type_from_width (fmt_var_width (&dialog->format));
gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
- var_is_numeric (dialog->pv));
+ var_type == VAL_NUMERIC);
+ if (var == NULL)
+ return;
- for (i = 0 ; i < 3 ; ++i )
+ for (i = 0 ; i < 3 ; ++i)
{
gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
gtk_widget_set_sensitive (dialog->mv[i], FALSE);
}
- if ( mv_has_range (&dialog->mvl))
+ if (mv_has_range (&dialog->mvl))
{
union value low, high;
gchar *low_text;
gchar *high_text;
- mv_peek_range (&dialog->mvl, &low.f, &high.f);
+ mv_get_range (&dialog->mvl, &low.f, &high.f);
+
- low_text = value_to_text (low, *write_spec);
- high_text = value_to_text (high, *write_spec);
+ low_text = value_to_text__ (low, &dialog->format, dialog->encoding);
+ high_text = value_to_text__ (high, &dialog->format, dialog->encoding);
gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
g_free (low_text);
g_free (high_text);
- if ( mv_has_value (&dialog->mvl))
+ if (mv_has_value (&dialog->mvl))
{
gchar *text;
- union value value;
- mv_peek_value (&dialog->mvl, &value, 0);
- text = value_to_text (value, *write_spec);
+ text = value_to_text__ (*mv_get_value (&dialog->mvl, 0),
+ &dialog->format, dialog->encoding);
gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
g_free (text);
}
@@ -320,19 +496,18 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
gtk_widget_set_sensitive (dialog->discrete, TRUE);
}
- else if ( mv_has_value (&dialog->mvl))
+ else if (mv_has_value (&dialog->mvl))
{
const int n = mv_n_values (&dialog->mvl);
- for (i = 0 ; i < 3 ; ++i )
+ for (i = 0 ; i < 3 ; ++i)
{
- if ( i < n)
+ if (i < n)
{
gchar *text ;
- union value value;
- mv_peek_value (&dialog->mvl, &value, i);
- text = value_to_text (value, *write_spec);
+ text = value_to_text__ (*mv_get_value (&dialog->mvl, i),
+ &dialog->format, dialog->encoding);
gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
g_free (text);
}
@@ -340,10 +515,15 @@ missing_val_dialog_show (struct missing_val_dialog *dialog)
}
gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
}
- else if ( mv_is_empty (&dialog->mvl))
+ else if (mv_is_empty (&dialog->mvl))
{
gtk_toggle_button_set_active (dialog->button_none, TRUE);
}
+}
- gtk_widget_show (dialog->window);
+const struct missing_values *
+psppire_missing_val_dialog_get_missing_values (
+ const PsppireMissingValDialog *dialog)
+{
+ return &dialog->mvl;
}