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