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
32struct _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
47typedef struct
48{
49 GtkWidgetClass parent;
50} GtkInspectorActionEditorClass;
51
52enum
53{
54 PROP_0,
55 PROP_OWNER,
56 PROP_NAME,
57 PROP_SIZEGROUP
58};
59
60G_DEFINE_TYPE (GtkInspectorActionEditor, gtk_inspector_action_editor, GTK_TYPE_WIDGET)
61
62static void update_widgets (GtkInspectorActionEditor *r);
63
64static void
65activate_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
79static void
80parameter_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
92static void
93state_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
109static void
110gtk_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
143static void
144update_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
157static void
158action_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
167static void
168update_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
175static void
176action_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
185static void
186update_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
232static void
233dispose (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
253static void
254get_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
277static void
278set_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
307static void
308gtk_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
328GtkWidget *
329gtk_inspector_action_editor_new (void)
330{
331 return g_object_new (GTK_TYPE_INSPECTOR_ACTION_EDITOR, NULL);
332}
333
334void
335gtk_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
343void
344gtk_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

source code of gtk/gtk/inspector/action-editor.c