1 /*
2 * Copyright (C) 2013 Tristan Van Berkom.
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * 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 program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * Authors:
19 * Tristan Van Berkom <tvb@gnome.org>
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib/gi18n-lib.h>
27
28 #include "glade.h"
29 #include "glade-widget.h"
30 #include "glade-popup.h"
31 #include "glade-editable.h"
32 #include "glade-editor-skeleton.h"
33
34 /* GObjectClass */
35 static void glade_editor_skeleton_dispose (GObject *object);
36
37 /* GladeEditableIface */
38 static void glade_editor_skeleton_editable_init (GladeEditableIface *iface);
39
40 /* GtkBuildableIface */
41 static void glade_editor_skeleton_buildable_init (GtkBuildableIface *iface);
42
43 struct _GladeEditorSkeletonPrivate
44 {
45 GSList *editors;
46 };
47
48 static GladeEditableIface *parent_editable_iface;
49 static GtkBuildableIface *parent_buildable_iface;
50
51 G_DEFINE_TYPE_WITH_CODE (GladeEditorSkeleton, glade_editor_skeleton, GTK_TYPE_BOX,
52 G_ADD_PRIVATE (GladeEditorSkeleton)
53 G_IMPLEMENT_INTERFACE (GLADE_TYPE_EDITABLE,
54 glade_editor_skeleton_editable_init)
55 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
56 glade_editor_skeleton_buildable_init));
57
58 static void
glade_editor_skeleton_init(GladeEditorSkeleton * skeleton)59 glade_editor_skeleton_init (GladeEditorSkeleton *skeleton)
60 {
61 skeleton->priv = glade_editor_skeleton_get_instance_private (skeleton);
62 }
63
64 static void
glade_editor_skeleton_class_init(GladeEditorSkeletonClass * klass)65 glade_editor_skeleton_class_init (GladeEditorSkeletonClass *klass)
66 {
67 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
68
69 gobject_class->dispose = glade_editor_skeleton_dispose;
70 }
71
72 /***********************************************************
73 * GObjectClass *
74 ***********************************************************/
75 static void
glade_editor_skeleton_dispose(GObject * object)76 glade_editor_skeleton_dispose (GObject *object)
77 {
78 GladeEditorSkeleton *skeleton = GLADE_EDITOR_SKELETON (object);
79 GladeEditorSkeletonPrivate *priv = skeleton->priv;
80
81 if (priv->editors)
82 {
83 g_slist_free_full (priv->editors, (GDestroyNotify)g_object_unref);
84 priv->editors = NULL;
85 }
86
87 G_OBJECT_CLASS (glade_editor_skeleton_parent_class)->dispose (object);
88 }
89
90 /*******************************************************************************
91 * GladeEditableIface *
92 *******************************************************************************/
93 static void
glade_editor_skeleton_load(GladeEditable * editable,GladeWidget * widget)94 glade_editor_skeleton_load (GladeEditable *editable,
95 GladeWidget *widget)
96 {
97 GladeEditorSkeleton *skeleton = GLADE_EDITOR_SKELETON (editable);
98 GladeEditorSkeletonPrivate *priv = skeleton->priv;
99 GSList *l;
100
101 /* Chain up to default implementation */
102 parent_editable_iface->load (editable, widget);
103
104 for (l = priv->editors; l; l = l->next)
105 {
106 GladeEditable *editor = l->data;
107
108 glade_editable_load (editor, widget);
109 }
110 }
111
112 static void
glade_editor_skeleton_set_show_name(GladeEditable * editable,gboolean show_name)113 glade_editor_skeleton_set_show_name (GladeEditable *editable, gboolean show_name)
114 {
115 GladeEditorSkeleton *skeleton = GLADE_EDITOR_SKELETON (editable);
116 GladeEditorSkeletonPrivate *priv = skeleton->priv;
117 GSList *l;
118
119 for (l = priv->editors; l; l = l->next)
120 {
121 GladeEditable *editor = l->data;
122
123 glade_editable_set_show_name (editor, show_name);
124 }
125 }
126
127 static void
glade_editor_skeleton_editable_init(GladeEditableIface * iface)128 glade_editor_skeleton_editable_init (GladeEditableIface *iface)
129 {
130 parent_editable_iface = g_type_default_interface_peek (GLADE_TYPE_EDITABLE);
131
132 iface->load = glade_editor_skeleton_load;
133 iface->set_show_name = glade_editor_skeleton_set_show_name;
134 }
135
136 /*******************************************************************************
137 * GtkBuildableIface *
138 *******************************************************************************/
139 typedef struct
140 {
141 GSList *editors;
142 } EditorParserData;
143
144 static void
editor_start_element(GMarkupParseContext * context,const gchar * element_name,const gchar ** names,const gchar ** values,gpointer user_data,GError ** error)145 editor_start_element (GMarkupParseContext *context,
146 const gchar *element_name,
147 const gchar **names,
148 const gchar **values,
149 gpointer user_data,
150 GError **error)
151 {
152 EditorParserData *editor_data = (EditorParserData *)user_data;
153 gchar *id;
154
155 if (strcmp (element_name, "editor") == 0)
156 {
157 if (g_markup_collect_attributes (element_name,
158 names,
159 values,
160 error,
161 G_MARKUP_COLLECT_STRDUP, "id", &id,
162 G_MARKUP_COLLECT_INVALID))
163 {
164 editor_data->editors = g_slist_append (editor_data->editors, id);
165 }
166 }
167 else if (strcmp (element_name, "child-editors") == 0)
168 ;
169 else
170 g_warning ("Unsupported tag for GladeEditorSkeleton: %s\n", element_name);
171 }
172
173 static const GMarkupParser editor_parser =
174 {
175 editor_start_element,
176 };
177
178 static gboolean
glade_editor_skeleton_custom_tag_start(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * tagname,GMarkupParser * parser,gpointer * data)179 glade_editor_skeleton_custom_tag_start (GtkBuildable *buildable,
180 GtkBuilder *builder,
181 GObject *child,
182 const gchar *tagname,
183 GMarkupParser *parser,
184 gpointer *data)
185 {
186 if (strcmp (tagname, "child-editors") == 0)
187 {
188 EditorParserData *parser_data;
189
190 parser_data = g_slice_new0 (EditorParserData);
191 *parser = editor_parser;
192 *data = parser_data;
193 return TRUE;
194 }
195
196 return parent_buildable_iface->custom_tag_start (buildable, builder, child,
197 tagname, parser, data);
198 }
199
200 static void
glade_editor_skeleton_custom_finished(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * tagname,gpointer user_data)201 glade_editor_skeleton_custom_finished (GtkBuildable *buildable,
202 GtkBuilder *builder,
203 GObject *child,
204 const gchar *tagname,
205 gpointer user_data)
206 {
207 EditorParserData *editor_data = (EditorParserData *)user_data;
208 GSList *l;
209
210 if (strcmp (tagname, "child-editors") != 0)
211 {
212 parent_buildable_iface->custom_finished (buildable, builder, child,
213 tagname, user_data);
214 return;
215 }
216
217 for (l = editor_data->editors; l; l = l->next)
218 {
219 GObject *object;
220 gchar *id = l->data;
221
222 object = gtk_builder_get_object (builder, id);
223
224 if (!GLADE_EDITABLE (object))
225 g_warning ("Object '%s' is not a GladeEditable\n",
226 object ? G_OBJECT_TYPE_NAME (object) : "(null)");
227 else
228 glade_editor_skeleton_add_editor (GLADE_EDITOR_SKELETON (buildable),
229 GLADE_EDITABLE (object));
230 }
231
232 g_slist_free_full (editor_data->editors, g_free);
233 g_slice_free (EditorParserData, editor_data);
234 }
235
236 static void
glade_editor_skeleton_buildable_init(GtkBuildableIface * iface)237 glade_editor_skeleton_buildable_init (GtkBuildableIface *iface)
238 {
239 parent_buildable_iface = g_type_interface_peek_parent (iface);
240 iface->custom_tag_start = glade_editor_skeleton_custom_tag_start;
241 iface->custom_finished = glade_editor_skeleton_custom_finished;
242 }
243
244 /*******************************************************************************
245 * API *
246 *******************************************************************************/
247 GtkWidget *
glade_editor_skeleton_new(void)248 glade_editor_skeleton_new (void)
249 {
250 return g_object_new (GLADE_TYPE_EDITOR_SKELETON, NULL);
251 }
252
253 void
glade_editor_skeleton_add_editor(GladeEditorSkeleton * skeleton,GladeEditable * editor)254 glade_editor_skeleton_add_editor (GladeEditorSkeleton *skeleton,
255 GladeEditable *editor)
256 {
257 GladeEditorSkeletonPrivate *priv;
258
259 g_return_if_fail (GLADE_IS_EDITOR_SKELETON (skeleton));
260 g_return_if_fail (GLADE_IS_EDITABLE (editor));
261
262 priv = skeleton->priv;
263
264 g_object_ref (editor);
265 priv->editors = g_slist_prepend (priv->editors, editor);
266 }
267