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,
193 GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
194 GTK_ICON_SIZE_DIALOG);
196 g_signal_connect_swapped (dialog,
198 G_CALLBACK (gtk_widget_destroy),
201 hbox = gtk_hbox_new (FALSE, 10);
203 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
206 gtk_box_pack_start (GTK_BOX (hbox), icon, TRUE, FALSE, 10);
207 gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
209 gtk_widget_show_all (dialog);
213 /* Acceptability predicate for PsppireMissingValDialog.
215 This function is also the only place that dialog->mvl gets updated. */
217 missing_val_dialog_acceptable (gpointer data)
219 PsppireMissingValDialog *dialog = data;
221 if ( gtk_toggle_button_get_active (dialog->button_discrete))
226 mv_clear(&dialog->mvl);
227 for(i = 0 ; i < 3 ; ++i )
230 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
233 if ( !text || strlen (g_strstrip (text)) == 0 )
239 if ( text_to_value__ (text, &dialog->format, dialog->encoding, &v))
242 mv_add_value (&dialog->mvl, &v);
247 value_destroy (&v, fmt_var_width (&dialog->format));
249 if ( nvals == 0 || badvals > 0 )
251 err_dialog (_("Incorrect value for variable type"),
252 GTK_WINDOW (dialog));
257 if (gtk_toggle_button_get_active (dialog->button_range))
259 gchar *discrete_text ;
261 union value low_val ;
262 union value high_val;
263 const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
264 const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
269 low_ok = text_to_value__ (low_text, &dialog->format, dialog->encoding,
271 high_ok = text_to_value__ (high_text, &dialog->format, dialog->encoding,
273 ok = low_ok && high_ok && low_val.f <= high_val.f;
276 err_dialog (_("Incorrect range specification"), GTK_WINDOW (dialog));
278 value_destroy (&low_val, fmt_var_width (&dialog->format));
280 value_destroy (&high_val, fmt_var_width (&dialog->format));
285 g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
287 mv_clear (&dialog->mvl);
288 mv_add_range (&dialog->mvl, low_val.f, high_val.f);
290 value_destroy (&low_val, fmt_var_width (&dialog->format));
291 value_destroy (&high_val, fmt_var_width (&dialog->format));
293 if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
295 union value discrete_val;
296 if ( !text_to_value__ (discrete_text,
301 err_dialog (_("Incorrect value for variable type"),
302 GTK_WINDOW (dialog) );
303 g_free (discrete_text);
304 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
307 mv_add_value (&dialog->mvl, &discrete_val);
308 value_destroy (&discrete_val, fmt_var_width (&dialog->format));
310 g_free (discrete_text);
314 if (gtk_toggle_button_get_active (dialog->button_none))
315 mv_clear (&dialog->mvl);
321 /* Callback which occurs when the 'discrete' radiobutton is toggled */
323 discrete (GtkToggleButton *button, gpointer data)
326 PsppireMissingValDialog *dialog = data;
328 for (i = 0 ; i < 3 ; ++i )
330 gtk_widget_set_sensitive (dialog->mv[i],
331 gtk_toggle_button_get_active (button));
335 /* Callback which occurs when the 'range' radiobutton is toggled */
337 range (GtkToggleButton *button, gpointer data)
339 PsppireMissingValDialog *dialog = data;
341 const gboolean active = gtk_toggle_button_get_active (button);
343 gtk_widget_set_sensitive (dialog->low, active);
344 gtk_widget_set_sensitive (dialog->high, active);
345 gtk_widget_set_sensitive (dialog->discrete, active);
350 /* Shows the dialog box and sets default values */
352 psppire_missing_val_dialog_constructor (GType type,
354 GObjectConstructParam *properties)
356 PsppireMissingValDialog *dialog;
357 GtkContainer *content_area;
361 obj = G_OBJECT_CLASS (psppire_missing_val_dialog_parent_class)->constructor (
362 type, n_properties, properties);
363 dialog = PSPPIRE_MISSING_VAL_DIALOG (obj);
365 content_area = GTK_CONTAINER (PSPPIRE_DIALOG (dialog)->box);
366 xml = builder_new ("missing-val-dialog.ui");
367 gtk_container_add (GTK_CONTAINER (content_area),
368 get_widget_assert (xml, "missing-values-dialog"));
370 dialog->mv[0] = get_widget_assert (xml, "mv0");
371 dialog->mv[1] = get_widget_assert (xml, "mv1");
372 dialog->mv[2] = get_widget_assert (xml, "mv2");
374 dialog->low = get_widget_assert (xml, "mv-low");
375 dialog->high = get_widget_assert (xml, "mv-high");
376 dialog->discrete = get_widget_assert (xml, "mv-discrete");
379 dialog->button_none =
380 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
382 dialog->button_discrete =
383 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
385 dialog->button_range =
386 GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
388 psppire_dialog_set_accept_predicate (PSPPIRE_DIALOG (dialog),
389 missing_val_dialog_acceptable,
392 g_signal_connect (dialog->button_discrete, "toggled",
393 G_CALLBACK (discrete), dialog);
395 g_signal_connect (dialog->button_range, "toggled",
396 G_CALLBACK (range), dialog);
398 g_object_unref (xml);
404 psppire_missing_val_dialog_set_variable (PsppireMissingValDialog *dialog,
405 const struct variable *var)
407 enum val_type var_type;
410 mv_destroy (&dialog->mvl);
411 g_free (dialog->encoding);
415 mv_copy (&dialog->mvl, var_get_missing_values (var));
416 dialog->encoding = g_strdup (var_get_encoding (var));
417 dialog->format = *var_get_print_format (var);
421 mv_init (&dialog->mvl, 0);
422 dialog->encoding = NULL;
423 dialog->format = F_8_0;
426 /* Blank all entry boxes and make them insensitive */
427 gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
428 gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
429 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
430 gtk_widget_set_sensitive (dialog->low, FALSE);
431 gtk_widget_set_sensitive (dialog->high, FALSE);
432 gtk_widget_set_sensitive (dialog->discrete, FALSE);
434 var_type = val_type_from_width (fmt_var_width (&dialog->format));
435 gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
436 var_type == VAL_NUMERIC);
441 for (i = 0 ; i < 3 ; ++i )
443 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
444 gtk_widget_set_sensitive (dialog->mv[i], FALSE);
447 if ( mv_has_range (&dialog->mvl))
449 union value low, high;
452 mv_get_range (&dialog->mvl, &low.f, &high.f);
455 low_text = value_to_text__ (low, &dialog->format, dialog->encoding);
456 high_text = value_to_text__ (high, &dialog->format, dialog->encoding);
458 gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
459 gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
463 if ( mv_has_value (&dialog->mvl))
466 text = value_to_text__ (*mv_get_value (&dialog->mvl, 0),
467 &dialog->format, dialog->encoding);
468 gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
472 gtk_toggle_button_set_active (dialog->button_range, TRUE);
473 gtk_widget_set_sensitive (dialog->low, TRUE);
474 gtk_widget_set_sensitive (dialog->high, TRUE);
475 gtk_widget_set_sensitive (dialog->discrete, TRUE);
478 else if ( mv_has_value (&dialog->mvl))
480 const int n = mv_n_values (&dialog->mvl);
482 for (i = 0 ; i < 3 ; ++i )
488 text = value_to_text__ (*mv_get_value (&dialog->mvl, i),
489 &dialog->format, dialog->encoding);
490 gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
493 gtk_widget_set_sensitive (dialog->mv[i], TRUE);
495 gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
497 else if ( mv_is_empty (&dialog->mvl))
499 gtk_toggle_button_set_active (dialog->button_none, TRUE);
503 const struct missing_values *
504 psppire_missing_val_dialog_get_missing_values (
505 const PsppireMissingValDialog *dialog)