Changed include paths to be explicitly specified in the #include directive.
[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 *label = gtk_label_new (msg);
43
44   GtkWidget *dialog = 
45     gtk_dialog_new_with_buttons ("PSPP",
46                                  window,
47                                  GTK_DIALOG_MODAL | 
48                                  GTK_DIALOG_DESTROY_WITH_PARENT | 
49                                  GTK_DIALOG_NO_SEPARATOR,
50                                  GTK_STOCK_OK,
51                                  GTK_RESPONSE_ACCEPT,
52                                  NULL);
53
54
55   GtkWidget *icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR,
56                                              GTK_ICON_SIZE_DIALOG);
57    
58   g_signal_connect_swapped (dialog,
59                             "response", 
60                             G_CALLBACK (gtk_widget_destroy),
61                             dialog);
62
63   GtkWidget *hbox = gtk_hbox_new(FALSE, 10);
64
65   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
66                      hbox);
67
68   gtk_box_pack_start(GTK_BOX(hbox), icon, TRUE, FALSE, 10);
69   gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 10);
70
71   gtk_widget_show_all (dialog);
72 }
73
74
75 /* Callback which occurs when the OK button is clicked */
76 static void 
77 missing_val_dialog_accept(GtkWidget *w, gpointer data)
78 {
79   struct missing_val_dialog *dialog = data;
80
81   const struct fmt_spec *write_spec = psppire_variable_get_write_spec(dialog->pv);
82   
83   if ( gtk_toggle_button_get_active(dialog->button_discrete))
84     {
85       gint nvals = 0;
86       gint badvals = 0;
87       gint i;
88       mv_set_type(&dialog->mvl, MV_NONE);
89       for(i = 0 ; i < 3 ; ++i ) 
90         {
91           gchar *text = 
92             g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->mv[i])));
93
94           union value v;
95           if ( !text || strlen(g_strstrip(text)) == 0 )
96             {
97               g_free(text);
98               continue;
99             }
100
101           if ( text_to_value(text, &v, *write_spec))
102             {
103               nvals++;
104               mv_add_value (&dialog->mvl, &v);
105             }
106           else 
107               badvals++;
108           g_free(text);
109         }
110       if ( nvals == 0 || badvals > 0 ) 
111         {
112           err_dialog(_("Incorrect value for variable type"), 
113                      GTK_WINDOW(dialog->window));
114           return ;
115         }
116     }
117   
118   if (gtk_toggle_button_get_active(dialog->button_range))
119     {
120       
121       union value low_val ; 
122       union value high_val;
123       const gchar *low_text = gtk_entry_get_text(GTK_ENTRY(dialog->low));
124       const gchar *high_text = gtk_entry_get_text(GTK_ENTRY(dialog->high));
125
126       if ( text_to_value(low_text, &low_val, *write_spec)
127            && 
128            text_to_value(high_text, &high_val, *write_spec) ) 
129         {
130           if ( low_val.f > high_val.f ) 
131             {
132               err_dialog(_("Incorrect range specification"),
133                           GTK_WINDOW(dialog->window));
134               return ;
135             }
136         }
137       else
138         {
139           err_dialog(_("Incorrect range specification"),
140                       GTK_WINDOW(dialog->window));
141           return;
142         }
143
144       gchar *discrete_text = 
145         g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->discrete)));
146
147
148       mv_set_type(&dialog->mvl, MV_NONE);
149       mv_add_num_range(&dialog->mvl, low_val.f, high_val.f);
150       
151       if ( discrete_text && strlen(g_strstrip(discrete_text)) > 0 )
152         {
153           union value discrete_val;
154           if ( !text_to_value(discrete_text, &discrete_val, 
155                               *write_spec))
156             {
157               err_dialog(_("Incorrect value for variable type"),
158                          GTK_WINDOW(dialog->window) );
159               g_free(discrete_text);
160               return;
161             }
162           mv_add_value(&dialog->mvl, &discrete_val);
163         }
164       g_free(discrete_text);
165     }
166
167   
168   if (gtk_toggle_button_get_active(dialog->button_none))
169     mv_set_type(&dialog->mvl, MV_NONE);
170
171   psppire_variable_set_missing(dialog->pv, &dialog->mvl);
172
173   gtk_widget_hide(dialog->window);
174 }
175
176
177 /* Callback which occurs when the 'discrete' radiobutton is toggled */
178 static void 
179 discrete(GtkToggleButton *button, gpointer data)
180 {
181   gint i;
182   struct missing_val_dialog *dialog = data;
183
184   for(i = 0 ; i < 3 ; ++i ) 
185     {
186       gtk_widget_set_sensitive(dialog->mv[i], 
187                                gtk_toggle_button_get_active(button));
188     }
189 }
190
191 /* Callback which occurs when the 'range' radiobutton is toggled */
192 static void 
193 range(GtkToggleButton *button, gpointer data)
194 {
195   struct missing_val_dialog *dialog = data;
196   
197   const gboolean active = gtk_toggle_button_get_active (button);
198
199   gtk_widget_set_sensitive(dialog->low, active);      
200   gtk_widget_set_sensitive(dialog->high, active);      
201   gtk_widget_set_sensitive(dialog->discrete, active);   
202 }
203
204
205 /* Creates the dialog structure from the xml */
206 struct missing_val_dialog * 
207 missing_val_dialog_create(GladeXML *xml)
208 {
209   struct missing_val_dialog *dialog = g_malloc(sizeof(*dialog));
210
211   dialog->window = get_widget_assert(xml, "missing_values_dialog");
212
213   gtk_window_set_transient_for
214     (GTK_WINDOW(dialog->window), 
215      GTK_WINDOW(get_widget_assert(xml, "data_editor")));
216
217
218   g_signal_connect_swapped(get_widget_assert(xml, "missing_val_cancel"),
219                    "clicked", G_CALLBACK(gtk_widget_hide), dialog->window);
220
221   g_signal_connect(get_widget_assert(xml, "missing_val_ok"),
222                    "clicked", G_CALLBACK(missing_val_dialog_accept), dialog);
223
224
225   dialog->mv[0] = get_widget_assert(xml, "mv0");
226   dialog->mv[1] = get_widget_assert(xml, "mv1");
227   dialog->mv[2] = get_widget_assert(xml, "mv2");
228
229   dialog->low = get_widget_assert(xml, "mv-low");
230   dialog->high = get_widget_assert(xml, "mv-high");
231   dialog->discrete = get_widget_assert(xml, "mv-discrete");
232   
233
234   dialog->button_none     =  
235     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "no_missing"));
236
237   dialog->button_discrete =  
238     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "discrete_missing"));
239
240   dialog->button_range    =  
241     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "range_missing"));
242
243
244   g_signal_connect(G_OBJECT(dialog->button_discrete), "toggled", 
245                    G_CALLBACK(discrete), dialog);
246
247   g_signal_connect(G_OBJECT(dialog->button_range), "toggled", 
248                    G_CALLBACK(range), dialog);
249
250   return dialog;
251 }
252
253 /* Shows the dialog box and sets default values */
254 void 
255 missing_val_dialog_show(struct missing_val_dialog *dialog)
256 {
257   gint i;
258   g_return_if_fail(dialog);
259   g_return_if_fail(dialog->pv);
260
261   mv_copy (&dialog->mvl, psppire_variable_get_missing(dialog->pv));
262
263   const struct fmt_spec *write_spec = psppire_variable_get_write_spec(dialog->pv);
264
265   /* Blank all entry boxes and make them insensitive */
266   gtk_entry_set_text(GTK_ENTRY(dialog->low), "");
267   gtk_entry_set_text(GTK_ENTRY(dialog->high), "");
268   gtk_entry_set_text(GTK_ENTRY(dialog->discrete), "");   
269   gtk_widget_set_sensitive(dialog->low, FALSE);      
270   gtk_widget_set_sensitive(dialog->high, FALSE);      
271   gtk_widget_set_sensitive(dialog->discrete, FALSE);   
272
273   gtk_widget_set_sensitive(GTK_WIDGET(dialog->button_range), 
274                            psppire_variable_get_type(dialog->pv) == NUMERIC);
275
276   for(i = 0 ; i < 3 ; ++i ) 
277     {
278       gtk_entry_set_text(GTK_ENTRY(dialog->mv[i]), "");   
279       gtk_widget_set_sensitive(dialog->mv[i], FALSE);
280     }
281
282   if ( mv_has_range (&dialog->mvl))
283     {
284       union value low, high;
285       gchar *low_text;
286       gchar *high_text;
287       mv_peek_range(&dialog->mvl, &low.f, &high.f);
288
289       low_text = value_to_text(low, *write_spec);
290       high_text = value_to_text(high, *write_spec);
291       
292       gtk_entry_set_text(GTK_ENTRY(dialog->low), low_text);
293       gtk_entry_set_text(GTK_ENTRY(dialog->high), high_text);
294       g_free(low_text);
295       g_free(high_text);
296
297       if ( mv_has_value(&dialog->mvl))
298         {
299           gchar *text;
300           union value value;
301           mv_peek_value(&dialog->mvl, &value, 0);
302           text = value_to_text(value, *write_spec);
303           gtk_entry_set_text(GTK_ENTRY(dialog->discrete), text);
304           g_free(text);
305         }
306       
307       gtk_toggle_button_set_active(dialog->button_range, TRUE);
308       gtk_widget_set_sensitive(dialog->low, TRUE);      
309       gtk_widget_set_sensitive(dialog->high, TRUE);      
310       gtk_widget_set_sensitive(dialog->discrete, TRUE);   
311
312     }
313   else if ( mv_has_value (&dialog->mvl))
314     {
315       const int n = mv_n_values (&dialog->mvl);
316
317       for(i = 0 ; i < 3 ; ++i ) 
318         {
319           if ( i < n)
320             {
321               union value value;
322
323               mv_peek_value(&dialog->mvl, &value, i);
324               gchar *text = value_to_text(value, *write_spec);
325               gtk_entry_set_text(GTK_ENTRY(dialog->mv[i]), text);
326               g_free(text);
327             }
328           gtk_widget_set_sensitive(dialog->mv[i], TRUE);
329         }
330       gtk_toggle_button_set_active(dialog->button_discrete, TRUE);
331     }
332   else if ( mv_is_empty (&dialog->mvl))
333     {
334       gtk_toggle_button_set_active(dialog->button_none, TRUE);
335     }
336
337   gtk_widget_show(dialog->window);
338 }