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 |
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 (editor: r->parameter_entry); |
72 | if (G_IS_ACTION_GROUP (r->owner)) |
73 | g_action_group_activate_action (G_ACTION_GROUP (r->owner), action_name: r->name, parameter); |
74 | else if (GTK_IS_ACTION_MUXER (r->owner)) |
75 | gtk_action_muxer_activate_action (GTK_ACTION_MUXER (r->owner), action_name: r->name, parameter); |
76 | update_widgets (r); |
77 | } |
78 | |
79 | static void |
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 (widget: r->activate_button, sensitive: r->enabled && value != NULL); |
88 | if (value) |
89 | g_variant_unref (value); |
90 | } |
91 | |
92 | static void |
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), action_name: r->name, value); |
104 | else if (GTK_IS_ACTION_MUXER (r->owner)) |
105 | gtk_action_muxer_change_action_state (GTK_ACTION_MUXER (r->owner), action_name: r->name, state: value); |
106 | } |
107 | } |
108 | |
109 | static void |
110 | gtk_inspector_action_editor_init (GtkInspectorActionEditor *r) |
111 | { |
112 | GtkBoxLayout *layout; |
113 | GtkWidget *row, *activate, *label; |
114 | |
115 | layout = GTK_BOX_LAYOUT (ptr: gtk_widget_get_layout_manager (GTK_WIDGET (r))); |
116 | gtk_orientable_set_orientation (GTK_ORIENTABLE (layout), orientation: GTK_ORIENTATION_HORIZONTAL); |
117 | gtk_box_layout_set_spacing (box_layout: layout, spacing: 10); |
118 | |
119 | row = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10); |
120 | activate = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10); |
121 | gtk_box_append (GTK_BOX (row), child: 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), child: r->activate_button); |
127 | |
128 | r->parameter_entry = gtk_inspector_variant_editor_new (NULL, callback: parameter_changed, data: r); |
129 | gtk_widget_hide (widget: r->parameter_entry); |
130 | gtk_box_append (GTK_BOX (activate), child: r->parameter_entry); |
131 | |
132 | gtk_widget_set_parent (widget: row, GTK_WIDGET (r)); |
133 | |
134 | r->state_editor = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10); |
135 | label = gtk_label_new (_("Set State" )); |
136 | gtk_box_append (GTK_BOX (r->state_editor), child: label); |
137 | r->state_entry = gtk_inspector_variant_editor_new (NULL, callback: state_changed, data: r); |
138 | gtk_box_append (GTK_BOX (r->state_editor), child: r->state_entry); |
139 | gtk_widget_set_parent (widget: r->state_editor, GTK_WIDGET (r)); |
140 | gtk_widget_hide (widget: r->state_editor); |
141 | } |
142 | |
143 | static void |
144 | update_enabled (GtkInspectorActionEditor *r, |
145 | gboolean enabled) |
146 | { |
147 | r->enabled = enabled; |
148 | if (r->parameter_entry) |
149 | { |
150 | gtk_widget_set_sensitive (widget: r->parameter_entry, sensitive: enabled); |
151 | parameter_changed (editor: r->parameter_entry, data: r); |
152 | } |
153 | if (r->activate_button) |
154 | gtk_widget_set_sensitive (widget: r->activate_button, sensitive: enabled); |
155 | } |
156 | |
157 | static void |
158 | action_enabled_changed_cb (GActionGroup *group, |
159 | const char *action_name, |
160 | gboolean enabled, |
161 | GtkInspectorActionEditor *r) |
162 | { |
163 | if (g_str_equal (v1: action_name, v2: r->name)) |
164 | update_enabled (r, enabled); |
165 | } |
166 | |
167 | static void |
168 | update_state (GtkInspectorActionEditor *r, |
169 | GVariant *state) |
170 | { |
171 | if (r->state_entry) |
172 | gtk_inspector_variant_editor_set_value (editor: r->state_entry, value: state); |
173 | } |
174 | |
175 | static void |
176 | action_state_changed_cb (GActionGroup *group, |
177 | const char *action_name, |
178 | GVariant *state, |
179 | GtkInspectorActionEditor *r) |
180 | { |
181 | if (g_str_equal (v1: action_name, v2: r->name)) |
182 | update_state (r, state); |
183 | } |
184 | |
185 | static void |
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), action_name: r->name, |
192 | enabled: &r->enabled, parameter_type: &r->parameter_type, NULL, NULL, |
193 | state: &state); |
194 | else if (GTK_IS_ACTION_MUXER (r->owner)) |
195 | gtk_action_muxer_query_action (GTK_ACTION_MUXER (r->owner), action_name: r->name, |
196 | enabled: &r->enabled, parameter_type: &r->parameter_type, NULL, NULL, |
197 | state: &state); |
198 | else |
199 | state = NULL; |
200 | |
201 | gtk_widget_set_sensitive (widget: r->activate_button, sensitive: r->enabled); |
202 | |
203 | if (r->parameter_type) |
204 | { |
205 | gtk_inspector_variant_editor_set_type (editor: r->parameter_entry, type: r->parameter_type); |
206 | gtk_widget_show (widget: r->parameter_entry); |
207 | gtk_widget_set_sensitive (widget: r->parameter_entry, sensitive: r->enabled); |
208 | } |
209 | else |
210 | gtk_widget_hide (widget: r->parameter_entry); |
211 | |
212 | if (state) |
213 | { |
214 | if (r->state_type) |
215 | g_variant_type_free (type: r->state_type); |
216 | r->state_type = g_variant_type_copy (type: g_variant_get_type (value: state)); |
217 | gtk_inspector_variant_editor_set_value (editor: r->state_entry, value: state); |
218 | gtk_widget_show (widget: r->state_editor); |
219 | } |
220 | else |
221 | gtk_widget_hide (widget: 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 |
233 | dispose (GObject *object) |
234 | { |
235 | GtkInspectorActionEditor *r = GTK_INSPECTOR_ACTION_EDITOR (object); |
236 | GtkWidget *child; |
237 | |
238 | g_free (mem: r->name); |
239 | if (r->state_type) |
240 | g_variant_type_free (type: 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 (widget: child); |
249 | |
250 | G_OBJECT_CLASS (gtk_inspector_action_editor_parent_class)->dispose (object); |
251 | } |
252 | |
253 | static void |
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, v_object: r->owner); |
265 | break; |
266 | |
267 | case PROP_NAME: |
268 | g_value_set_string (value, v_string: 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 |
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 (mem: 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 |
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 (oclass: object_class, property_id: PROP_OWNER, |
318 | pspec: g_param_spec_object (name: "owner" , nick: "Owner" , blurb: "The owner of the action" , |
319 | G_TYPE_OBJECT, flags: G_PARAM_READWRITE)); |
320 | |
321 | g_object_class_install_property (oclass: object_class, property_id: PROP_NAME, |
322 | pspec: g_param_spec_string (name: "name" , nick: "Name" , blurb: "The action name" , |
323 | NULL, flags: G_PARAM_READWRITE)); |
324 | |
325 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); |
326 | } |
327 | |
328 | GtkWidget * |
329 | gtk_inspector_action_editor_new (void) |
330 | { |
331 | return g_object_new (GTK_TYPE_INSPECTOR_ACTION_EDITOR, NULL); |
332 | } |
333 | |
334 | void |
335 | gtk_inspector_action_editor_set (GtkInspectorActionEditor *self, |
336 | GObject *owner, |
337 | const char *name) |
338 | { |
339 | g_object_set (object: self, first_property_name: "owner" , owner, "name" , name, NULL); |
340 | update_widgets (r: self); |
341 | } |
342 | |
343 | void |
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 | |