]> Pileus Git - ~andy/gtk/blob - gtk/gtkcelllayout.c
Do not assume that text is null-terminated as pointed out by Christopher
[~andy/gtk] / gtk / gtkcelllayout.c
1 /* gtkcelllayout.c
2  * Copyright (C) 2003  Kristian Rietveld  <kris@gtk.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include "gtkcelllayout.h"
25 #include "gtkintl.h"
26 #include "gtkalias.h"
27
28 GType
29 gtk_cell_layout_get_type (void)
30 {
31   static GType cell_layout_type = 0;
32
33   if (! cell_layout_type)
34     {
35       const GTypeInfo cell_layout_info =
36       {
37         sizeof (GtkCellLayoutIface),
38         NULL,
39         NULL,
40         NULL,
41         NULL,
42         NULL,
43         0,
44         0,
45         NULL
46       };
47
48       cell_layout_type =
49         g_type_register_static (G_TYPE_INTERFACE, I_("GtkCellLayout"),
50                                 &cell_layout_info, 0);
51
52       g_type_interface_add_prerequisite (cell_layout_type, G_TYPE_OBJECT);
53     }
54
55   return cell_layout_type;
56 }
57
58 /**
59  * gtk_cell_layout_pack_start:
60  * @cell_layout: A #GtkCellLayout.
61  * @cell: A #GtkCellRenderer.
62  * @expand: %TRUE if @cell is to be given extra space allocated to @cell_layout.
63  *
64  * Packs the @cell into the beginning of @cell_layout. If @expand is %FALSE,
65  * then the @cell is allocated no more space than it needs. Any unused space
66  * is divided evenly between cells for which @expand is %TRUE.
67  *
68  * Note that reusing the same cell renderer is not supported. 
69  *
70  * Since: 2.4
71  */
72 void
73 gtk_cell_layout_pack_start (GtkCellLayout   *cell_layout,
74                             GtkCellRenderer *cell,
75                             gboolean         expand)
76 {
77   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
78   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
79
80   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_start) (cell_layout,
81                                                            cell,
82                                                            expand);
83 }
84
85 /**
86  * gtk_cell_layout_pack_end:
87  * @cell_layout: A #GtkCellLayout.
88  * @cell: A #GtkCellRenderer.
89  * @expand: %TRUE if @cell is to be given extra space allocated to @cell_layout.
90  *
91  * Adds the @cell to the end of @cell_layout. If @expand is %FALSE, then the
92  * @cell is allocated no more space than it needs. Any unused space is
93  * divided evenly between cells for which @expand is %TRUE.
94  *
95  * Note that reusing the same cell renderer is not supported. 
96  *
97  * Since: 2.4
98  */
99 void
100 gtk_cell_layout_pack_end (GtkCellLayout   *cell_layout,
101                           GtkCellRenderer *cell,
102                           gboolean         expand)
103 {
104   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
105   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
106
107   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->pack_end) (cell_layout,
108                                                          cell,
109                                                          expand);
110 }
111
112 /**
113  * gtk_cell_layout_clear:
114  * @cell_layout: A #GtkCellLayout.
115  *
116  * Unsets all the mappings on all renderers on @cell_layout and
117  * removes all renderers from @cell_layout.
118  *
119  * Since: 2.4
120  */
121 void
122 gtk_cell_layout_clear (GtkCellLayout *cell_layout)
123 {
124   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
125
126   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear) (cell_layout);
127 }
128
129 static void
130 gtk_cell_layout_set_attributesv (GtkCellLayout   *cell_layout,
131                                  GtkCellRenderer *cell,
132                                  va_list          args)
133 {
134   gchar *attribute;
135   gint column;
136   GtkCellLayoutIface *iface;
137
138   attribute = va_arg (args, gchar *);
139
140   iface = GTK_CELL_LAYOUT_GET_IFACE (cell_layout);
141
142   (* iface->clear_attributes) (cell_layout, cell);
143
144   while (attribute != NULL)
145     {
146       column = va_arg (args, gint);
147       (* iface->add_attribute) (cell_layout, cell, attribute, column);
148       attribute = va_arg (args, gchar *);
149     }
150 }
151
152 /**
153  * gtk_cell_layout_set_attributes:
154  * @cell_layout: A #GtkCellLayout.
155  * @cell: A #GtkCellRenderer.
156  * @Varargs: A %NULL-terminated list of attributes.
157  *
158  * Sets the attributes in list as the attributes of @cell_layout. The
159  * attributes should be in attribute/column order, as in
160  * gtk_cell_layout_add_attribute(). All existing attributes are removed, and
161  * replaced with the new attributes.
162  *
163  * Since: 2.4
164  */
165 void
166 gtk_cell_layout_set_attributes (GtkCellLayout   *cell_layout,
167                                 GtkCellRenderer *cell,
168                                 ...)
169 {
170   va_list args;
171
172   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
173   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
174
175   va_start (args, cell);
176   gtk_cell_layout_set_attributesv (cell_layout, cell, args);
177   va_end (args);
178 }
179
180 /**
181  * gtk_cell_layout_add_attribute:
182  * @cell_layout: A #GtkCellLayout.
183  * @cell: A #GtkCellRenderer.
184  * @attribute: An attribute on the renderer.
185  * @column: The column position on the model to get the attribute from.
186  *
187  * Adds an attribute mapping to the list in @cell_layout. The @column is the
188  * column of the model to get a value from, and the @attribute is the
189  * parameter on @cell to be set from the value. So for example if column 2
190  * of the model contains strings, you could have the "text" attribute of a
191  * #GtkCellRendererText get its values from column 2.
192  *
193  * Since: 2.4
194  */
195 void
196 gtk_cell_layout_add_attribute (GtkCellLayout   *cell_layout,
197                                GtkCellRenderer *cell,
198                                const gchar     *attribute,
199                                gint             column)
200 {
201   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
202   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
203   g_return_if_fail (attribute != NULL);
204   g_return_if_fail (column >= 0);
205
206   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->add_attribute) (cell_layout,
207                                                               cell,
208                                                               attribute,
209                                                               column);
210 }
211
212 /**
213  * gtk_cell_layout_set_cell_data_func:
214  * @cell_layout: A #GtkCellLayout.
215  * @cell: A #GtkCellRenderer.
216  * @func: The #GtkCellLayoutDataFunc to use.
217  * @func_data: The user data for @func.
218  * @destroy: The destroy notification for @func_data.
219  *
220  * Sets the #GtkCellLayoutDataFunc to use for @cell_layout. This function
221  * is used instead of the standard attributes mapping for setting the
222  * column value, and should set the value of @cell_layout's cell renderer(s)
223  * as appropriate. @func may be %NULL to remove and older one.
224  *
225  * Since: 2.4
226  */
227 void
228 gtk_cell_layout_set_cell_data_func (GtkCellLayout         *cell_layout,
229                                     GtkCellRenderer       *cell,
230                                     GtkCellLayoutDataFunc  func,
231                                     gpointer               func_data,
232                                     GDestroyNotify         destroy)
233 {
234   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
235   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
236
237   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->set_cell_data_func) (cell_layout,
238                                                                    cell,
239                                                                    func,
240                                                                    func_data,
241                                                                    destroy);
242 }
243
244 /**
245  * gtk_cell_layout_clear_attributes:
246  * @cell_layout: A #GtkCellLayout.
247  * @cell: A #GtkCellRenderer to clear the attribute mapping on.
248  *
249  * Clears all existing attributes previously set with
250  * gtk_cell_layout_set_attributes().
251  *
252  * Since: 2.4
253  */
254 void
255 gtk_cell_layout_clear_attributes (GtkCellLayout   *cell_layout,
256                                   GtkCellRenderer *cell)
257 {
258   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
259   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
260
261   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->clear_attributes) (cell_layout,
262                                                                  cell);
263 }
264
265 /**
266  * gtk_cell_layout_reorder:
267  * @cell_layout: A #GtkCellLayout.
268  * @cell: A #GtkCellRenderer to reorder.
269  * @position: New position to insert @cell at.
270  *
271  * Re-inserts @cell at @position. Note that @cell has already to be packed
272  * into @cell_layout for this to function properly.
273  *
274  * Since: 2.4
275  */
276 void
277 gtk_cell_layout_reorder (GtkCellLayout   *cell_layout,
278                          GtkCellRenderer *cell,
279                          gint             position)
280 {
281   g_return_if_fail (GTK_IS_CELL_LAYOUT (cell_layout));
282   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
283
284   (* GTK_CELL_LAYOUT_GET_IFACE (cell_layout)->reorder) (cell_layout,
285                                                         cell,
286                                                         position);
287 }
288
289 /**
290  * gtk_cell_layout_get_cells:
291  * @cell_layout: a #GtkCellLayout
292  * 
293  * Returns the cell renderers which have been added to @cell_layout.
294  *
295  * Return value: a list of cell renderers. The list, but not the
296  *   renderers has been newly allocated and should be freed with
297  *   g_list_free() when no longer needed.
298  * 
299  * Since: 2.12
300  */
301 GList *
302 gtk_cell_layout_get_cells (GtkCellLayout *cell_layout)
303 {
304   GtkCellLayoutIface *iface;
305
306   g_return_val_if_fail (GTK_IS_CELL_LAYOUT (cell_layout), NULL);
307
308   iface = GTK_CELL_LAYOUT_GET_IFACE (cell_layout);  
309   if (iface->get_cells)
310     return iface->get_cells (cell_layout);
311
312   return NULL;
313 }
314
315 typedef struct {
316   GtkCellLayout   *cell_layout;
317   GtkCellRenderer *renderer;
318   gchar           *attr_name;
319 } AttributesSubParserData;
320
321 static void
322 attributes_start_element (GMarkupParseContext *context,
323                           const gchar         *element_name,
324                           const gchar        **names,
325                           const gchar        **values,
326                           gpointer             user_data,
327                           GError             **error)
328 {
329   AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
330   guint i;
331
332   if (strcmp (element_name, "attribute") == 0)
333     for (i = 0; names[i]; i++)
334       if (strcmp (names[i], "name") == 0)
335         parser_data->attr_name = g_strdup (values[i]);
336   else if (strcmp (element_name, "attributes") == 0)
337     return;
338   else
339     g_warning ("Unsupported tag for GtkCellLayout: %s\n", element_name);
340 }
341
342 static void
343 attributes_text_element (GMarkupParseContext *context,
344                          const gchar         *text,
345                          gsize                text_len,
346                          gpointer             user_data,
347                          GError             **error)
348 {
349   AttributesSubParserData *parser_data = (AttributesSubParserData*)user_data;
350   glong l;
351   gchar *endptr;
352   gchar *string;
353   
354   if (!parser_data->attr_name)
355     return;
356
357   errno = 0;
358   string = g_strndup (text, text_len);
359   l = strtol (string, &endptr, 0);
360   if (errno || endptr == string)
361     {
362       g_set_error (error, 
363                    GTK_BUILDER_ERROR,
364                    GTK_BUILDER_ERROR_INVALID_VALUE,
365                    "Could not parse integer `%s'",
366                    string);
367       g_free (string);
368       return;
369     }
370   g_free (string);
371
372   gtk_cell_layout_add_attribute (parser_data->cell_layout,
373                                  parser_data->renderer,
374                                  parser_data->attr_name, l);
375   g_free (parser_data->attr_name);
376   parser_data->attr_name = NULL;
377 }
378
379 static const GMarkupParser attributes_parser =
380   {
381     attributes_start_element,
382     NULL,
383     attributes_text_element,
384   };
385
386 gboolean
387 _gtk_cell_layout_buildable_custom_tag_start (GtkBuildable  *buildable,
388                                              GtkBuilder    *builder,
389                                              GObject       *child,
390                                              const gchar   *tagname,
391                                              GMarkupParser *parser,
392                                              gpointer      *data)
393 {
394   AttributesSubParserData *parser_data;
395
396   if (!child)
397     return FALSE;
398
399   if (strcmp (tagname, "attributes") == 0)
400     {
401       parser_data = g_slice_new0 (AttributesSubParserData);
402       parser_data->cell_layout = GTK_CELL_LAYOUT (buildable);
403       parser_data->renderer = GTK_CELL_RENDERER (child);
404       parser_data->attr_name = NULL;
405
406       *parser = attributes_parser;
407       *data = parser_data;
408       return TRUE;
409     }
410
411   return FALSE;
412 }
413
414 void
415 _gtk_cell_layout_buildable_custom_tag_end (GtkBuildable *buildable,
416                                            GtkBuilder   *builder,
417                                            GObject      *child,
418                                            const gchar  *tagname,
419                                            gpointer     *data)
420 {
421   AttributesSubParserData *parser_data;
422
423   parser_data = (AttributesSubParserData*)data;
424   g_assert (!parser_data->attr_name);
425   g_slice_free (AttributesSubParserData, parser_data);
426 }
427
428 void
429 _gtk_cell_layout_buildable_add_child (GtkBuildable      *buildable,
430                                       GtkBuilder        *builder,
431                                       GObject           *child,
432                                       const gchar       *type)
433 {
434   GtkCellLayoutIface *iface;
435   
436   g_return_if_fail (GTK_IS_CELL_LAYOUT (buildable));
437   g_return_if_fail (GTK_IS_CELL_RENDERER (child));
438
439   iface = GTK_CELL_LAYOUT_GET_IFACE (buildable);
440   g_return_if_fail (iface->pack_start != NULL);
441   iface->pack_start (GTK_CELL_LAYOUT (buildable), GTK_CELL_RENDERER (child), FALSE);
442 }
443
444 #define __GTK_CELL_LAYOUT_C__
445 #include "gtkaliasdef.c"