1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2005, 2006, 2009, 2011, 2012, 2015 Free Software Foundation
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/>. */
17 /* This module describes the behaviour of the Missing Values dialog box,
18 used for input of the missing values in the variable sheet */
22 #include "ui/gui/missing-val-dialog.h"
24 #include "builder-wrapper.h"
26 #include <data/format.h>
27 #include "missing-val-dialog.h"
28 #include <data/missing-values.h>
29 #include <data/variable.h>
30 #include <data/data-in.h>
37 #define _(msgid) gettext (msgid)
38 #define N_(msgid) msgid
40 static GObject *psppire_missing_val_dialog_constructor (
41 GType type, guint, GObjectConstructParam *);
42 static void psppire_missing_val_dialog_finalize (GObject *);
44 G_DEFINE_TYPE (PsppireMissingValDialog,
45 psppire_missing_val_dialog,
55 psppire_missing_val_dialog_set_property (GObject *object,
60 PsppireMissingValDialog *obj = PSPPIRE_MISSING_VAL_DIALOG (object);
65 psppire_missing_val_dialog_set_variable (obj,
66 g_value_get_pointer (value));
68 case PROP_MISSING_VALUES:
70 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
76 psppire_missing_val_dialog_get_property (GObject *object,
81 PsppireMissingValDialog *obj = PSPPIRE_MISSING_VAL_DIALOG (object);
85 case PROP_MISSING_VALUES:
86 g_value_set_pointer (value, &obj->mvl);
90 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
96 psppire_missing_val_dialog_class_init (PsppireMissingValDialogClass *class)
98 GObjectClass *gobject_class;
99 gobject_class = G_OBJECT_CLASS (class);
101 gobject_class->constructor = psppire_missing_val_dialog_constructor;
102 gobject_class->finalize = psppire_missing_val_dialog_finalize;
103 gobject_class->set_property = psppire_missing_val_dialog_set_property;
104 gobject_class->get_property = psppire_missing_val_dialog_get_property;
106 g_object_class_install_property (
107 gobject_class, PROP_VARIABLE,
108 g_param_spec_pointer ("variable",
110 "Variable whose missing values are to be edited. "
111 "The variable's print format and encoding are also "
115 g_object_class_install_property (
116 gobject_class, PROP_MISSING_VALUES,
117 g_param_spec_pointer ("missing-values",
119 "Edited missing values.",
124 psppire_missing_val_dialog_init (PsppireMissingValDialog *dialog)
126 /* We do all of our work on widgets in the constructor function, because that
127 runs after the construction properties have been set. Otherwise
128 PsppireDialog's "orientation" property hasn't been set and therefore we
129 have no box to populate. */
130 mv_init (&dialog->mvl, 0);
131 dialog->encoding = NULL;
135 psppire_missing_val_dialog_finalize (GObject *obj)
137 PsppireMissingValDialog *dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
139 mv_destroy (&dialog->mvl);
140 g_free (dialog->encoding);
142 G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->finalize (obj);
145 PsppireMissingValDialog *
146 psppire_missing_val_dialog_new (const struct variable *var)
148 return PSPPIRE_MISSING_VAL_DIALOG (
149 g_object_new (PSPPIRE_TYPE_MISSING_VAL_DIALOG,
155 psppire_missing_val_dialog_run (GtkWindow *parent_window,
156 const struct variable *var,
157 struct missing_values *mv)
159 PsppireMissingValDialog *dialog;
161 dialog = psppire_missing_val_dialog_new (var);
162 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
163 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
164 gtk_widget_show (GTK_WIDGET (dialog));
166 if (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK)
167 mv_copy (mv, psppire_missing_val_dialog_get_missing_values (dialog));
169 mv_copy (mv, var_get_missing_values (var));
171 gtk_widget_destroy (GTK_WIDGET (dialog));
175 /* A simple (sub) dialog box for displaying user input errors */
177 err_dialog (const gchar *msg, GtkWindow *window)
180 gtk_message_dialog_new (window,
181 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
186 gtk_dialog_run (GTK_DIALOG (dialog));
187 gtk_widget_destroy (dialog);
190 /* Acceptability predicate for PsppireMissingValDialog.
192 This function is also the only place that dialog->mvl gets updated. */
194 missing_val_dialog_acceptable (gpointer data)
196 PsppireMissingValDialog *dialog = data;
198 if ( gtk_toggle_button_get_active (dialog->button_discrete))
203 mv_clear(&dialog->mvl);
204 for(i = 0 ; i < 3 ; ++i )
207 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
210 if ( !text || strlen (g_strstrip (text)) == 0 )
216 if ( text_to_value__ (text, &dialog->format, dialog->encoding, &v))
219 mv_add_value (&dialog->mvl, &v);
224 value_destroy (&v, fmt_var_width (&dialog->format));
226 if ( nvals == 0 || badvals > 0 )
228 err_dialog (_("Incorrect value for variable type"),
229 GTK_WINDOW (dialog));
234 if (gtk_toggle_button_get_active (dialog->button_range))
236 gchar *discrete_text ;
238 union value low_val ;
239 union value high_val;
240 const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
241 const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
246 low_ok = text_to_value__ (low_text, &dialog->format, dialog->encoding,
248 high_ok = text_to_value__ (high_text, &dialog->format, dialog->encoding,
250 ok = low_ok && high_ok && low_val.f <= high_val.f;
253 err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog));
255 value_destroy (&low_val, fmt_var_width (&dialog->format));
257 value_destroy (&high_val, fmt_var_width (&dialog->format));
262 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
264 mv_clear (&dialog->mvl);
265 mv_add_range (&dialog->mvl, low_val.f, high_val.f);
267 value_destroy (&low_val, fmt_var_width (&dialog->format));
268 value_destroy (&high_val, fmt_var_width (&dialog->format));
270 if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
272 union value discrete_val;
273 if ( !text_to_value__ (discrete_text,
278 err_dialog (_("Incorrect value for variable type"),
279 GTK_WINDOW (dialog) );
280 g_free (discrete_text);
281 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
284 mv_add_value (&dialog->mvl, &discrete_val);
285 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
287 g_free (discrete_text);
291 if (gtk_toggle_button_get_active (dialog->button_none))
292 mv_clear (&dialog->mvl);
298 /* Callback which occurs when the 'discrete' radiobutton is toggled */
300 discrete (GtkToggleButton *button, gpointer data)
303 PsppireMissingValDialog *dialog = data;
305 for (i = 0 ; i < 3 ; ++i )
307 gtk_widget_set_sensitive (dialog->mv[i],
308 gtk_toggle_button_get_active (button));
312 /* Callback which occurs when the 'range' radiobutton is toggled */
314 range (GtkToggleButton *button, gpointer data)
316 PsppireMissingValDialog *dialog = data;
318 const gboolean active = gtk_toggle_button_get_active (button);
320 gtk_widget_set_sensitive (dialog->low, active);
321 gtk_widget_set_sensitive (dialog->high, active);
322 gtk_widget_set_sensitive (dialog->discrete, active);
327 /* Shows the dialog box and sets default values */
329 psppire_missing_val_dialog_constructor (GType type,
331 GObjectConstructParam *properties)
333 PsppireMissingValDialog *dialog;
334 GtkContainer *content_area;
338 obj = G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->constructor (
339 type, n_properties, properties);
340 dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
342 content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog));
343 xml = builder_new ("missing-val-dialog.ui");
344 gtk_container_add (GTK_CONTAINER (content_area),
345 get_widget_assert (xml, "missing-values-dialog"));
347 dialog->mv[0] = get_widget_assert (xml, "mv0");
348 dialog->mv[1] = get_widget_assert (xml, "mv1");
349 dialog->mv[2] = get_widget_assert (xml, "mv2");
351 dialog->low = get_widget_assert (xml, "mv-low");
352 dialog->high = get_widget_assert (xml, "mv-high");
353 dialog->discrete = get_widget_assert (xml, "mv-discrete");
356 dialog->button_none =
357 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
359 dialog->button_discrete =
360 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
362 dialog->button_range =
363 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
365 psppire_dialog_set_accept_predicate (PSPPIRE_DIALOG (dialog),
366 missing_val_dialog_acceptable,
369 g_signal_connect (dialog->button_discrete, "toggled",
370 G_CALLBACK (discrete), dialog);
372 g_signal_connect (dialog->button_range, "toggled",
373 G_CALLBACK (range), dialog);
375 g_object_unref (xml);
381 psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *dialog,
382 const struct variable *var)
384 enum val_type var_type;
387 mv_destroy (&dialog->mvl);
388 g_free (dialog->encoding);
392 mv_copy (&dialog->mvl, var_get_missing_values (var));
393 dialog->encoding = g_strdup (var_get_encoding (var));
394 dialog->format = *var_get_print_format (var);
398 mv_init (&dialog->mvl, 0);
399 dialog->encoding = NULL;
400 dialog->format = F_8_0;
403 /* Blank all entry boxes and make them insensitive */
404 gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
405 gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
406 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
407 gtk_widget_set_sensitive (dialog->low, FALSE);
408 gtk_widget_set_sensitive (dialog->high, FALSE);
409 gtk_widget_set_sensitive (dialog->discrete, FALSE);
411 var_type = val_type_from_width (fmt_var_width (&dialog->format));
412 gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
413 var_type == VAL_NUMERIC);
418 for (i = 0 ; i < 3 ; ++i )
420 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
421 gtk_widget_set_sensitive (dialog->mv[i], FALSE);
424 if ( mv_has_range (&dialog->mvl))
426 union value low, high;
429 mv_get_range (&dialog->mvl, &low.f, &high.f);
432 low_text = value_to_text__ (low, &dialog->format, dialog->encoding);
433 high_text = value_to_text__ (high, &dialog->format, dialog->encoding);
435 gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
436 gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
440 if ( mv_has_value (&dialog->mvl))
443 text = value_to_text__ (*mv_get_value (&dialog->mvl, 0),
444 &dialog->format, dialog->encoding);
445 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
449 gtk_toggle_button_set_active (dialog->button_range, TRUE);
450 gtk_widget_set_sensitive (dialog->low, TRUE);
451 gtk_widget_set_sensitive (dialog->high, TRUE);
452 gtk_widget_set_sensitive (dialog->discrete, TRUE);
455 else if ( mv_has_value (&dialog->mvl))
457 const int n = mv_n_values (&dialog->mvl);
459 for (i = 0 ; i < 3 ; ++i )
465 text = value_to_text__ (*mv_get_value (&dialog->mvl, i),
466 &dialog->format, dialog->encoding);
467 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
470 gtk_widget_set_sensitive (dialog->mv[i], TRUE);
472 gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
474 else if ( mv_is_empty (&dialog->mvl))
476 gtk_toggle_button_set_active (dialog->button_none, TRUE);
480 const struct missing_values *
481 psppire_missing_val_dialog_get_missing_values (
482 const PsppireMissingValDialog *dialog)