find-dialog.c: Replace exp10 with our own integer version
[pspp] / src / ui / gui / psppire-buttonbox.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007, 2010, 2011, 2012  Free Software Foundation
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17
18 #include <config.h>
19
20 #include <glib.h>
21 #include <gtk/gtk.h>
22 #include "psppire-buttonbox.h"
23 #include "psppire-dialog.h"
24
25 #include "helper.h"
26
27 #include <gettext.h>
28
29 #define _(msgid) gettext (msgid)
30 #define N_(msgid) msgid
31
32 GType psppire_button_flags_get_type (void);
33
34
35 static void psppire_button_box_class_init          (PsppireButtonboxClass *);
36 static void psppire_button_box_init                (PsppireButtonbox      *);
37
38
39 GType
40 psppire_buttonbox_get_type (void)
41 {
42   static GType button_box_type = 0;
43
44   if (!button_box_type)
45     {
46       static const GTypeInfo button_box_info =
47       {
48         sizeof (PsppireButtonboxClass),
49         NULL, /* base_init */
50         NULL, /* base_finalize */
51         (GClassInitFunc) psppire_button_box_class_init,
52         NULL, /* class_finalize */
53         NULL, /* class_data */
54         sizeof (PsppireButtonbox),
55         0,
56         (GInstanceInitFunc) psppire_button_box_init,
57       };
58
59       button_box_type = g_type_register_static (GTK_TYPE_BUTTON_BOX,
60                                             "PsppireButtonbox", &button_box_info, 0);
61     }
62
63   return button_box_type;
64 }
65
66 enum {
67   PROP_BUTTONS = 1,
68   PROP_DEFAULT = 2
69 };
70
71 static void
72 set_default (PsppireButtonbox *bb)
73 {
74   int i;
75
76   for (i = 0 ; i < n_PsppireButtonboxButtons ; ++i)
77     if (bb->def == (1 << i))
78       {
79         gtk_widget_set_can_default (bb->button[i], TRUE);
80         gtk_widget_grab_default (bb->button[i]);
81       }
82 }
83
84 static void
85 psppire_buttonbox_set_property (GObject         *object,
86                                 guint            prop_id,
87                                 const GValue    *value,
88                                 GParamSpec      *pspec)
89 {
90   gint i;
91   guint flags;
92   PsppireButtonbox *bb = PSPPIRE_BUTTONBOX (object);
93
94   switch (prop_id)
95     {
96     case PROP_BUTTONS:
97       flags = g_value_get_flags (value);
98       for (i = 0 ; i < n_PsppireButtonboxButtons ; ++i)
99         g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
100       break;
101
102     case PROP_DEFAULT:
103       bb->def = g_value_get_flags (value);
104       if (gtk_widget_get_realized (GTK_WIDGET (bb)))
105         set_default (bb);
106       break;
107
108     default:
109       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
110     }
111 }
112
113 static void
114 psppire_buttonbox_get_property (GObject         *object,
115                                 guint            prop_id,
116                                 GValue          *value,
117                                 GParamSpec      *pspec)
118 {
119   guint flags = 0;
120   gint i;
121
122   PsppireButtonbox *bb = PSPPIRE_BUTTONBOX (object);
123
124   switch (prop_id)
125     {
126     case PROP_BUTTONS:
127       for (i = 0 ; i < n_PsppireButtonboxButtons ; ++i)
128         {
129           gboolean visibility;
130           g_object_get (bb->button[i], "visible", &visibility, NULL);
131
132           if (visibility)
133             flags |= (0x01 << i);
134         }
135
136       g_value_set_flags (value, flags);
137       break;
138
139     case PROP_DEFAULT:
140       g_value_set_flags (value, bb->def);
141
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144       break;
145     }
146 }
147
148
149 typedef enum
150   {
151     PSPPIRE_BUTTON_OK_MASK     = (1 << PSPPIRE_BUTTON_OK),
152     PSPPIRE_BUTTON_GOTO_MASK   = (1 << PSPPIRE_BUTTON_GOTO),
153     PSPPIRE_BUTTON_CONTINUE_MASK = (1 << PSPPIRE_BUTTON_CONTINUE),
154     PSPPIRE_BUTTON_CANCEL_MASK = (1 << PSPPIRE_BUTTON_CANCEL),
155     PSPPIRE_BUTTON_CLOSE_MASK  = (1 << PSPPIRE_BUTTON_CLOSE),
156     PSPPIRE_BUTTON_HELP_MASK   = (1 << PSPPIRE_BUTTON_HELP),
157     PSPPIRE_BUTTON_RESET_MASK  = (1 << PSPPIRE_BUTTON_RESET),
158     PSPPIRE_BUTTON_PASTE_MASK  = (1 << PSPPIRE_BUTTON_PASTE)
159   } PsppireButtonMask;
160
161 static GParamSpec *button_flags;
162 static GParamSpec *default_flags;
163
164 static void
165 psppire_button_box_class_init (PsppireButtonboxClass *class)
166 {
167   GObjectClass *object_class = G_OBJECT_CLASS (class);
168
169   object_class->set_property = psppire_buttonbox_set_property;
170   object_class->get_property = psppire_buttonbox_get_property;
171
172   button_flags =
173     g_param_spec_flags ("buttons",
174                         "Buttons",
175                         "The mask that decides what buttons appear in the button box",
176                         PSPPIRE_TYPE_BUTTON_MASK,
177                         PSPPIRE_BUTTON_OK_MASK |
178                         PSPPIRE_BUTTON_CANCEL_MASK |
179                         PSPPIRE_BUTTON_RESET_MASK |
180                         PSPPIRE_BUTTON_HELP_MASK |
181                         PSPPIRE_BUTTON_PASTE_MASK,
182                         G_PARAM_READWRITE);
183   g_object_class_install_property (object_class,
184                                    PROP_BUTTONS,
185                                    button_flags);
186
187   default_flags =
188     g_param_spec_flags ("default",
189                         "Default",
190                         "The mask that decides what what button grabs the default",
191                         PSPPIRE_TYPE_BUTTON_MASK,
192                         0,
193                         G_PARAM_READWRITE);
194   g_object_class_install_property (object_class,
195                                    PROP_DEFAULT,
196                                    default_flags);
197 }
198
199 static void
200 close_and_respond (GtkWidget *w, gint response)
201 {
202   PsppireDialog *dialog;
203
204   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
205
206   /* If we're not in a psppire dialog (for example when in glade)
207      then do nothing */
208   if (! PSPPIRE_IS_DIALOG (toplevel))
209     return;
210
211   dialog = PSPPIRE_DIALOG (toplevel);
212
213   dialog->response = response;
214
215   psppire_dialog_close (dialog);
216 }
217
218 static gboolean
219 is_acceptable (GtkWidget *w)
220 {
221   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
222
223   return (PSPPIRE_IS_DIALOG (toplevel)
224           && psppire_dialog_is_acceptable (PSPPIRE_DIALOG (toplevel)));
225 }
226
227 static void
228 close_dialog (GtkWidget *w, gpointer data)
229 {
230   close_and_respond (w, GTK_RESPONSE_CLOSE);
231 }
232
233 static void
234 continue_button_clicked (GtkWidget *w, gpointer data)
235 {
236   if (is_acceptable (w))
237     close_and_respond (w, PSPPIRE_RESPONSE_CONTINUE);
238 }
239
240
241 static void
242 ok_button_clicked (GtkWidget *w, gpointer data)
243 {
244   if (is_acceptable (w))
245     close_and_respond (w, GTK_RESPONSE_OK);
246 }
247
248
249 static void
250 paste_button_clicked (GtkWidget *w, gpointer data)
251 {
252   if (is_acceptable (w))
253     close_and_respond (w, PSPPIRE_RESPONSE_PASTE);
254 }
255
256 static void
257 goto_button_clicked (GtkWidget *w, gpointer data)
258 {
259   if (is_acceptable (w))
260     close_and_respond (w, PSPPIRE_RESPONSE_GOTO);
261 }
262
263
264 static void
265 refresh_clicked (GtkWidget *w, gpointer data)
266 {
267   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
268   PsppireDialog *dialog;
269
270   if (! PSPPIRE_IS_DIALOG (toplevel))
271     return;
272
273   dialog = PSPPIRE_DIALOG (toplevel);
274
275   psppire_dialog_reload (dialog);
276 }
277
278 static void
279 help_clicked (GtkWidget *w, gpointer data)
280 {
281   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
282   PsppireDialog *dialog;
283
284   if (! PSPPIRE_IS_DIALOG (toplevel))
285     return;
286
287   dialog = PSPPIRE_DIALOG (toplevel);
288
289   psppire_dialog_help (dialog);
290 }
291
292 static void
293 on_validity_change (GtkWidget *toplevel, gboolean valid, gpointer data)
294 {
295   PsppireButtonbox *bb = data;
296
297   /* Set the sensitivity of all the 'executive order' buttons */
298   gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_OK]), valid);
299   gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_PASTE]), valid);
300   gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_GOTO]), valid);
301   gtk_widget_set_sensitive (GTK_WIDGET (bb->button[PSPPIRE_BUTTON_CONTINUE]), valid);
302 }
303
304 static gboolean
305 on_key_press (GtkWidget *w, GdkEventKey *e, gpointer ud)
306 {
307   PsppireButtonbox *bb = PSPPIRE_BUTTONBOX (ud);
308   if (e->keyval == GDK_KEY_Escape)
309     {
310       g_signal_emit_by_name (bb->button[PSPPIRE_BUTTON_CANCEL], "activate");
311       g_signal_emit_by_name (bb->button[PSPPIRE_BUTTON_CLOSE], "activate");
312     }
313   return FALSE;
314 }
315
316
317 static void
318 on_realize (GtkWidget *buttonbox, gpointer data)
319 {
320   GtkWidget *toplevel = gtk_widget_get_toplevel (buttonbox);
321
322   if (PSPPIRE_IS_DIALOG (toplevel))
323     {
324       g_signal_connect (toplevel, "validity-changed",
325                         G_CALLBACK (on_validity_change), buttonbox);
326
327       g_signal_connect (toplevel, "key-press-event",
328                         G_CALLBACK (on_key_press), buttonbox);
329     }
330
331   set_default (PSPPIRE_BUTTONBOX (buttonbox));
332 }
333
334
335 static void
336 psppire_button_box_init (PsppireButtonbox *bb)
337 {
338   bb->def = PSPPIRE_BUTTON_CONTINUE;
339
340   bb->button[PSPPIRE_BUTTON_OK] = gtk_button_new_with_label (_("OK"));
341   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_OK]);
342   g_signal_connect (bb->button[PSPPIRE_BUTTON_OK], "clicked",
343                     G_CALLBACK (ok_button_clicked), NULL);
344   g_object_set (bb->button[PSPPIRE_BUTTON_OK], "no-show-all", TRUE, NULL);
345
346
347   bb->button[PSPPIRE_BUTTON_GOTO] =
348     gtk_button_new_with_label (_("Go To"));
349   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_GOTO]);
350   g_signal_connect (bb->button[PSPPIRE_BUTTON_GOTO], "clicked",
351                     G_CALLBACK (goto_button_clicked), NULL);
352   g_object_set (bb->button[PSPPIRE_BUTTON_GOTO], "no-show-all", TRUE, NULL);
353
354
355   bb->button[PSPPIRE_BUTTON_CONTINUE] =
356     gtk_button_new_with_mnemonic (_("Continue"));
357
358   psppire_box_pack_start_defaults (GTK_BOX (bb),
359                                bb->button[PSPPIRE_BUTTON_CONTINUE]);
360   g_signal_connect (bb->button[PSPPIRE_BUTTON_CONTINUE], "clicked",
361                     G_CALLBACK (continue_button_clicked), NULL);
362
363   g_object_set (bb->button[PSPPIRE_BUTTON_CONTINUE],
364                 "no-show-all", TRUE, NULL);
365
366
367
368   bb->button[PSPPIRE_BUTTON_PASTE] = gtk_button_new_with_label (_("Paste"));
369   g_signal_connect (bb->button[PSPPIRE_BUTTON_PASTE], "clicked",
370                     G_CALLBACK (paste_button_clicked), NULL);
371   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_PASTE]);
372   g_object_set (bb->button[PSPPIRE_BUTTON_PASTE], "no-show-all", TRUE, NULL);
373
374   bb->button[PSPPIRE_BUTTON_CANCEL] = gtk_button_new_with_label (_("Cancel"));
375   g_signal_connect (bb->button[PSPPIRE_BUTTON_CANCEL], "clicked",
376                     G_CALLBACK (close_dialog), NULL);
377   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_CANCEL]);
378   g_object_set (bb->button[PSPPIRE_BUTTON_CANCEL], "no-show-all", TRUE, NULL);
379
380   bb->button[PSPPIRE_BUTTON_CLOSE] = gtk_button_new_with_label (_("Close"));
381   g_signal_connect (bb->button[PSPPIRE_BUTTON_CLOSE], "clicked",
382                     G_CALLBACK (close_dialog), NULL);
383   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_CLOSE]);
384   g_object_set (bb->button[PSPPIRE_BUTTON_CLOSE], "no-show-all", TRUE, NULL);
385
386
387   bb->button[PSPPIRE_BUTTON_RESET] = gtk_button_new_with_label (_("Reset"));
388   g_signal_connect (bb->button[PSPPIRE_BUTTON_RESET], "clicked",
389                     G_CALLBACK (refresh_clicked), NULL);
390   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_RESET]);
391   g_object_set (bb->button[PSPPIRE_BUTTON_RESET], "no-show-all", TRUE, NULL);
392
393
394   bb->button[PSPPIRE_BUTTON_HELP] = gtk_button_new_with_label (_("Help"));
395   g_signal_connect (bb->button[PSPPIRE_BUTTON_HELP], "clicked",
396                     G_CALLBACK (help_clicked), NULL);
397   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_HELP]);
398   g_object_set (bb->button[PSPPIRE_BUTTON_HELP], "no-show-all", TRUE, NULL);
399
400
401   /* Set the default visibilities */
402   {
403     GValue value = { 0 };
404     guint flags;
405     gint i;
406     g_value_init (&value, button_flags->value_type);
407     g_param_value_set_default(button_flags, &value);
408
409
410     flags = g_value_get_flags (&value);
411
412     for (i = 0 ; i < n_PsppireButtonboxButtons ; ++i)
413       g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
414
415     g_value_unset (&value);
416   }
417
418
419   g_signal_connect (bb, "realize", G_CALLBACK (on_realize), NULL);
420 }
421
422 GType
423 psppire_button_flags_get_type (void)
424 {
425   static GType ftype = 0;
426   if (ftype == 0)
427     {
428       static const GFlagsValue values[] =
429         {
430           { PSPPIRE_BUTTON_OK_MASK,      "PSPPIRE_BUTTON_OK_MASK",       "Accept dialog and run it" },
431           { PSPPIRE_BUTTON_GOTO_MASK,    "PSPPIRE_BUTTON_GOTO_MASK",     "Goto case/variable" },
432           { PSPPIRE_BUTTON_CONTINUE_MASK,"PSPPIRE_BUTTON_CONTINUE_MASK", "Accept and close the subdialog" },
433           { PSPPIRE_BUTTON_CANCEL_MASK,  "PSPPIRE_BUTTON_CANCEL_MASK",   "Close dialog and discard settings" },
434           { PSPPIRE_BUTTON_CLOSE_MASK,   "PSPPIRE_BUTTON_CLOSE_MASK",    "Close dialog" },
435           { PSPPIRE_BUTTON_HELP_MASK,    "PSPPIRE_BUTTON_HELP_MASK",     "Invoke context sensitive help" },
436           { PSPPIRE_BUTTON_RESET_MASK,   "PSPPIRE_BUTTON_RESET_MASK",    "Restore dialog to its default settings" },
437           { PSPPIRE_BUTTON_PASTE_MASK,   "PSPPIRE_BUTTON_PASTE_MASK",    "Accept dialog and paste syntax" },
438           { 0, NULL, NULL }
439         };
440
441       ftype = g_flags_register_static
442         (g_intern_static_string ("PsppireButtonFlags"), values);
443
444     }
445   return ftype;
446 }
447