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