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 }