Re-added the help button callbacks
[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   connect_help (xml);
217
218   dialog->window = get_widget_assert (xml, "missing_values_dialog");
219
220   gtk_window_set_transient_for
221     (GTK_WINDOW (dialog->window),
222      GTK_WINDOW (get_widget_assert (xml, "data_editor")));
223
224
225   g_signal_connect_swapped (get_widget_assert (xml, "missing_val_cancel"),
226                    "clicked", G_CALLBACK (gtk_widget_hide), dialog->window);
227
228   g_signal_connect (get_widget_assert (xml, "missing_val_ok"),
229                    "clicked", G_CALLBACK (missing_val_dialog_accept), dialog);
230
231
232   dialog->mv[0] = get_widget_assert (xml, "mv0");
233   dialog->mv[1] = get_widget_assert (xml, "mv1");
234   dialog->mv[2] = get_widget_assert (xml, "mv2");
235
236   dialog->low = get_widget_assert (xml, "mv-low");
237   dialog->high = get_widget_assert (xml, "mv-high");
238   dialog->discrete = get_widget_assert (xml, "mv-discrete");
239
240
241   dialog->button_none     =
242     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "no_missing"));
243
244   dialog->button_discrete =
245     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "discrete_missing"));
246
247   dialog->button_range    =
248     GTK_TOGGLE_BUTTON (get_widget_assert (xml, "range_missing"));
249
250
251   g_signal_connect (G_OBJECT (dialog->button_discrete), "toggled",
252                    G_CALLBACK (discrete), dialog);
253
254   g_signal_connect (G_OBJECT (dialog->button_range), "toggled",
255                    G_CALLBACK (range), dialog);
256
257   return dialog;
258 }
259
260 /* Shows the dialog box and sets default values */
261 void
262 missing_val_dialog_show (struct missing_val_dialog *dialog)
263 {
264   const struct fmt_spec *write_spec ;
265
266   gint i;
267   g_return_if_fail (dialog);
268   g_return_if_fail (dialog->pv);
269
270   mv_copy (&dialog->mvl, var_get_missing_values (dialog->pv));
271
272   write_spec = var_get_write_format (dialog->pv);
273
274   /* Blank all entry boxes and make them insensitive */
275   gtk_entry_set_text (GTK_ENTRY (dialog->low), "");
276   gtk_entry_set_text (GTK_ENTRY (dialog->high), "");
277   gtk_entry_set_text (GTK_ENTRY (dialog->discrete), "");
278   gtk_widget_set_sensitive (dialog->low, FALSE);
279   gtk_widget_set_sensitive (dialog->high, FALSE);
280   gtk_widget_set_sensitive (dialog->discrete, FALSE);
281
282   gtk_widget_set_sensitive (GTK_WIDGET (dialog->button_range),
283                            var_is_numeric (dialog->pv));
284
285
286   for (i = 0 ; i < 3 ; ++i )
287     {
288       gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), "");
289       gtk_widget_set_sensitive (dialog->mv[i], FALSE);
290     }
291
292   if ( mv_has_range (&dialog->mvl))
293     {
294       union value low, high;
295       gchar *low_text;
296       gchar *high_text;
297       mv_peek_range (&dialog->mvl, &low.f, &high.f);
298
299       low_text = value_to_text (low, *write_spec);
300       high_text = value_to_text (high, *write_spec);
301
302       gtk_entry_set_text (GTK_ENTRY (dialog->low), low_text);
303       gtk_entry_set_text (GTK_ENTRY (dialog->high), high_text);
304       g_free (low_text);
305       g_free (high_text);
306
307       if ( mv_has_value (&dialog->mvl))
308         {
309           gchar *text;
310           union value value;
311           mv_peek_value (&dialog->mvl, &value, 0);
312           text = value_to_text (value, *write_spec);
313           gtk_entry_set_text (GTK_ENTRY (dialog->discrete), text);
314           g_free (text);
315         }
316
317       gtk_toggle_button_set_active (dialog->button_range, TRUE);
318       gtk_widget_set_sensitive (dialog->low, TRUE);
319       gtk_widget_set_sensitive (dialog->high, TRUE);
320       gtk_widget_set_sensitive (dialog->discrete, TRUE);
321
322     }
323   else if ( mv_has_value (&dialog->mvl))
324     {
325       const int n = mv_n_values (&dialog->mvl);
326
327       for (i = 0 ; i < 3 ; ++i )
328         {
329           if ( i < n)
330             {
331               gchar *text ;
332               union value value;
333
334               mv_peek_value (&dialog->mvl, &value, i);
335               text = value_to_text (value, *write_spec);
336               gtk_entry_set_text (GTK_ENTRY (dialog->mv[i]), text);
337               g_free (text);
338             }
339           gtk_widget_set_sensitive (dialog->mv[i], TRUE);
340         }
341       gtk_toggle_button_set_active (dialog->button_discrete, TRUE);
342     }
343   else if ( mv_is_empty (&dialog->mvl))
344     {
345       gtk_toggle_button_set_active (dialog->button_none, TRUE);
346     }
347
348   gtk_widget_show (dialog->window);
349 }