1 /*
2 * Copyright (c) 2014 Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19 #include <glib/gi18n-lib.h>
20
21 #include "action-editor.h"
22 #include "variant-editor.h"
23
24 #include "gtktogglebutton.h"
25 #include "gtkentry.h"
26 #include "gtklabel.h"
27 #include "gtkbox.h"
28 #include "gtkboxlayout.h"
29 #include "gtkorientable.h"
30 #include "gtkactionmuxerprivate.h"
31
32 struct _GtkInspectorActionEditor
33 {
34 GtkWidget parent;
35
36 GObject *owner;
37 char *name;
38 gboolean enabled;
39 const GVariantType *parameter_type;
40 GVariantType *state_type;
41 GtkWidget *activate_button;
42 GtkWidget *parameter_entry;
43 GtkWidget *state_entry;
44 GtkWidget *state_editor;
45 };
46
47 typedef struct
48 {
49 GtkWidgetClass parent;
50 } GtkInspectorActionEditorClass;
51
52 enum
53 {
54 PROP_0,
55 PROP_OWNER,
56 PROP_NAME,
57 PROP_SIZEGROUP
58 };
59
60 G_DEFINE_TYPE (GtkInspectorActionEditor, gtk_inspector_action_editor, GTK_TYPE_WIDGET)
61
62 static void update_widgets (GtkInspectorActionEditor *r);
63
64 static void
activate_action(GtkWidget * button,GtkInspectorActionEditor * r)65 activate_action (GtkWidget *button,
66 GtkInspectorActionEditor *r)
67 {
68 GVariant *parameter = NULL;
69
70 if (r->parameter_entry)
71 parameter = gtk_inspector_variant_editor_get_value (r->parameter_entry);
72 if (G_IS_ACTION_GROUP (r->owner))
73 g_action_group_activate_action (G_ACTION_GROUP (r->owner), r->name, parameter);
74 else if (GTK_IS_ACTION_MUXER (r->owner))
75 gtk_action_muxer_activate_action (GTK_ACTION_MUXER (r->owner), r->name, parameter);
76 update_widgets (r);
77 }
78
79 static void
parameter_changed(GtkWidget * editor,gpointer data)80 parameter_changed (GtkWidget *editor,
81 gpointer data)
82 {
83 GtkInspectorActionEditor *r = data;
84 GVariant *value;
85
86 value = gtk_inspector_variant_editor_get_value (editor);
87 gtk_widget_set_sensitive (r->activate_button, r->enabled && value != NULL);
88 if (value)
89 g_variant_unref (value);
90 }
91
92 static void
state_changed(GtkWidget * editor,gpointer data)93 state_changed (GtkWidget *editor,
94 gpointer data)
95 {
96 GtkInspectorActionEditor *r = data;
97 GVariant *value;
98
99 value = gtk_inspector_variant_editor_get_value (editor);
100 if (value)
101 {
102 if (G_IS_ACTION_GROUP (r->owner))
103 g_action_group_change_action_state (G_ACTION_GROUP (r->owner), r->name, value);
104 else if (GTK_IS_ACTION_MUXER (r->owner))
105 gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (r->owner), r->name, value);
106 }
107 }
108
109 static void
gtk_inspector_action_editor_init(GtkInspectorActionEditor * r)110 gtk_inspector_action_editor_init (GtkInspectorActionEditor *r)
111 {
112 GtkBoxLayout *layout;
113 GtkWidget *row, *activate, *label;
114
115 layout = GTK_BOX_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (r)));
116 gtk_orientable_set_orientation (GTK_ORIENTABLE (layout), GTK_ORIENTATION_HORIZONTAL);
117 gtk_box_layout_set_spacing (layout, 10);
118
119 row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
120 activate = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
121 gtk_box_append (GTK_BOX (row), activate);
122
123 r->activate_button = gtk_button_new_with_label (_("Activate"));
124 g_signal_connect (r->activate_button, "clicked", G_CALLBACK (activate_action), r);
125
126 gtk_box_append (GTK_BOX (activate), r->activate_button);
127
128 r->parameter_entry = gtk_inspector_variant_editor_new (NULL, parameter_changed, r);
129 gtk_widget_hide (r->parameter_entry);
130 gtk_box_append (GTK_BOX (activate), r->parameter_entry);
131
132 gtk_widget_set_parent (row, GTK_WIDGET (r));
133
134 r->state_editor = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
135 label = gtk_label_new (_("Set State"));
136 gtk_box_append (GTK_BOX (r->state_editor), label);
137 r->state_entry = gtk_inspector_variant_editor_new (NULL, state_changed, r);
138 gtk_box_append (GTK_BOX (r->state_editor), r->state_entry);
139 gtk_widget_set_parent (r->state_editor, GTK_WIDGET (r));
140 gtk_widget_hide (r->state_editor);
141 }
142
143 static void
update_enabled(GtkInspectorActionEditor * r,gboolean enabled)144 update_enabled (GtkInspectorActionEditor *r,
145 gboolean enabled)
146 {
147 r->enabled = enabled;
148 if (r->parameter_entry)
149 {
150 gtk_widget_set_sensitive (r->parameter_entry, enabled);
151 parameter_changed (r->parameter_entry, r);
152 }
153 if (r->activate_button)
154 gtk_widget_set_sensitive (r->activate_button, enabled);
155 }
156
157 static void
action_enabled_changed_cb(GActionGroup * group,const char * action_name,gboolean enabled,GtkInspectorActionEditor * r)158 action_enabled_changed_cb (GActionGroup *group,
159 const char *action_name,
160 gboolean enabled,
161 GtkInspectorActionEditor *r)
162 {
163 if (g_str_equal (action_name, r->name))
164 update_enabled (r, enabled);
165 }
166
167 static void
update_state(GtkInspectorActionEditor * r,GVariant * state)168 update_state (GtkInspectorActionEditor *r,
169 GVariant *state)
170 {
171 if (r->state_entry)
172 gtk_inspector_variant_editor_set_value (r->state_entry, state);
173 }
174
175 static void
action_state_changed_cb(GActionGroup * group,const char * action_name,GVariant * state,GtkInspectorActionEditor * r)176 action_state_changed_cb (GActionGroup *group,
177 const char *action_name,
178 GVariant *state,
179 GtkInspectorActionEditor *r)
180 {
181 if (g_str_equal (action_name, r->name))
182 update_state (r, state);
183 }
184
185 static void
update_widgets(GtkInspectorActionEditor * r)186 update_widgets (GtkInspectorActionEditor *r)
187 {
188 GVariant *state;
189
190 if (G_IS_ACTION_GROUP (r->owner))
191 g_action_group_query_action (G_ACTION_GROUP (r->owner), r->name,
192 &r->enabled, &r->parameter_type, NULL, NULL,
193 &state);
194 else if (GTK_IS_ACTION_MUXER (r->owner))
195 gtk_action_muxer_query_action (GTK_ACTION_MUXER (r->owner), r->name,
196 &r->enabled, &r->parameter_type, NULL, NULL,
197 &state);
198 else
199 state = NULL;
200
201 gtk_widget_set_sensitive (r->activate_button, r->enabled);
202
203 if (r->parameter_type)
204 {
205 gtk_inspector_variant_editor_set_type (r->parameter_entry, r->parameter_type);
206 gtk_widget_show (r->parameter_entry);
207 gtk_widget_set_sensitive (r->parameter_entry, r->enabled);
208 }
209 else
210 gtk_widget_hide (r->parameter_entry);
211
212 if (state)
213 {
214 if (r->state_type)
215 g_variant_type_free (r->state_type);
216 r->state_type = g_variant_type_copy (g_variant_get_type (state));
217 gtk_inspector_variant_editor_set_value (r->state_entry, state);
218 gtk_widget_show (r->state_editor);
219 }
220 else
221 gtk_widget_hide (r->state_editor);
222
223 if (G_IS_ACTION_GROUP (r->owner))
224 {
225 g_signal_connect (r->owner, "action-enabled-changed",
226 G_CALLBACK (action_enabled_changed_cb), r);
227 g_signal_connect (r->owner, "action-state-changed",
228 G_CALLBACK (action_state_changed_cb), r);
229 }
230 }
231
232 static void
dispose(GObject * object)233 dispose (GObject *object)
234 {
235 GtkInspectorActionEditor *r = GTK_INSPECTOR_ACTION_EDITOR (object);
236 GtkWidget *child;
237
238 g_free (r->name);
239 if (r->state_type)
240 g_variant_type_free (r->state_type);
241 if (r->owner)
242 {
243 g_signal_handlers_disconnect_by_func (r->owner, action_enabled_changed_cb, r);
244 g_signal_handlers_disconnect_by_func (r->owner, action_state_changed_cb, r);
245 }
246
247 while ((child = gtk_widget_get_first_child (GTK_WIDGET (r))))
248 gtk_widget_unparent (child);
249
250 G_OBJECT_CLASS (gtk_inspector_action_editor_parent_class)->dispose (object);
251 }
252
253 static void
get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)254 get_property (GObject *object,
255 guint param_id,
256 GValue *value,
257 GParamSpec *pspec)
258 {
259 GtkInspectorActionEditor *r = GTK_INSPECTOR_ACTION_EDITOR (object);
260
261 switch (param_id)
262 {
263 case PROP_OWNER:
264 g_value_set_object (value, r->owner);
265 break;
266
267 case PROP_NAME:
268 g_value_set_string (value, r->name);
269 break;
270
271 default:
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
273 break;
274 }
275 }
276
277 static void
set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)278 set_property (GObject *object,
279 guint param_id,
280 const GValue *value,
281 GParamSpec *pspec)
282 {
283 GtkInspectorActionEditor *r = GTK_INSPECTOR_ACTION_EDITOR (object);
284
285 switch (param_id)
286 {
287 case PROP_OWNER:
288 if (r->owner)
289 {
290 g_signal_handlers_disconnect_by_func (r->owner, action_enabled_changed_cb, r);
291 g_signal_handlers_disconnect_by_func (r->owner, action_state_changed_cb, r);
292 }
293 r->owner = g_value_get_object (value);
294 break;
295
296 case PROP_NAME:
297 g_free (r->name);
298 r->name = g_value_dup_string (value);
299 break;
300
301 default:
302 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
303 break;
304 }
305 }
306
307 static void
gtk_inspector_action_editor_class_init(GtkInspectorActionEditorClass * klass)308 gtk_inspector_action_editor_class_init (GtkInspectorActionEditorClass *klass)
309 {
310 GObjectClass *object_class = G_OBJECT_CLASS (klass);
311 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
312
313 object_class->dispose = dispose;
314 object_class->get_property = get_property;
315 object_class->set_property = set_property;
316
317 g_object_class_install_property (object_class, PROP_OWNER,
318 g_param_spec_object ("owner", "Owner", "The owner of the action",
319 G_TYPE_OBJECT, G_PARAM_READWRITE));
320
321 g_object_class_install_property (object_class, PROP_NAME,
322 g_param_spec_string ("name", "Name", "The action name",
323 NULL, G_PARAM_READWRITE));
324
325 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
326 }
327
328 GtkWidget *
gtk_inspector_action_editor_new(void)329 gtk_inspector_action_editor_new (void)
330 {
331 return g_object_new (GTK_TYPE_INSPECTOR_ACTION_EDITOR, NULL);
332 }
333
334 void
gtk_inspector_action_editor_set(GtkInspectorActionEditor * self,GObject * owner,const char * name)335 gtk_inspector_action_editor_set (GtkInspectorActionEditor *self,
336 GObject *owner,
337 const char *name)
338 {
339 g_object_set (self, "owner", owner, "name", name, NULL);
340 update_widgets (self);
341 }
342
343 void
gtk_inspector_action_editor_update(GtkInspectorActionEditor * r,gboolean enabled,GVariant * state)344 gtk_inspector_action_editor_update (GtkInspectorActionEditor *r,
345 gboolean enabled,
346 GVariant *state)
347 {
348 update_enabled (r, enabled);
349 update_state (r, state);
350 }
351