Warnings: missing initializer for value_tables and function type cast (GObject)
[pspp] / src / ui / gui / psppire-dialog-action.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2012, 2016  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 "psppire-dialog-action.h"
21 #include "psppire-dialog.h"
22 #include "executor.h"
23 #include "helper.h"
24 #include "psppire-data-window.h"
25 #include "builder-wrapper.h"
26
27 static GObjectClass * parent_class = NULL;
28
29 static const gchar *
30 __get_name (GAction *act)
31 {
32   return G_OBJECT_TYPE_NAME (act);
33 }
34
35 static const GVariantType *
36 __get_state_type (GAction *act)
37 {
38   return NULL;
39 }
40
41
42 static GVariant *
43 __get_state (GAction *act)
44 {
45   return NULL;
46 }
47
48
49 static const GVariantType *
50 __get_parameter_type (GAction *act)
51 {
52   return PSPPIRE_DIALOG_ACTION (act)->parameter_type;
53 }
54
55 static gboolean
56 __get_enabled (GAction *act)
57 {
58   return TRUE;
59 }
60
61 static void psppire_dialog_action_activate (PsppireDialogAction *act, GVariant *parameter);
62
63 void
64 psppire_dialog_action_activate_null (PsppireDialogAction *act)
65 {
66   psppire_dialog_action_activate (act, NULL);
67 }
68
69
70 static void
71 __activate (GAction *action, GVariant *parameter)
72 {
73   psppire_dialog_action_activate (PSPPIRE_DIALOG_ACTION (action), parameter);
74 }
75
76
77 static void
78 action_model_init (GActionInterface *iface)
79 {
80   iface->get_name = __get_name;
81   iface->get_state_type = __get_state_type;
82   iface->get_state = __get_state;
83   iface->get_parameter_type = __get_parameter_type;
84   iface->get_enabled = __get_enabled;
85   iface->activate = __activate;
86 }
87
88 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PsppireDialogAction, \
89                                   psppire_dialog_action, \
90                                   G_TYPE_OBJECT, \
91                                   G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, \
92                                                          action_model_init))
93
94 /* Properties */
95 enum
96 {
97   PROP_0,
98   PROP_TOPLEVEL,
99   PROP_NAME,
100   PROP_ENABLED,
101   PROP_STATE,
102   PROP_STATE_TYPE,
103   PROP_PARAMETER_TYPE
104 };
105
106 static void
107 psppire_dialog_action_set_property (GObject         *object,
108                                guint            prop_id,
109                                const GValue    *value,
110                                GParamSpec      *pspec)
111 {
112   PsppireDialogAction *act = PSPPIRE_DIALOG_ACTION (object);
113
114   switch (prop_id)
115     {
116     case PROP_TOPLEVEL:
117       {
118         GObject *p = g_value_get_object (value);
119         act->toplevel = GTK_WIDGET (p);
120       }
121       break;
122     default:
123       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
124       break;
125     };
126 }
127
128
129 static void
130 psppire_dialog_action_get_property (GObject    *object,
131                                guint            prop_id,
132                                GValue          *value,
133                                GParamSpec      *pspec)
134 {
135   PsppireDialogAction *dialog_action = PSPPIRE_DIALOG_ACTION (object);
136
137   switch (prop_id)
138     {
139     case PROP_TOPLEVEL:
140       g_value_take_object (value, dialog_action->toplevel);
141       break;
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144       break;
145     };
146 }
147
148
149
150 static void
151 on_destroy_dataset (GObject *w)
152 {
153   GHashTable *t = g_object_get_data (w, "thing-table");
154   GSList *dl = g_object_get_data (w, "widget-list");
155
156   g_slist_free_full (dl, (GDestroyNotify) gtk_widget_destroy);
157   g_hash_table_unref (t);
158 }
159
160 /* Each toplevel widget - that is the data window, which generally has a 1-1 association
161    with a dataset - has an associated GHashTable.
162
163    This GHashTable is keyed by the address of a PsppireDialogAction, and its values
164    are user determined pointers (typically a GtkBuilder*).
165
166    This is useful for storing the state of dialogs so they can persist between invocations.
167 */
168 GHashTable *
169 psppire_dialog_action_get_hash_table (PsppireDialogAction *act)
170 {
171   GHashTable *t = g_object_get_data (G_OBJECT (act->toplevel), "thing-table");
172   if (t == NULL)
173     {
174       t = g_hash_table_new_full (g_direct_hash, g_direct_equal, 0, g_object_unref);
175       g_object_set_data (G_OBJECT (act->toplevel), "thing-table", t);
176       g_object_set_data (G_OBJECT (act->toplevel), "widget-list", NULL);
177       g_signal_connect (act->toplevel, "destroy", G_CALLBACK (on_destroy_dataset), NULL);
178     }
179
180   return t;
181 }
182
183 GtkBuilder *
184 psppire_dialog_action_get_xml (PsppireDialogAction *da)
185 {
186   GHashTable *thing = psppire_dialog_action_get_hash_table (da);
187   GtkBuilder *xml = g_hash_table_lookup (thing, da);
188   return xml;
189 }
190
191
192 static void
193 psppire_dialog_action_activate (PsppireDialogAction *act, GVariant *parameter)
194 {
195   gint response;
196
197   PsppireDialogActionClass *class = PSPPIRE_DIALOG_ACTION_GET_CLASS (act);
198
199   act->dict = PSPPIRE_DATA_WINDOW(act->toplevel)->dict;
200
201   GSList *wl = g_object_get_data (G_OBJECT (act->toplevel), "widget-list");
202   wl = g_slist_prepend (wl, act->dialog);
203   g_object_set_data (G_OBJECT (act->toplevel), "widget-list", wl);
204
205   if (class->initial_activate)
206     {
207       GHashTable *thing = psppire_dialog_action_get_hash_table (act);
208       GtkBuilder *xml = g_hash_table_lookup (thing, act);
209       if (xml == NULL)
210         {
211           xml = class->initial_activate (act, parameter);
212           g_hash_table_insert (thing, act, xml);
213         }
214     }
215
216   if (class->activate)
217     {
218       GHashTable *thing = psppire_dialog_action_get_hash_table (act);
219       GtkBuilder *xml = g_hash_table_lookup (thing, act);
220       if (xml != NULL)
221         class->activate (act, parameter);
222     }
223
224   gtk_window_set_transient_for (GTK_WINDOW (act->dialog),
225                                 GTK_WINDOW (act->toplevel));
226
227   if (act->source)
228     {
229       g_object_set (act->source, "model", act->dict, NULL);
230       gtk_widget_grab_focus (act->source);
231     }
232
233   if (!act->activated)
234     psppire_dialog_reload (PSPPIRE_DIALOG (act->dialog));
235
236   act->activated = TRUE;
237
238   response = psppire_dialog_run (PSPPIRE_DIALOG (act->dialog));
239
240   if (class->generate_syntax)
241     {
242       switch (response)
243         {
244         case GTK_RESPONSE_OK:
245           g_free (execute_syntax_string (PSPPIRE_DATA_WINDOW (act->toplevel),
246                                          class->generate_syntax (act)));
247           break;
248         case PSPPIRE_RESPONSE_PASTE:
249           g_free (paste_syntax_to_window (class->generate_syntax (act)));
250           break;
251         default:
252           break;
253         }
254     }
255 }
256
257 static void
258 psppire_dialog_action_class_init (PsppireDialogActionClass *class)
259 {
260   GObjectClass *object_class = G_OBJECT_CLASS (class);
261
262   parent_class = g_type_class_peek_parent (class);
263
264   GParamSpec *toplevel_spec =
265     g_param_spec_object ("top-level",
266                          "Top Level",
267                          "The top level widget to which this dialog action belongs",
268                          GTK_TYPE_WINDOW,
269                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
270
271   object_class->set_property = psppire_dialog_action_set_property;
272   object_class->get_property = psppire_dialog_action_get_property;
273
274   class->generate_syntax = NULL;
275
276   g_object_class_install_property (object_class,
277                                    PROP_TOPLEVEL,
278                                    toplevel_spec);
279
280   g_object_class_override_property (object_class, PROP_NAME, "name");
281   g_object_class_override_property (object_class, PROP_ENABLED, "enabled");
282   g_object_class_override_property (object_class, PROP_STATE, "state");
283   g_object_class_override_property (object_class, PROP_STATE_TYPE, "state-type");
284   g_object_class_override_property (object_class, PROP_PARAMETER_TYPE, "parameter-type");
285 }
286
287
288 static void
289 psppire_dialog_action_init (PsppireDialogAction *act)
290 {
291   act->toplevel = NULL;
292   act->dict = NULL;
293   act->activated = FALSE;
294   act->parameter_type = NULL;
295 }
296
297 void
298 psppire_dialog_action_set_valid_predicate (PsppireDialogAction *act,
299                                            ContentsAreValid dialog_state_valid)
300 {
301   psppire_dialog_set_valid_predicate (PSPPIRE_DIALOG (act->dialog),
302                                       dialog_state_valid, act);
303 }
304
305 void
306 psppire_dialog_action_set_refresh (PsppireDialogAction *pda,
307                                    PsppireDialogActionRefresh refresh)
308 {
309   g_signal_connect_swapped (pda->dialog, "refresh", G_CALLBACK (refresh),  pda);
310 }