Enable the show value labels feature
[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 void
305 on_realize (GtkWidget *buttonbox, gpointer data)
306 {
307   GtkWidget *toplevel = gtk_widget_get_toplevel (buttonbox);
308
309   if ( PSPPIRE_IS_DIALOG (toplevel))
310     {
311       g_signal_connect (toplevel, "validity-changed",
312                         G_CALLBACK (on_validity_change), buttonbox);
313     }
314   set_default (PSPPIRE_BUTTONBOX (buttonbox));
315 }
316
317 static void
318 psppire_button_box_init (PsppireButtonbox *bb)
319 {
320   bb->def = PSPPIRE_BUTTON_CONTINUE;
321
322   bb->button[PSPPIRE_BUTTON_OK] = gtk_button_new_with_label (_("OK"));
323   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_OK]);
324   g_signal_connect (bb->button[PSPPIRE_BUTTON_OK], "clicked",
325                     G_CALLBACK (ok_button_clicked), NULL);
326   g_object_set (bb->button[PSPPIRE_BUTTON_OK], "no-show-all", TRUE, NULL);
327
328
329   bb->button[PSPPIRE_BUTTON_GOTO] =
330     gtk_button_new_with_label (_("Go To"));
331   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_GOTO]);
332   g_signal_connect (bb->button[PSPPIRE_BUTTON_GOTO], "clicked",
333                     G_CALLBACK (goto_button_clicked), NULL);
334   g_object_set (bb->button[PSPPIRE_BUTTON_GOTO], "no-show-all", TRUE, NULL);
335
336
337   bb->button[PSPPIRE_BUTTON_CONTINUE] =
338     gtk_button_new_with_mnemonic (_("Continue"));
339
340   psppire_box_pack_start_defaults (GTK_BOX (bb),
341                                bb->button[PSPPIRE_BUTTON_CONTINUE]);
342   g_signal_connect (bb->button[PSPPIRE_BUTTON_CONTINUE], "clicked",
343                     G_CALLBACK (continue_button_clicked), NULL);
344
345   g_object_set (bb->button[PSPPIRE_BUTTON_CONTINUE],
346                 "no-show-all", TRUE, NULL);
347
348
349
350   bb->button[PSPPIRE_BUTTON_PASTE] = gtk_button_new_with_label (_("Paste"));
351   g_signal_connect (bb->button[PSPPIRE_BUTTON_PASTE], "clicked",
352                     G_CALLBACK (paste_button_clicked), NULL);
353   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_PASTE]);
354   g_object_set (bb->button[PSPPIRE_BUTTON_PASTE], "no-show-all", TRUE, NULL);
355
356   bb->button[PSPPIRE_BUTTON_CANCEL] = gtk_button_new_with_label (_("Cancel"));
357   g_signal_connect (bb->button[PSPPIRE_BUTTON_CANCEL], "clicked",
358                     G_CALLBACK (close_dialog), NULL);
359   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_CANCEL]);
360   g_object_set (bb->button[PSPPIRE_BUTTON_CANCEL], "no-show-all", TRUE, NULL);
361
362   bb->button[PSPPIRE_BUTTON_CLOSE] = gtk_button_new_with_label (_("Close"));
363   g_signal_connect (bb->button[PSPPIRE_BUTTON_CLOSE], "clicked",
364                     G_CALLBACK (close_dialog), NULL);
365   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_CLOSE]);
366   g_object_set (bb->button[PSPPIRE_BUTTON_CLOSE], "no-show-all", TRUE, NULL);
367
368
369   bb->button[PSPPIRE_BUTTON_RESET] = gtk_button_new_with_label (_("Reset"));
370   g_signal_connect (bb->button[PSPPIRE_BUTTON_RESET], "clicked",
371                     G_CALLBACK (refresh_clicked), NULL);
372   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_RESET]);
373   g_object_set (bb->button[PSPPIRE_BUTTON_RESET], "no-show-all", TRUE, NULL);
374
375
376   bb->button[PSPPIRE_BUTTON_HELP] = gtk_button_new_with_label (_("Help"));
377   g_signal_connect (bb->button[PSPPIRE_BUTTON_HELP], "clicked",
378                     G_CALLBACK (help_clicked), NULL);
379   psppire_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_HELP]);
380   g_object_set (bb->button[PSPPIRE_BUTTON_HELP], "no-show-all", TRUE, NULL);
381
382
383   /* Set the default visibilities */
384   {
385     GValue value = { 0 };
386     guint flags;
387     gint i;
388     g_value_init (&value, button_flags->value_type);
389     g_param_value_set_default(button_flags, &value);
390
391
392     flags = g_value_get_flags (&value);
393
394     for (i = 0 ; i < n_PsppireButtonboxButtons ; ++i )
395       g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
396
397     g_value_unset (&value);
398   }
399
400
401   g_signal_connect (bb, "realize", G_CALLBACK (on_realize), NULL);
402 }
403
404 GType
405 psppire_button_flags_get_type (void)
406 {
407   static GType ftype = 0;
408   if (ftype == 0)
409     {
410       static const GFlagsValue values[] =
411         {
412           { PSPPIRE_BUTTON_OK_MASK,      "PSPPIRE_BUTTON_OK_MASK",       "Accept dialog and run it" },
413           { PSPPIRE_BUTTON_GOTO_MASK,    "PSPPIRE_BUTTON_GOTO_MASK",     "Goto case/variable" },
414           { PSPPIRE_BUTTON_CONTINUE_MASK,"PSPPIRE_BUTTON_CONTINUE_MASK", "Accept and close the subdialog" },
415           { PSPPIRE_BUTTON_CANCEL_MASK,  "PSPPIRE_BUTTON_CANCEL_MASK",   "Close dialog and discard settings" },
416           { PSPPIRE_BUTTON_CLOSE_MASK,   "PSPPIRE_BUTTON_CLOSE_MASK",    "Close dialog" },
417           { PSPPIRE_BUTTON_HELP_MASK,    "PSPPIRE_BUTTON_HELP_MASK",     "Invoke context sensitive help" },
418           { PSPPIRE_BUTTON_RESET_MASK,   "PSPPIRE_BUTTON_RESET_MASK",    "Restore dialog to its default settings" },
419           { PSPPIRE_BUTTON_PASTE_MASK,   "PSPPIRE_BUTTON_PASTE_MASK",    "Accept dialog and paste syntax" },
420           { 0, NULL, NULL }
421         };
422
423       ftype = g_flags_register_static
424         (g_intern_static_string ("PsppireButtonFlags"), values);
425
426     }
427   return ftype;
428 }
429