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 "variant-editor.h"
22
23#include "gtksizegroup.h"
24#include "gtktogglebutton.h"
25#include "gtkentry.h"
26#include "gtklabel.h"
27#include "gtkbox.h"
28#include "gtkbinlayout.h"
29
30
31struct _GtkInspectorVariantEditor
32{
33 GtkWidget parent;
34
35 const GVariantType *type;
36
37 GtkWidget *editor;
38 GtkInspectorVariantEditorChanged callback;
39 gpointer data;
40};
41
42typedef struct
43{
44 GtkWidgetClass parent;
45} GtkInspectorVariantEditorClass;
46
47static void
48variant_editor_changed_cb (GObject *obj,
49 GParamSpec *pspec,
50 GtkInspectorVariantEditor *self)
51{
52 self->callback (GTK_WIDGET (self), self->data);
53}
54
55G_DEFINE_TYPE (GtkInspectorVariantEditor, gtk_inspector_variant_editor, GTK_TYPE_WIDGET)
56
57static void
58gtk_inspector_variant_editor_init (GtkInspectorVariantEditor *editor)
59{
60}
61
62
63static void
64dispose (GObject *object)
65{
66 GtkInspectorVariantEditor *self = GTK_INSPECTOR_VARIANT_EDITOR (object);
67
68 if (self->editor)
69 {
70 g_signal_handlers_disconnect_by_func (self->editor, variant_editor_changed_cb, self->data);
71
72 gtk_widget_unparent (widget: self->editor);
73 }
74
75 G_OBJECT_CLASS (gtk_inspector_variant_editor_parent_class)->dispose (object);
76}
77
78static void
79gtk_inspector_variant_editor_class_init (GtkInspectorVariantEditorClass *klass)
80{
81 GObjectClass *object_class = G_OBJECT_CLASS (klass);
82 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
83
84 object_class->dispose = dispose;
85
86 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
87}
88
89static void
90ensure_editor (GtkInspectorVariantEditor *self,
91 const GVariantType *type)
92{
93 if (self->type &&
94 g_variant_type_equal (type1: self->type, type2: type))
95 return;
96
97 if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_BOOLEAN))
98 {
99 if (self->editor)
100 gtk_widget_unparent (widget: self->editor);
101
102 self->editor = gtk_toggle_button_new_with_label (label: "FALSE");
103 g_signal_connect (self->editor, "notify::active",
104 G_CALLBACK (variant_editor_changed_cb), self);
105 }
106 else if (g_variant_type_equal (type1: type, G_VARIANT_TYPE_STRING))
107 {
108 if (self->editor)
109 gtk_widget_unparent (widget: self->editor);
110
111 self->editor = gtk_entry_new ();
112 gtk_editable_set_width_chars (GTK_EDITABLE (self->editor), n_chars: 10);
113 g_signal_connect (self->editor, "notify::text",
114 G_CALLBACK (variant_editor_changed_cb), self);
115 }
116 else if (!GTK_IS_BOX (self->editor))
117 {
118 GtkWidget *entry, *label;
119
120 if (self->editor)
121 gtk_widget_unparent (widget: self->editor);
122
123 self->editor = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
124 entry = gtk_entry_new ();
125 gtk_editable_set_width_chars (GTK_EDITABLE (entry), n_chars: 10);
126 gtk_box_append (GTK_BOX (self->editor), child: entry);
127 label = gtk_label_new (str: g_variant_type_peek_string (type));
128 gtk_box_append (GTK_BOX (self->editor), child: label);
129 g_signal_connect (entry, "notify::text",
130 G_CALLBACK (variant_editor_changed_cb), self);
131 }
132
133 self->type = type;
134 gtk_widget_set_parent (widget: self->editor, GTK_WIDGET (self));
135}
136
137GtkWidget *
138gtk_inspector_variant_editor_new (const GVariantType *type,
139 GtkInspectorVariantEditorChanged callback,
140 gpointer data)
141{
142 GtkInspectorVariantEditor *self;
143
144 self = g_object_new (GTK_TYPE_INSPECTOR_VARIANT_EDITOR, NULL);
145
146 self->callback = callback;
147 self->data = data;
148
149 if (type)
150 ensure_editor (self, type);
151
152 return GTK_WIDGET (self);
153}
154
155void
156gtk_inspector_variant_editor_set_type (GtkWidget *editor,
157 const GVariantType *type)
158{
159 GtkInspectorVariantEditor *self = GTK_INSPECTOR_VARIANT_EDITOR (editor);
160
161 ensure_editor (self, type);
162}
163
164void
165gtk_inspector_variant_editor_set_value (GtkWidget *editor,
166 GVariant *value)
167{
168 GtkInspectorVariantEditor *self = GTK_INSPECTOR_VARIANT_EDITOR (editor);
169
170 ensure_editor (self, type: g_variant_get_type (value));
171
172 g_signal_handlers_block_by_func (self->editor, variant_editor_changed_cb, self->data);
173
174 if (g_variant_type_equal (type1: self->type, G_VARIANT_TYPE_BOOLEAN))
175 {
176 GtkToggleButton *tb = GTK_TOGGLE_BUTTON (self->editor);
177
178 if (gtk_toggle_button_get_active (toggle_button: tb) != g_variant_get_boolean (value))
179 {
180 gtk_toggle_button_set_active (toggle_button: tb, is_active: g_variant_get_boolean (value));
181 gtk_button_set_label (GTK_BUTTON (tb),
182 label: g_variant_get_boolean (value) ? "TRUE" : "FALSE");
183 }
184 }
185 else if (g_variant_type_equal (type1: self->type, G_VARIANT_TYPE_STRING))
186 {
187 GtkEntry *entry = GTK_ENTRY (self->editor);
188
189 gtk_editable_set_text (GTK_EDITABLE (entry),
190 text: g_variant_get_string (value, NULL));
191 }
192 else
193 {
194 GtkWidget *entry;
195 char *text;
196
197 entry = gtk_widget_get_first_child (widget: self->editor);
198
199 text = g_variant_print (value, FALSE);
200 gtk_editable_set_text (GTK_EDITABLE (entry), text);
201 g_free (mem: text);
202 }
203
204 g_signal_handlers_unblock_by_func (self->editor, variant_editor_changed_cb, self->data);
205}
206
207GVariant *
208gtk_inspector_variant_editor_get_value (GtkWidget *editor)
209{
210 GtkInspectorVariantEditor *self = GTK_INSPECTOR_VARIANT_EDITOR (editor);
211 GVariant *value;
212
213 if (self->type == NULL)
214 return NULL;
215
216 if (g_variant_type_equal (type1: self->type, G_VARIANT_TYPE_BOOLEAN))
217 {
218 GtkToggleButton *tb = GTK_TOGGLE_BUTTON (self->editor);
219 value = g_variant_new_boolean (value: gtk_toggle_button_get_active (toggle_button: tb));
220 }
221 else if (g_variant_type_equal (type1: self->type, G_VARIANT_TYPE_STRING))
222 {
223 GtkEntry *entry = GTK_ENTRY (self->editor);
224 value = g_variant_new_string (string: gtk_editable_get_text (GTK_EDITABLE (entry)));
225 }
226 else
227 {
228 GtkWidget *entry;
229 const char *text;
230
231 entry = gtk_widget_get_first_child (widget: self->editor);
232 text = gtk_editable_get_text (GTK_EDITABLE (entry));
233
234 value = g_variant_parse (type: self->type, text, NULL, NULL, NULL);
235 }
236
237 return value;
238}
239

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