Added the Variable Information dialog.
[pspp-builds.git] / src / ui / gui / psppire-buttonbox.c
1 /*
2     PSPPIRE --- A Graphical User Interface for PSPP
3     Copyright (C) 2007  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
21 #include <config.h>
22
23 #include <glib.h>
24 #include <gtk/gtk.h>
25 #include <gtk/gtksignal.h>
26 #include "psppire-buttonbox.h"
27 #include "psppire-dialog.h"
28
29 #include <gettext.h>
30
31 #define _(msgid) gettext (msgid)
32 #define N_(msgid) msgid
33
34 GType psppire_button_flags_get_type (void);
35
36
37 static void psppire_button_box_class_init          (PsppireButtonBoxClass *);
38 static void psppire_button_box_init                (PsppireButtonBox      *);
39
40
41 GType
42 psppire_button_box_get_type (void)
43 {
44   static GType button_box_type = 0;
45
46   if (!button_box_type)
47     {
48       static const GTypeInfo button_box_info =
49       {
50         sizeof (PsppireButtonBoxClass),
51         NULL, /* base_init */
52         NULL, /* base_finalize */
53         (GClassInitFunc) psppire_button_box_class_init,
54         NULL, /* class_finalize */
55         NULL, /* class_data */
56         sizeof (PsppireButtonBox),
57         0,
58         (GInstanceInitFunc) psppire_button_box_init,
59       };
60
61       button_box_type = g_type_register_static (GTK_TYPE_BUTTON_BOX,
62                                             "PsppireButtonBox", &button_box_info, 0);
63     }
64
65   return button_box_type;
66 }
67
68 enum {
69   PROP_BUTTONS = 1
70 };
71
72 static void
73 psppire_buttonbox_set_property (GObject         *object,
74                                guint            prop_id,
75                                const GValue    *value,
76                                GParamSpec      *pspec)
77 {
78   gint i;
79   guint flags;
80   PsppireButtonBox *bb = PSPPIRE_BUTTONBOX (object);
81   if ( prop_id != PROP_BUTTONS)
82     {
83       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
84       return ;
85     }
86
87   flags = g_value_get_flags (value);
88
89   for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
90     g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
91 }
92
93 static void
94 psppire_buttonbox_get_property (GObject         *object,
95                                guint            prop_id,
96                                GValue          *value,
97                                GParamSpec      *pspec)
98 {
99   guint flags = 0;
100   gint i;
101
102   PsppireButtonBox *bb = PSPPIRE_BUTTONBOX (object);
103
104   if  (PROP_BUTTONS != prop_id)
105     {
106       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
107       return;
108     }
109
110   for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
111     {
112       gboolean visibility;
113       g_object_get (bb->button[i], "visible", &visibility, NULL);
114
115       if ( visibility )
116         flags |= (0x01 << i);
117     }
118
119   g_value_set_flags (value, flags);
120 }
121
122
123 typedef enum
124   {
125     PSPPIRE_BUTTON_OK_MASK     = (1 << PSPPIRE_BUTTON_OK),
126     PSPPIRE_BUTTON_GOTO_MASK   = (1 << PSPPIRE_BUTTON_GOTO),
127     PSPPIRE_BUTTON_CONTINUE_MASK = (1 << PSPPIRE_BUTTON_CONTINUE),
128     PSPPIRE_BUTTON_CANCEL_MASK = (1 << PSPPIRE_BUTTON_CANCEL),
129     PSPPIRE_BUTTON_HELP_MASK   = (1 << PSPPIRE_BUTTON_HELP),
130     PSPPIRE_BUTTON_RESET_MASK  = (1 << PSPPIRE_BUTTON_RESET),
131     PSPPIRE_BUTTON_PASTE_MASK  = (1 << PSPPIRE_BUTTON_PASTE)
132   } PsppireButtonMask;
133
134 static GParamSpec *button_flags;
135
136 static void
137 psppire_button_box_class_init (PsppireButtonBoxClass *class)
138 {
139   GObjectClass *object_class = G_OBJECT_CLASS (class);
140
141   object_class->set_property = psppire_buttonbox_set_property;
142   object_class->get_property = psppire_buttonbox_get_property;
143
144   button_flags =
145     g_param_spec_flags ("buttons",
146                         _("Buttons"),
147                         _("The mask that decides what buttons appear in the button box"),
148                         G_TYPE_PSPPIRE_BUTTON_MASK,
149                         PSPPIRE_BUTTON_OK_MASK |
150                         PSPPIRE_BUTTON_CANCEL_MASK |
151                         PSPPIRE_BUTTON_RESET_MASK |
152                         PSPPIRE_BUTTON_HELP_MASK |
153                         PSPPIRE_BUTTON_PASTE_MASK,
154                         G_PARAM_READWRITE);
155
156
157   g_object_class_install_property (object_class,
158                                    PROP_BUTTONS,
159                                    button_flags);
160
161 }
162
163 static void
164 close_and_respond (GtkWidget *w, gint response)
165 {
166   PsppireDialog *dialog;
167
168   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
169
170   /* If we're not in a psppire dialog (for example when in glade)
171      then do nothing */
172   if ( ! PSPPIRE_IS_DIALOG (toplevel))
173     return;
174
175   dialog = PSPPIRE_DIALOG (toplevel);
176
177   dialog->response = response;
178
179   psppire_dialog_close (dialog);
180 }
181
182
183 static void
184 close_dialog (GtkWidget *w, gpointer data)
185 {
186   close_and_respond (w, GTK_RESPONSE_CLOSE);
187 }
188
189
190 static void
191 ok_button_clicked (GtkWidget *w, gpointer data)
192 {
193   close_and_respond (w, GTK_RESPONSE_OK);
194 }
195
196
197 static void
198 paste_button_clicked (GtkWidget *w, gpointer data)
199 {
200   close_and_respond (w, PSPPIRE_RESPONSE_PASTE);
201 }
202
203 static void
204 goto_button_clicked (GtkWidget *w, gpointer data)
205 {
206   close_and_respond (w, PSPPIRE_RESPONSE_GOTO);
207 }
208
209
210 static void
211 refresh_clicked (GtkWidget *w, gpointer data)
212 {
213   GtkWidget *toplevel = gtk_widget_get_toplevel (w);
214   PsppireDialog *dialog;
215
216   if ( ! PSPPIRE_IS_DIALOG (toplevel))
217     return;
218
219   dialog = PSPPIRE_DIALOG (toplevel);
220
221   psppire_dialog_reload (dialog);
222 }
223
224
225 static void
226 psppire_button_box_init (PsppireButtonBox *bb)
227 {
228
229   bb->button[PSPPIRE_BUTTON_OK] = gtk_button_new_from_stock (GTK_STOCK_OK);
230   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_OK]);
231   g_signal_connect (bb->button[PSPPIRE_BUTTON_OK], "clicked",
232                     G_CALLBACK (ok_button_clicked), NULL);
233   g_object_set (bb->button[PSPPIRE_BUTTON_OK], "no-show-all", TRUE, NULL);
234
235
236   bb->button[PSPPIRE_BUTTON_GOTO] =
237     gtk_button_new_from_stock (GTK_STOCK_JUMP_TO);
238   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_GOTO]);
239   g_signal_connect (bb->button[PSPPIRE_BUTTON_GOTO], "clicked",
240                     G_CALLBACK (goto_button_clicked), NULL);
241   g_object_set (bb->button[PSPPIRE_BUTTON_GOTO], "no-show-all", TRUE, NULL);
242
243
244   bb->button[PSPPIRE_BUTTON_CONTINUE] =
245     gtk_button_new_with_mnemonic (_("Continue"));
246
247   gtk_box_pack_start_defaults (GTK_BOX (bb),
248                                bb->button[PSPPIRE_BUTTON_CONTINUE]);
249
250   g_object_set (bb->button[PSPPIRE_BUTTON_CONTINUE],
251                 "no-show-all", TRUE, NULL);
252
253
254
255   bb->button[PSPPIRE_BUTTON_PASTE] = gtk_button_new_with_mnemonic (_("_Paste"));
256   g_signal_connect (bb->button[PSPPIRE_BUTTON_PASTE], "clicked",
257                     G_CALLBACK (paste_button_clicked), NULL);
258   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_PASTE]);
259   g_object_set (bb->button[PSPPIRE_BUTTON_PASTE], "no-show-all", TRUE, NULL);
260
261   bb->button[PSPPIRE_BUTTON_CANCEL] = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
262   g_signal_connect (bb->button[PSPPIRE_BUTTON_CANCEL], "clicked",
263                     G_CALLBACK (close_dialog), NULL);
264   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_CANCEL]);
265   g_object_set (bb->button[PSPPIRE_BUTTON_CANCEL], "no-show-all", TRUE, NULL);
266
267
268   bb->button[PSPPIRE_BUTTON_RESET] = gtk_button_new_from_stock (GTK_STOCK_REFRESH);
269   g_signal_connect (bb->button[PSPPIRE_BUTTON_RESET], "clicked",
270                     G_CALLBACK (refresh_clicked), NULL);
271   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_RESET]);
272   g_object_set (bb->button[PSPPIRE_BUTTON_RESET], "no-show-all", TRUE, NULL);
273
274
275   bb->button[PSPPIRE_BUTTON_HELP] = gtk_button_new_from_stock (GTK_STOCK_HELP);
276   gtk_box_pack_start_defaults (GTK_BOX (bb), bb->button[PSPPIRE_BUTTON_HELP]);
277   g_object_set (bb->button[PSPPIRE_BUTTON_HELP], "no-show-all", TRUE, NULL);
278
279
280   /* Set the default visibilities */
281   {
282     GValue value = { 0 };
283     guint flags;
284     gint i;
285     g_value_init (&value, button_flags->value_type);
286     g_param_value_set_default(button_flags, &value);
287
288
289     flags = g_value_get_flags (&value);
290
291     for (i = 0 ; i < n_PsppireButtonBoxButtons ; ++i )
292       g_object_set (bb->button[i], "visible", 0x01 & (flags >> i)  , NULL);
293
294     g_value_unset (&value);
295   }
296
297 }
298
299
300 /* This function is lifted verbatim from the Gtk2.10.6 library */
301
302 void
303 _psppire_button_box_child_requisition (GtkWidget *widget,
304                                        int       *nvis_children,
305                                        int       *nvis_secondaries,
306                                        int       *width,
307                                        int       *height)
308 {
309   GtkButtonBox *bbox;
310   GtkBoxChild *child;
311   GList *children;
312   gint nchildren;
313   gint nsecondaries;
314   gint needed_width;
315   gint needed_height;
316   GtkRequisition child_requisition;
317   gint ipad_w;
318   gint ipad_h;
319   gint width_default;
320   gint height_default;
321   gint ipad_x_default;
322   gint ipad_y_default;
323
324   gint child_min_width;
325   gint child_min_height;
326   gint ipad_x;
327   gint ipad_y;
328
329   g_return_if_fail (GTK_IS_BUTTON_BOX (widget));
330
331   bbox = GTK_BUTTON_BOX (widget);
332
333   gtk_widget_style_get (widget,
334                         "child-min-width", &width_default,
335                         "child-min-height", &height_default,
336                         "child-internal-pad-x", &ipad_x_default,
337                         "child-internal-pad-y", &ipad_y_default,
338                         NULL);
339
340   child_min_width = bbox->child_min_width   != GTK_BUTTONBOX_DEFAULT
341     ? bbox->child_min_width : width_default;
342   child_min_height = bbox->child_min_height !=GTK_BUTTONBOX_DEFAULT
343     ? bbox->child_min_height : height_default;
344   ipad_x = bbox->child_ipad_x != GTK_BUTTONBOX_DEFAULT
345     ? bbox->child_ipad_x : ipad_x_default;
346   ipad_y = bbox->child_ipad_y != GTK_BUTTONBOX_DEFAULT
347     ? bbox->child_ipad_y : ipad_y_default;
348
349   nchildren = 0;
350   nsecondaries = 0;
351   children = GTK_BOX(bbox)->children;
352   needed_width = child_min_width;
353   needed_height = child_min_height;
354   ipad_w = ipad_x * 2;
355   ipad_h = ipad_y * 2;
356
357   while (children)
358     {
359       child = children->data;
360       children = children->next;
361
362       if (GTK_WIDGET_VISIBLE (child->widget))
363         {
364           nchildren += 1;
365           gtk_widget_size_request (child->widget, &child_requisition);
366
367           if (child_requisition.width + ipad_w > needed_width)
368             needed_width = child_requisition.width + ipad_w;
369           if (child_requisition.height + ipad_h > needed_height)
370             needed_height = child_requisition.height + ipad_h;
371           if (child->is_secondary)
372             nsecondaries++;
373         }
374     }
375
376   if (nvis_children)
377     *nvis_children = nchildren;
378   if (nvis_secondaries)
379     *nvis_secondaries = nsecondaries;
380   if (width)
381     *width = needed_width;
382   if (height)
383     *height = needed_height;
384 }
385
386
387 GType
388 psppire_button_flags_get_type (void)
389 {
390   static GType ftype = 0;
391   if (ftype == 0)
392     {
393       static const GFlagsValue values[] =
394         {
395           { PSPPIRE_BUTTON_OK_MASK,     "PSPPIRE_BUTTON_OK_MASK",     N_("OK") },
396           { PSPPIRE_BUTTON_GOTO_MASK,   "PSPPIRE_BUTTON_GOTO_MASK", N_("Go To") },
397           { PSPPIRE_BUTTON_CONTINUE_MASK,"PSPPIRE_BUTTON_CONTINUE_MASK", N_("Continue") },
398           { PSPPIRE_BUTTON_CANCEL_MASK, "PSPPIRE_BUTTON_CANCEL_MASK", N_("Cancel") },
399           { PSPPIRE_BUTTON_HELP_MASK,   "PSPPIRE_BUTTON_HELP_MASK",   N_("Help") },
400           { PSPPIRE_BUTTON_RESET_MASK,  "PSPPIRE_BUTTON_RESET_MASK",  N_("Reset") },
401           { PSPPIRE_BUTTON_PASTE_MASK,  "PSPPIRE_BUTTON_PASTE_MASK",  N_("Paste") },
402           { 0, NULL, NULL }
403         };
404
405       ftype = g_flags_register_static
406         (g_intern_static_string ("PsppireButtonFlags"), values);
407
408     }
409   return ftype;
410 }
411