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 | |
31 | struct _GtkInspectorVariantEditor |
32 | { |
33 | GtkWidget parent; |
34 | |
35 | const GVariantType *type; |
36 | |
37 | GtkWidget *editor; |
38 | GtkInspectorVariantEditorChanged callback; |
39 | gpointer data; |
40 | }; |
41 | |
42 | typedef struct |
43 | { |
44 | GtkWidgetClass parent; |
45 | } GtkInspectorVariantEditorClass; |
46 | |
47 | static void |
48 | variant_editor_changed_cb (GObject *obj, |
49 | GParamSpec *pspec, |
50 | GtkInspectorVariantEditor *self) |
51 | { |
52 | self->callback (GTK_WIDGET (self), self->data); |
53 | } |
54 | |
55 | G_DEFINE_TYPE (GtkInspectorVariantEditor, gtk_inspector_variant_editor, GTK_TYPE_WIDGET) |
56 | |
57 | static void |
58 | gtk_inspector_variant_editor_init (GtkInspectorVariantEditor *editor) |
59 | { |
60 | } |
61 | |
62 | |
63 | static void |
64 | dispose (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 | |
78 | static void |
79 | gtk_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 | |
89 | static void |
90 | ensure_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 | |
137 | GtkWidget * |
138 | gtk_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 | |
155 | void |
156 | gtk_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 | |
164 | void |
165 | gtk_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 | |
207 | GVariant * |
208 | gtk_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 | |