Fixed a lot of internationalisation issues.
[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 <config.h>
25 #include <gettext.h>
26 #define _(msgid) gettext (msgid)
27 #define N_(msgid) msgid
28
29
30 #include "helper.h"
31 #include "missing-val-dialog.h"
32 #include <data/missing-values.h>
33 #include <data/variable.h>
34 #include <data/data-in.h>
35 #include "psppire-variable.h"
36
37 #include <gtk/gtk.h>
38 #include <glade/glade.h>
39
40 #include <string.h>
41
42
43 /* A simple (sub) dialog box for displaying user input errors */
44 static void
45 err_dialog(const gchar *msg, GtkWindow *window)
46 {
47   GtkWidget *hbox ;
48   GtkWidget *label = gtk_label_new (msg);
49
50   GtkWidget *dialog = 
51     gtk_dialog_new_with_buttons ("PSPP",
52                                  window,
53                                  GTK_DIALOG_MODAL | 
54                                  GTK_DIALOG_DESTROY_WITH_PARENT | 
55                                  GTK_DIALOG_NO_SEPARATOR,
56                                  GTK_STOCK_OK,
57                                  GTK_RESPONSE_ACCEPT,
58                                  NULL);
59
60
61   GtkWidget *icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_ERROR,
62                                              GTK_ICON_SIZE_DIALOG);
63    
64   g_signal_connect_swapped (dialog,
65                             "response", 
66                             G_CALLBACK (gtk_widget_destroy),
67                             dialog);
68
69   hbox = gtk_hbox_new(FALSE, 10);
70
71   gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
72                      hbox);
73
74   gtk_box_pack_start(GTK_BOX(hbox), icon, TRUE, FALSE, 10);
75   gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 10);
76
77   gtk_widget_show_all (dialog);
78 }
79
80
81 /* Callback which occurs when the OK button is clicked */
82 static void 
83 missing_val_dialog_accept(GtkWidget *w, gpointer data)
84 {
85   struct missing_val_dialog *dialog = data;
86
87   const struct fmt_spec *write_spec = psppire_variable_get_write_spec(dialog->pv);
88   
89   if ( gtk_toggle_button_get_active(dialog->button_discrete))
90     {
91       gint nvals = 0;
92       gint badvals = 0;
93       gint i;
94       mv_set_type(&dialog->mvl, MV_NONE);
95       for(i = 0 ; i < 3 ; ++i ) 
96         {
97           gchar *text = 
98             g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->mv[i])));
99
100           union value v;
101           if ( !text || strlen(g_strstrip(text)) == 0 )
102             {
103               g_free(text);
104               continue;
105             }
106
107           if ( text_to_value(text, &v, *write_spec))
108             {
109               nvals++;
110               mv_add_value (&dialog->mvl, &v);
111             }
112           else 
113               badvals++;
114           g_free(text);
115         }
116       if ( nvals == 0 || badvals > 0 ) 
117         {
118           err_dialog(_("Incorrect value for variable type"), 
119                      GTK_WINDOW(dialog->window));
120           return ;
121         }
122     }
123   
124   if (gtk_toggle_button_get_active(dialog->button_range))
125     {
126       gchar *discrete_text ;
127       
128       union value low_val ; 
129       union value high_val;
130       const gchar *low_text = gtk_entry_get_text(GTK_ENTRY(dialog->low));
131       const gchar *high_text = gtk_entry_get_text(GTK_ENTRY(dialog->high));
132
133       if ( text_to_value(low_text, &low_val, *write_spec)
134            && 
135            text_to_value(high_text, &high_val, *write_spec) ) 
136         {
137           if ( low_val.f > high_val.f ) 
138             {
139               err_dialog(_("Incorrect range specification"),
140                           GTK_WINDOW(dialog->window));
141               return ;
142             }
143         }
144       else
145         {
146           err_dialog(_("Incorrect range specification"),
147                       GTK_WINDOW(dialog->window));
148           return;
149         }
150
151       discrete_text = 
152         g_strdup(gtk_entry_get_text(GTK_ENTRY(dialog->discrete)));
153
154       mv_set_type(&dialog->mvl, MV_NONE);
155       mv_add_num_range(&dialog->mvl, low_val.f, high_val.f);
156       
157       if ( discrete_text && strlen(g_strstrip(discrete_text)) > 0 )
158         {
159           union value discrete_val;
160           if ( !text_to_value(discrete_text, &discrete_val, 
161                               *write_spec))
162             {
163               err_dialog(_("Incorrect value for variable type"),
164                          GTK_WINDOW(dialog->window) );
165               g_free(discrete_text);
166               return;
167             }
168           mv_add_value(&dialog->mvl, &discrete_val);
169         }
170       g_free(discrete_text);
171     }
172
173   
174   if (gtk_toggle_button_get_active(dialog->button_none))
175     mv_set_type(&dialog->mvl, MV_NONE);
176
177   psppire_variable_set_missing(dialog->pv, &dialog->mvl);
178
179   gtk_widget_hide(dialog->window);
180 }
181
182
183 /* Callback which occurs when the 'discrete' radiobutton is toggled */
184 static void 
185 discrete(GtkToggleButton *button, gpointer data)
186 {
187   gint i;
188   struct missing_val_dialog *dialog = data;
189
190   for(i = 0 ; i < 3 ; ++i ) 
191     {
192       gtk_widget_set_sensitive(dialog->mv[i], 
193                                gtk_toggle_button_get_active(button));
194     }
195 }
196
197 /* Callback which occurs when the 'range' radiobutton is toggled */
198 static void 
199 range(GtkToggleButton *button, gpointer data)
200 {
201   struct missing_val_dialog *dialog = data;
202   
203   const gboolean active = gtk_toggle_button_get_active (button);
204
205   gtk_widget_set_sensitive(dialog->low, active);      
206   gtk_widget_set_sensitive(dialog->high, active);      
207   gtk_widget_set_sensitive(dialog->discrete, active);   
208 }
209
210
211 /* Creates the dialog structure from the xml */
212 struct missing_val_dialog * 
213 missing_val_dialog_create(GladeXML *xml)
214 {
215   struct missing_val_dialog *dialog = g_malloc(sizeof(*dialog));
216
217   dialog->window = get_widget_assert(xml, "missing_values_dialog");
218
219   gtk_window_set_transient_for
220     (GTK_WINDOW(dialog->window), 
221      GTK_WINDOW(get_widget_assert(xml, "data_editor")));
222
223
224   g_signal_connect_swapped(get_widget_assert(xml, "missing_val_cancel"),
225                    "clicked", G_CALLBACK(gtk_widget_hide), dialog->window);
226
227   g_signal_connect(get_widget_assert(xml, "missing_val_ok"),
228                    "clicked", G_CALLBACK(missing_val_dialog_accept), dialog);
229
230
231   dialog->mv[0] = get_widget_assert(xml, "mv0");
232   dialog->mv[1] = get_widget_assert(xml, "mv1");
233   dialog->mv[2] = get_widget_assert(xml, "mv2");
234
235   dialog->low = get_widget_assert(xml, "mv-low");
236   dialog->high = get_widget_assert(xml, "mv-high");
237   dialog->discrete = get_widget_assert(xml, "mv-discrete");
238   
239
240   dialog->button_none     =  
241     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "no_missing"));
242
243   dialog->button_discrete =  
244     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "discrete_missing"));
245
246   dialog->button_range    =  
247     GTK_TOGGLE_BUTTON(get_widget_assert(xml, "range_missing"));
248
249
250   g_signal_connect(G_OBJECT(dialog->button_discrete), "toggled", 
251                    G_CALLBACK(discrete), dialog);
252
253   g_signal_connect(G_OBJECT(dialog->button_range), "toggled", 
254                    G_CALLBACK(range), dialog);
255
256   return dialog;
257 }
258
259 /* Shows the dialog box and sets default values */
260 void 
261 missing_val_dialog_show(struct missing_val_dialog *dialog)
262 {
263   const struct fmt_spec *write_spec ;
264
265   gint i;
266   g_return_if_fail(dialog);
267   g_return_if_fail(dialog->pv);
268
269   mv_copy (&dialog->mvl, psppire_variable_get_missing(dialog->pv));
270
271   write_spec = psppire_variable_get_write_spec(dialog->pv);
272
273   /* Blank all entry boxes and make them insensitive */
274   gtk_entry_set_text(GTK_ENTRY(dialog->low), "");
275   gtk_entry_set_text(GTK_ENTRY(dialog->high), "");
276   gtk_entry_set_text(GTK_ENTRY(dialog->discrete), "");   
277   gtk_widget_set_sensitive(dialog->low, FALSE);      
278   gtk_widget_set_sensitive(dialog->high, FALSE);      
279   gtk_widget_set_sensitive(dialog->discrete, FALSE);   
280
281   gtk_widget_set_sensitive(GTK_WIDGET(dialog->button_range), 
282                            psppire_variable_get_type(dialog->pv) == NUMERIC);
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 }