1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2005, 2006, 2009, 2011, 2012 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,
150 "orientation", PSPPIRE_VERTICAL,
156 psppire_missing_val_dialog_run (GtkWindow *parent_window,
157 const struct variable *var,
158 struct missing_values *mv)
160 PsppireMissingValDialog *dialog;
162 dialog = psppire_missing_val_dialog_new (var);
163 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent_window);
164 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
165 gtk_widget_show (GTK_WIDGET (dialog));
167 if (psppire_dialog_run (PSPPIRE_DIALOG (dialog)) == GTK_RESPONSE_OK)
168 mv_copy (mv, psppire_missing_val_dialog_get_missing_values (dialog));
170 mv_copy (mv, var_get_missing_values (var));
172 gtk_widget_destroy (GTK_WIDGET (dialog));
176 /* A simple (sub) dialog box for displaying user input errors */
178 err_dialog (const gchar *msg, GtkWindow *window)
181 GtkWidget *label = gtk_label_new (msg);
184 gtk_dialog_new_with_buttons ("PSPP",
187 GTK_DIALOG_DESTROY_WITH_PARENT |
188 GTK_DIALOG_NO_SEPARATOR,
194 GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
195 GTK_ICON_SIZE_DIALOG);
197 g_signal_connect_swapped (dialog,
199 G_CALLBACK (gtk_widget_destroy),
202 hbox = gtk_hbox_new (FALSE, 10);
204 gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
207 gtk_box_pack_start (GTK_BOX (hbox), icon, TRUE, FALSE, 10);
208 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
210 gtk_widget_show_all (dialog);
214 /* Acceptability predicate for PsppireMissingValDialog.
216 This function is also the only place that dialog->mvl gets updated. */
218 missing_val_dialog_acceptable (gpointer data)
220 PsppireMissingValDialog *dialog = data;
222 if ( gtk_toggle_button_get_active (dialog->button_discrete))
227 mv_clear(&dialog->mvl);
228 for(i = 0 ; i < 3 ; ++i )
231 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
234 if ( !text || strlen (g_strstrip (text)) == 0 )
240 if ( text_to_value__ (text, &dialog->format, dialog->encoding, &v))
243 mv_add_value (&dialog->mvl, &v);
248 value_destroy (&v, fmt_var_width (&dialog->format));
250 if ( nvals == 0 || badvals > 0 )
252 err_dialog (_("Incorrect value for variable type"),
253 GTK_WINDOW (dialog));
258 if (gtk_toggle_button_get_active (dialog->button_range))
260 gchar *discrete_text ;
262 union value low_val ;
263 union value high_val;
264 const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
265 const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
270 low_ok = text_to_value__ (low_text, &dialog->format, dialog->encoding,
272 high_ok = text_to_value__ (high_text, &dialog->format, dialog->encoding,
274 ok = low_ok && high_ok && low_val.f <= high_val.f;
277 err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog));
279 value_destroy (&low_val, fmt_var_width (&dialog->format));
281 value_destroy (&high_val, fmt_var_width (&dialog->format));
286 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
288 mv_clear (&dialog->mvl);
289 mv_add_range (&dialog->mvl, low_val.f, high_val.f);
291 value_destroy (&low_val, fmt_var_width (&dialog->format));
292 value_destroy (&high_val, fmt_var_width (&dialog->format));
294 if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
296 union value discrete_val;
297 if ( !text_to_value__ (discrete_text,
302 err_dialog (_("Incorrect value for variable type"),
303 GTK_WINDOW (dialog) );
304 g_free (discrete_text);
305 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
308 mv_add_value (&dialog->mvl, &discrete_val);
309 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
311 g_free (discrete_text);
315 if (gtk_toggle_button_get_active (dialog->button_none))
316 mv_clear (&dialog->mvl);
322 /* Callback which occurs when the 'discrete' radiobutton is toggled */
324 discrete (GtkToggleButton *button, gpointer data)
327 PsppireMissingValDialog *dialog = data;
329 for (i = 0 ; i < 3 ; ++i )
331 gtk_widget_set_sensitive (dialog->mv[i],
332 gtk_toggle_button_get_active (button));
336 /* Callback which occurs when the 'range' radiobutton is toggled */
338 range (GtkToggleButton *button, gpointer data)
340 PsppireMissingValDialog *dialog = data;
342 const gboolean active = gtk_toggle_button_get_active (button);
344 gtk_widget_set_sensitive (dialog->low, active);
345 gtk_widget_set_sensitive (dialog->high, active);
346 gtk_widget_set_sensitive (dialog->discrete, active);
351 /* Shows the dialog box and sets default values */
353 psppire_missing_val_dialog_constructor (GType type,
355 GObjectConstructParam *properties)
357 PsppireMissingValDialog *dialog;
358 GtkContainer *content_area;
362 obj = G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->constructor (
363 type, n_properties, properties);
364 dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
366 content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog)->box);
367 xml = builder_new ("missing-val-dialog.ui");
368 gtk_container_add (GTK_CONTAINER (content_area),
369 get_widget_assert (xml, "missing-values-dialog"));
371 dialog->mv[0] = get_widget_assert (xml, "mv0");
372 dialog->mv[1] = get_widget_assert (xml, "mv1");
373 dialog->mv[2] = get_widget_assert (xml, "mv2");
375 dialog->low = get_widget_assert (xml, "mv-low");
376 dialog->high = get_widget_assert (xml, "mv-high");
377 dialog->discrete = get_widget_assert (xml, "mv-discrete");
380 dialog->button_none =
381 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
383 dialog->button_discrete =
384 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
386 dialog->button_range =
387 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
389 psppire_dialog_set_accept_predicate (PSPPIRE_DIALOG (dialog),
390 missing_val_dialog_acceptable,
393 g_signal_connect (dialog->button_discrete, "toggled",
394 G_CALLBACK (discrete), dialog);
396 g_signal_connect (dialog->button_range, "toggled",
397 G_CALLBACK (range), dialog);
399 g_object_unref (xml);
405 psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *dialog,
406 const struct variable *var)
408 enum val_type var_type;
411 mv_destroy (&dialog->mvl);
412 g_free (dialog->encoding);
416 mv_copy (&dialog->mvl, var_get_missing_values (var));
417 dialog->encoding = g_strdup (var_get_encoding (var));
418 dialog->format = *var_get_print_format (var);
422 mv_init (&dialog->mvl, 0);
423 dialog->encoding = NULL;
424 dialog->format = F_8_0;
427 /* Blank all entry boxes and make them insensitive */
428 gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
429 gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
430 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
431 gtk_widget_set_sensitive (dialog->low, FALSE);
432 gtk_widget_set_sensitive (dialog->high, FALSE);
433 gtk_widget_set_sensitive (dialog->discrete, FALSE);
435 var_type = val_type_from_width (fmt_var_width (&dialog->format));
436 gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
437 var_type == VAL_NUMERIC);
442 for (i = 0 ; i < 3 ; ++i )
444 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
445 gtk_widget_set_sensitive (dialog->mv[i], FALSE);
448 if ( mv_has_range (&dialog->mvl))
450 union value low, high;
453 mv_get_range (&dialog->mvl, &low.f, &high.f);
456 low_text = value_to_text__ (low, &dialog->format, dialog->encoding);
457 high_text = value_to_text__ (high, &dialog->format, dialog->encoding);
459 gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
460 gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
464 if ( mv_has_value (&dialog->mvl))
467 text = value_to_text__ (*mv_get_value (&dialog->mvl, 0),
468 &dialog->format, dialog->encoding);
469 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
473 gtk_toggle_button_set_active (dialog->button_range, TRUE);
474 gtk_widget_set_sensitive (dialog->low, TRUE);
475 gtk_widget_set_sensitive (dialog->high, TRUE);
476 gtk_widget_set_sensitive (dialog->discrete, TRUE);
479 else if ( mv_has_value (&dialog->mvl))
481 const int n = mv_n_values (&dialog->mvl);
483 for (i = 0 ; i < 3 ; ++i )
489 text = value_to_text__ (*mv_get_value (&dialog->mvl, i),
490 &dialog->format, dialog->encoding);
491 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
494 gtk_widget_set_sensitive (dialog->mv[i], TRUE);
496 gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
498 else if ( mv_is_empty (&dialog->mvl))
500 gtk_toggle_button_set_active (dialog->button_none, TRUE);
504 const struct missing_values *
505 psppire_missing_val_dialog_get_missing_values (
506 const PsppireMissingValDialog *dialog)