Whitespace changes only.
[pspp-builds.git] / src / ui / gui / missing-val-dialog.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2005, 2006  Free Software Foundation
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18     02110-1301, USA. */
19
20 /*  This module describes the behaviour of the Missing Values dialog box,
21     used for input of the missing values in the variable sheet */
22
23 #include <config.h>
24 #include <gettext.h>
25 #define _(msgid) gettext (msgid)
26 #define N_(msgid) msgid
27
28
29 #include "helper.h"
30 #include "missing-val-dialog.h"
31 #include <data/missing-values.h>
32 #include <data/variable.h>
33 #include <data/data-in.h>
34
35
36 #include <gtk/gtk.h>
37 #include <glade/glade.h>
38
39 #include <string.h>
40
41
42 /* A simple (sub) dialog box for displaying user input errors */
43 static void
44 err_dialog (const gchar *msg, GtkWindow *window)
45 {
46   GtkWidget *hbox ;
47   GtkWidget *label = gtk_label_new (msg);
48
49   GtkWidget *dialog =
50     gtk_dialog_new_with_buttons ("PSPP",
51                                  window,
52                                  GTK_DIALOG_MODAL |
53                                  GTK_DIALOG_DESTROY_WITH_PARENT |
54                                  GTK_DIALOG_NO_SEPARATOR,
55                                  GTK_STOCK_OK,
56                                  GTK_RESPONSE_ACCEPT,
57                                  NULL);
58
59
60   GtkWidget *icon = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
61                                              GTK_ICON_SIZE_DIALOG);
62
63   g_signal_connect_swapped (dialog,
64                             "response",
65                             G_CALLBACK (gtk_widget_destroy),
66                             dialog);
67
68   hbox = gtk_hbox_new (FALSE, 10);
69
70   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox),
71                      hbox);
72
73   gtk_box_pack_start (GTK_BOX (hbox), icon, TRUE, FALSE, 10);
74   gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 10);
75
76   gtk_widget_show_all (dialog);
77 }
78
79
80 /* Callback which occurs when the OK button is clicked */
81 static void
82 missing_val_dialog_accept (GtkWidget *w, gpointer data)
83 {
84   struct missing_val_dialog *dialog = data;
85
86   const struct fmt_spec *write_spec = var_get_write_format (dialog->pv);
87
88   if ( gtk_toggle_button_get_active (dialog->button_discrete))
89     {
90       gint nvals = 0;
91       gint badvals = 0;
92       gint i;
93       mv_clear (&dialog->mvl);
94       for (i = 0 ; i < 3 ; ++i )
95         {
96           gchar *text =
97             g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->mv[i])));
98
99           union value v;
100           if ( !text || strlen (g_strstrip (text)) == 0 )
101             {
102               g_free (text);
103               continue;
104             }
105
106           if ( text_to_value (text, &v, *write_spec))
107             {
108               nvals++;
109               mv_add_value (&dialog->mvl, &v);
110             }
111           else
112               badvals++;
113           g_free (text);
114         }
115       if ( nvals == 0 || badvals > 0 )
116         {
117           err_dialog (_("Incorrect value for variable type"),
118                      GTK_WINDOW (dialog->window));
119           return ;
120         }
121     }
122
123   if (gtk_toggle_button_get_active (dialog->button_range))
124     {
125       gchar *discrete_text ;
126
127       union value low_val ;
128       union value high_val;
129       const gchar *low_text = gtk_entry_get_text (GTK_ENTRY (dialog->low));
130       const gchar *high_text = gtk_entry_get_text (GTK_ENTRY (dialog->high));
131
132       if ( text_to_value (low_text, &low_val, *write_spec)
133            &&
134            text_to_value (high_text, &high_val, *write_spec) )
135         {
136           if ( low_val.f > high_val.f )
137             {
138               err_dialog (_("Incorrect range specification"),
139                           GTK_WINDOW (dialog->window));
140               return ;
141             }
142         }
143       else
144         {
145           err_dialog (_("Incorrect range specification"),
146                       GTK_WINDOW (dialog->window));
147           return;
148         }
149
150       discrete_text =
151         g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->discrete)));
152
153       mv_clear (&dialog->mvl);
154       mv_add_num_range (&dialog->mvl, low_val.f, high_val.f);
155
156       if ( discrete_text && strlen (g_strstrip (discrete_text)) > 0 )
157         {
158           union value discrete_val;
159           if ( !text_to_value (discrete_text, &discrete_val,
160                               *write_spec))
161             {
162               err_dialog (_("Incorrect value for variable type"),
163                          GTK_WINDOW (dialog->window) );
164               g_free (discrete_text);
165               return;
166             }
167           mv_add_value (&dialog->mvl, &discrete_val);
168         }
169       g_free (discrete_text);
170     }
171
172
173   if (gtk_toggle_button_get_active (dialog->button_none))
174     mv_clear (&dialog->mvl);
175
176   var_set_missing_values (dialog->pv, &dialog->mvl);
177
178   gtk_widget_hide (dialog->window);
179 }
180
181
182 /* Callback which occurs when the 'discrete' radiobutton is toggled */
183 static void
184 discrete (GtkToggleButton *button, gpointer data)
185 {
186   gint i;
187   struct missing_val_dialog *dialog = data;
188
189   for (i = 0 ; i < 3 ; ++i )
190     {
191       gtk_widget_set_sensitive (dialog->mv[i],
192                                gtk_toggle_button_get_active (button));
193     }
194 }
195
196 /* Callback which occurs when the 'range' radiobutton is toggled */
197 static void
198 range (GtkToggleButton *button, gpointer data)
199 {
200   struct missing_val_dialog *dialog = data;
201
202   const gboolean active = gtk_toggle_button_get_active (button);
203
204   gtk_widget_set_sensitive (dialog->low, active);
205   gtk_widget_set_sensitive (dialog->high, active);
206   gtk_widget_set_sensitive (dialog->discrete, active);
207 }
208
209
210 /* Creates the dialog structure from the xml */
211 struct missing_val_dialog *
212 missing_val_dialog_create (GladeXML *xml)
213 {
214   struct missing_val_dialog *dialog = g_malloc (sizeof (*dialog));
215
216   dialog->window = get_widget_assert (xml, "missing_values_dialog");
217
218   gtk_window_set_transient_for
219     (GTK_WINDOW (dialog->window),
220      GTK_WINDOW (get_widget_assert (xml, "data_editor")));
221
222
223   g_signal_connect_swapped (get_widget_assert (xml, "missing_val_cancel"),
224                    "clicked", G_CALLBACK (gtk_widget_hide), dialog->window);
225
226   g_signal_connect (get_widget_assert (xml, "missing_val_ok"),
227                    "clicked", G_CALLBACK (missing_val_dialog_accept), dialog);
228
229
230   dialog->mv[0] = get_widget_assert (xml, "mv0");
231   dialog->mv[1] = get_widget_assert (xml, "mv1");
232   dialog->mv[2] = get_widget_assert (xml, "mv2");
233
234   dialog->low = get_widget_assert (xml, "mv-low");
235   dialog->high = get_widget_assert (xml, "mv-high");
236   dialog->discrete = get_widget_assert (xml, "mv-discrete");
237
238
239   dialog->button_none     =
240     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
241
242   dialog->button_discrete =
243     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
244
245   dialog->button_range    =
246     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
247
248
249   g_signal_connect (G_OBJECT (dialog->button_discrete), "toggled",
250                    G_CALLBACK (discrete), dialog);
251
252   g_signal_connect (G_OBJECT (dialog->button_range), "toggled",
253                    G_CALLBACK (range), dialog);
254
255   return dialog;
256 }
257
258 /* Shows the dialog box and sets default values */
259 void
260 missing_val_dialog_show (struct missing_val_dialog *dialog)
261 {
262   const struct fmt_spec *write_spec ;
263
264   gint i;
265   g_return_if_fail (dialog);
266   g_return_if_fail (dialog->pv);
267
268   mv_copy (&dialog->mvl, var_get_missing_values (dialog->pv));
269
270   write_spec = var_get_write_format (dialog->pv);
271
272   /* Blank all entry boxes and make them insensitive */
273   gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
274   gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
275   gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
276   gtk_widget_set_sensitive (dialog->low, FALSE);
277   gtk_widget_set_sensitive (dialog->high, FALSE);
278   gtk_widget_set_sensitive (dialog->discrete, FALSE);
279
280   gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
281                            var_is_numeric (dialog->pv));
282
283
284   for (i = 0 ; i < 3 ; ++i )
285     {
286       gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
287       gtk_widget_set_sensitive (dialog->mv[i], FALSE);
288     }
289
290   if ( mv_has_range (&dialog->mvl))
291     {
292       union value low, high;
293       gchar *low_text;
294       gchar *high_text;
295       mv_peek_range (&dialog->mvl, &low.f, &high.f);
296
297       low_text = value_to_text (low, *write_spec);
298       high_text = value_to_text (high, *write_spec);
299
300       gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
301       gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
302       g_free (low_text);
303       g_free (high_text);
304
305       if ( mv_has_value (&dialog->mvl))
306         {
307           gchar *text;
308           union value value;
309           mv_peek_value (&dialog->mvl, &value, 0);
310           text = value_to_text (value, *write_spec);
311           gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
312           g_free (text);
313         }
314
315       gtk_toggle_button_set_active (dialog->button_range, TRUE);
316       gtk_widget_set_sensitive (dialog->low, TRUE);
317       gtk_widget_set_sensitive (dialog->high, TRUE);
318       gtk_widget_set_sensitive (dialog->discrete, TRUE);
319
320     }
321   else if ( mv_has_value (&dialog->mvl))
322     {
323       const int n = mv_n_values (&dialog->mvl);
324
325       for (i = 0 ; i < 3 ; ++i )
326         {
327           if ( i < n)
328             {
329               gchar *text ;
330               union value value;
331
332               mv_peek_value (&dialog->mvl, &value, i);
333               text = value_to_text (value, *write_spec);
334               gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
335               g_free (text);
336             }
337           gtk_widget_set_sensitive (dialog->mv[i], TRUE);
338         }
339       gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
340     }
341   else if ( mv_is_empty (&dialog->mvl))
342     {
343       gtk_toggle_button_set_active (dialog->button_none, TRUE);
344     }
345
346   gtk_widget_show (dialog->window);
347 }