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 GtkWidget *label = gtk_label_new (msg);
183 gtk_dialog_new_with_buttons ("PSPP",
186 GTK_DIALOG_DESTROY_WITH_PARENT,
192 GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
193 GTK_ICON_SIZE_DIALOG);
195 g_signal_connect_swapped (dialog,
197 G_CALLBACK (gtk_widget_destroy),
200 hbox = gtk_hbox_new (FALSE, 10);
202 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
205 gtk_box_pack_start (GTK_BOX (hbox), icon, TRUE, FALSE, 10);
206 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
208 gtk_widget_show_all (dialog);
212 /* Acceptability predicate for PsppireMissingValDialog.
214 This function is also the only place that dialog->mvl gets updated. */
216 missing_val_dialog_acceptable (gpointer data)
218 PsppireMissingValDialog *dialog = data;
220 if ( gtk_toggle_button_get_active (dialog->button_discrete))
225 mv_clear(&dialog->mvl);
226 for(i = 0 ; i < 3 ; ++i )
229 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
232 if ( !text || strlen (g_strstrip (text)) == 0 )
238 if ( text_to_value__ (text, &dialog->format, dialog->encoding, &v))
241 mv_add_value (&dialog->mvl, &v);
246 value_destroy (&v, fmt_var_width (&dialog->format));
248 if ( nvals == 0 || badvals > 0 )
250 err_dialog (_("Incorrect value for variable type"),
251 GTK_WINDOW (dialog));
256 if (gtk_toggle_button_get_active (dialog->button_range))
258 gchar *discrete_text ;
260 union value low_val ;
261 union value high_val;
262 const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
263 const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
268 low_ok = text_to_value__ (low_text, &dialog->format, dialog->encoding,
270 high_ok = text_to_value__ (high_text, &dialog->format, dialog->encoding,
272 ok = low_ok && high_ok && low_val.f <= high_val.f;
275 err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog));
277 value_destroy (&low_val, fmt_var_width (&dialog->format));
279 value_destroy (&high_val, fmt_var_width (&dialog->format));
284 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
286 mv_clear (&dialog->mvl);
287 mv_add_range (&dialog->mvl, low_val.f, high_val.f);
289 value_destroy (&low_val, fmt_var_width (&dialog->format));
290 value_destroy (&high_val, fmt_var_width (&dialog->format));
292 if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
294 union value discrete_val;
295 if ( !text_to_value__ (discrete_text,
300 err_dialog (_("Incorrect value for variable type"),
301 GTK_WINDOW (dialog) );
302 g_free (discrete_text);
303 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
306 mv_add_value (&dialog->mvl, &discrete_val);
307 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
309 g_free (discrete_text);
313 if (gtk_toggle_button_get_active (dialog->button_none))
314 mv_clear (&dialog->mvl);
320 /* Callback which occurs when the 'discrete' radiobutton is toggled */
322 discrete (GtkToggleButton *button, gpointer data)
325 PsppireMissingValDialog *dialog = data;
327 for (i = 0 ; i < 3 ; ++i )
329 gtk_widget_set_sensitive (dialog->mv[i],
330 gtk_toggle_button_get_active (button));
334 /* Callback which occurs when the 'range' radiobutton is toggled */
336 range (GtkToggleButton *button, gpointer data)
338 PsppireMissingValDialog *dialog = data;
340 const gboolean active = gtk_toggle_button_get_active (button);
342 gtk_widget_set_sensitive (dialog->low, active);
343 gtk_widget_set_sensitive (dialog->high, active);
344 gtk_widget_set_sensitive (dialog->discrete, active);
349 /* Shows the dialog box and sets default values */
351 psppire_missing_val_dialog_constructor (GType type,
353 GObjectConstructParam *properties)
355 PsppireMissingValDialog *dialog;
356 GtkContainer *content_area;
360 obj = G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->constructor (
361 type, n_properties, properties);
362 dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
364 content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog));
365 xml = builder_new ("missing-val-dialog.ui");
366 gtk_container_add (GTK_CONTAINER (content_area),
367 get_widget_assert (xml, "missing-values-dialog"));
369 dialog->mv[0] = get_widget_assert (xml, "mv0");
370 dialog->mv[1] = get_widget_assert (xml, "mv1");
371 dialog->mv[2] = get_widget_assert (xml, "mv2");
373 dialog->low = get_widget_assert (xml, "mv-low");
374 dialog->high = get_widget_assert (xml, "mv-high");
375 dialog->discrete = get_widget_assert (xml, "mv-discrete");
378 dialog->button_none =
379 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
381 dialog->button_discrete =
382 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
384 dialog->button_range =
385 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
387 psppire_dialog_set_accept_predicate (PSPPIRE_DIALOG (dialog),
388 missing_val_dialog_acceptable,
391 g_signal_connect (dialog->button_discrete, "toggled",
392 G_CALLBACK (discrete), dialog);
394 g_signal_connect (dialog->button_range, "toggled",
395 G_CALLBACK (range), dialog);
397 g_object_unref (xml);
403 psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *dialog,
404 const struct variable *var)
406 enum val_type var_type;
409 mv_destroy (&dialog->mvl);
410 g_free (dialog->encoding);
414 mv_copy (&dialog->mvl, var_get_missing_values (var));
415 dialog->encoding = g_strdup (var_get_encoding (var));
416 dialog->format = *var_get_print_format (var);
420 mv_init (&dialog->mvl, 0);
421 dialog->encoding = NULL;
422 dialog->format = F_8_0;
425 /* Blank all entry boxes and make them insensitive */
426 gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
427 gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
428 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
429 gtk_widget_set_sensitive (dialog->low, FALSE);
430 gtk_widget_set_sensitive (dialog->high, FALSE);
431 gtk_widget_set_sensitive (dialog->discrete, FALSE);
433 var_type = val_type_from_width (fmt_var_width (&dialog->format));
434 gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
435 var_type == VAL_NUMERIC);
440 for (i = 0 ; i < 3 ; ++i )
442 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
443 gtk_widget_set_sensitive (dialog->mv[i], FALSE);
446 if ( mv_has_range (&dialog->mvl))
448 union value low, high;
451 mv_get_range (&dialog->mvl, &low.f, &high.f);
454 low_text = value_to_text__ (low, &dialog->format, dialog->encoding);
455 high_text = value_to_text__ (high, &dialog->format, dialog->encoding);
457 gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
458 gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
462 if ( mv_has_value (&dialog->mvl))
465 text = value_to_text__ (*mv_get_value (&dialog->mvl, 0),
466 &dialog->format, dialog->encoding);
467 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
471 gtk_toggle_button_set_active (dialog->button_range, TRUE);
472 gtk_widget_set_sensitive (dialog->low, TRUE);
473 gtk_widget_set_sensitive (dialog->high, TRUE);
474 gtk_widget_set_sensitive (dialog->discrete, TRUE);
477 else if ( mv_has_value (&dialog->mvl))
479 const int n = mv_n_values (&dialog->mvl);
481 for (i = 0 ; i < 3 ; ++i )
487 text = value_to_text__ (*mv_get_value (&dialog->mvl, i),
488 &dialog->format, dialog->encoding);
489 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
492 gtk_widget_set_sensitive (dialog->mv[i], TRUE);
494 gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
496 else if ( mv_is_empty (&dialog->mvl))
498 gtk_toggle_button_set_active (dialog->button_none, TRUE);
502 const struct missing_values *
503 psppire_missing_val_dialog_get_missing_values (
504 const PsppireMissingValDialog *dialog)