]> www.fi.muni.cz Git - evince.git/blob - cut-n-paste/toolbar-editor/egg-toolbars-model.c
56f4c8fbf2fae9eae0c163429745072164a7a738
[evince.git] / cut-n-paste / toolbar-editor / egg-toolbars-model.c
1 /*
2  *  Copyright (C) 2002-2004 Marco Pesenti Gritti
3  *  Copyright (C) 2004 Christian Persch
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  *  $Id$
20  */
21
22 #include "config.h"
23
24 #include "egg-toolbars-model.h"
25 #include "eggtypebuiltins.h"
26 #include "eggmarshalers.h"
27
28 #include <unistd.h>
29 #include <string.h>
30 #include <libxml/tree.h>
31 #include <gdk/gdkproperty.h>
32
33 static void egg_toolbars_model_class_init (EggToolbarsModelClass *klass);
34 static void egg_toolbars_model_init       (EggToolbarsModel      *t);
35 static void egg_toolbars_model_finalize   (GObject               *object);
36
37 enum
38 {
39   ITEM_ADDED,
40   ITEM_REMOVED,
41   TOOLBAR_ADDED,
42   TOOLBAR_CHANGED,
43   TOOLBAR_REMOVED,
44   GET_ITEM_TYPE,
45   GET_ITEM_ID,
46   GET_ITEM_DATA,
47   LAST_SIGNAL
48 };
49
50 typedef struct
51 {
52   char *name;
53   EggTbModelFlags flags;
54 } EggToolbarsToolbar;
55
56 typedef struct
57 {
58   char *id;
59   char *type;
60   gboolean separator;
61 } EggToolbarsItem;
62
63 static guint signals[LAST_SIGNAL] = { 0 };
64
65 static GObjectClass *parent_class = NULL;
66
67 #define EGG_TOOLBARS_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_TOOLBARS_MODEL, EggToolbarsModelPrivate))
68
69 struct EggToolbarsModelPrivate
70 {
71   GNode *toolbars;
72 };
73
74 GType
75 egg_toolbars_model_get_type (void)
76 {
77   static GType type = 0;
78
79   if (G_UNLIKELY (type == 0))
80     {
81       static const GTypeInfo our_info = {
82         sizeof (EggToolbarsModelClass),
83         NULL,                   /* base_init */
84         NULL,                   /* base_finalize */
85         (GClassInitFunc) egg_toolbars_model_class_init,
86         NULL,
87         NULL,                   /* class_data */
88         sizeof (EggToolbarsModel),
89         0,                      /* n_preallocs */
90         (GInstanceInitFunc) egg_toolbars_model_init
91       };
92       volatile GType flags_type; /* work around gcc's optimiser */
93
94       /* make sure the flags type is known */
95       flags_type = EGG_TYPE_TB_MODEL_FLAGS;
96
97       type = g_type_register_static (G_TYPE_OBJECT,
98                                      "EggToolbarsModel",
99                                      &our_info, 0);
100     }
101
102   return type;
103 }
104
105 static xmlDocPtr
106 egg_toolbars_model_to_xml (EggToolbarsModel *t)
107 {
108   GNode *l1, *l2, *tl;
109   xmlDocPtr doc;
110
111   g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), NULL);
112
113   tl = t->priv->toolbars;
114
115   xmlIndentTreeOutput = TRUE;
116   doc = xmlNewDoc ((const xmlChar*) "1.0");
117   doc->children = xmlNewDocNode (doc, NULL, (const xmlChar*) "toolbars", NULL);
118
119   for (l1 = tl->children; l1 != NULL; l1 = l1->next)
120     {
121       xmlNodePtr tnode;
122       EggToolbarsToolbar *toolbar = l1->data;
123
124       tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL);
125       xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name);
126
127       for (l2 = l1->children; l2 != NULL; l2 = l2->next)
128         {
129           xmlNodePtr node;
130           EggToolbarsItem *item = l2->data;
131
132           if (item->separator)
133             {
134               node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL);
135             }
136           else
137             {
138               char *data;
139
140               node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL);
141               data = egg_toolbars_model_get_item_data (t, item->type, item->id);
142               xmlSetProp (node, (const xmlChar*) "type", (const xmlChar*) item->type);
143               xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) data);
144               g_free (data);
145             }
146         }
147     }
148
149   return doc;
150 }
151
152 static gboolean
153 safe_save_xml (const char *xml_file, xmlDocPtr doc)
154 {
155         char *tmp_file;
156         char *old_file;
157         gboolean old_exist;
158         gboolean retval = TRUE;
159
160         tmp_file = g_strconcat (xml_file, ".tmp", NULL);
161         old_file = g_strconcat (xml_file, ".old", NULL);
162
163         if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
164         {
165                 g_warning ("Failed to write XML data to %s", tmp_file);
166                 goto failed;
167         }
168
169         old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
170
171         if (old_exist)
172         {
173                 if (rename (xml_file, old_file) < 0)
174                 {
175                         g_warning ("Failed to rename %s to %s", xml_file, old_file);
176                         retval = FALSE;
177                         goto failed;
178                 }
179         }
180
181         if (rename (tmp_file, xml_file) < 0)
182         {
183                 g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
184
185                 if (rename (old_file, xml_file) < 0)
186                 {
187                         g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
188                 }
189                 retval = FALSE;
190                 goto failed;
191         }
192
193         if (old_exist)
194         {
195                 if (unlink (old_file) < 0)
196                 {
197                         g_warning ("Failed to delete old file %s", old_file);
198                 }
199         }
200
201         failed:
202         g_free (old_file);
203         g_free (tmp_file);
204
205         return retval;
206 }
207
208 void
209 egg_toolbars_model_save (EggToolbarsModel *t,
210                          const char *xml_file,
211                          const char *version)
212 {
213   xmlDocPtr doc;
214   xmlNodePtr root;
215
216   g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
217
218   doc = egg_toolbars_model_to_xml (t);
219   root = xmlDocGetRootElement (doc);
220   xmlSetProp (root, (const xmlChar*) "version", (const xmlChar*) version);
221   safe_save_xml (xml_file, doc);
222   xmlFreeDoc (doc);
223 }
224
225 static EggToolbarsToolbar *
226 toolbars_toolbar_new (const char *name)
227 {
228   EggToolbarsToolbar *toolbar;
229
230   toolbar = g_new (EggToolbarsToolbar, 1);
231   toolbar->name = g_strdup (name);
232   toolbar->flags = 0;
233
234   return toolbar;
235 }
236
237 static EggToolbarsItem *
238 toolbars_item_new (const char *id,
239                    const char *type,
240                    gboolean    separator)
241 {
242   EggToolbarsItem *item;
243
244   g_return_val_if_fail (id != NULL, NULL);
245   g_return_val_if_fail (type != NULL, NULL);
246
247   item = g_new (EggToolbarsItem, 1);
248   item->id = g_strdup (id);
249   item->type = g_strdup (type);
250   item->separator = separator;
251
252   return item;
253 }
254
255 static void
256 free_toolbar_node (GNode *toolbar_node)
257 {
258   EggToolbarsToolbar *toolbar = toolbar_node->data;
259
260   g_free (toolbar->name);
261   g_free (toolbar);
262
263   g_node_destroy (toolbar_node);
264 }
265
266 static void
267 free_item_node (GNode *item_node)
268 {
269   EggToolbarsItem *item = item_node->data;
270
271   g_free (item->id);
272   g_free (item->type);
273   g_free (item);
274
275   g_node_destroy (item_node);
276 }
277
278 EggTbModelFlags
279 egg_toolbars_model_get_flags (EggToolbarsModel *t,
280                               int               toolbar_position)
281 {
282   GNode *toolbar_node;
283   EggToolbarsToolbar *toolbar;
284
285   toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
286   g_return_val_if_fail (toolbar_node != NULL, 0);
287
288   toolbar = toolbar_node->data;
289
290   return toolbar->flags;
291 }
292
293 void
294 egg_toolbars_model_set_flags (EggToolbarsModel *t,
295                               int               toolbar_position,
296                               EggTbModelFlags   flags)
297 {
298   GNode *toolbar_node;
299   EggToolbarsToolbar *toolbar;
300
301   toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
302   g_return_if_fail (toolbar_node != NULL);
303
304   toolbar = toolbar_node->data;
305
306   toolbar->flags = flags;
307
308   g_signal_emit (G_OBJECT (t), signals[TOOLBAR_CHANGED],
309                  0, toolbar_position);
310 }
311
312 void
313 egg_toolbars_model_add_separator (EggToolbarsModel *t,
314                                   int               toolbar_position,
315                                   int               position)
316 {
317   GNode *parent_node;
318   GNode *node;
319   EggToolbarsItem *item;
320   int real_position;
321
322   g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
323
324   parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
325   item = toolbars_item_new ("separator", EGG_TOOLBAR_ITEM_TYPE, TRUE);
326   node = g_node_new (item);
327   g_node_insert (parent_node, position, node);
328
329   real_position = g_node_child_position (parent_node, node);
330
331   g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
332                  toolbar_position, real_position);
333 }
334
335 static gboolean
336 impl_add_item (EggToolbarsModel    *t,
337                int                  toolbar_position,
338                int                  position,
339                const char          *id,
340                const char          *type)
341 {
342   GNode *parent_node;
343   GNode *node;
344   EggToolbarsItem *item;
345   int real_position;
346
347   g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
348   g_return_val_if_fail (id != NULL, FALSE);
349   g_return_val_if_fail (type != NULL, FALSE);
350
351   parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
352   item = toolbars_item_new (id, type, FALSE);
353   node = g_node_new (item);
354   g_node_insert (parent_node, position, node);
355
356   real_position = g_node_child_position (parent_node, node);
357
358   g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
359                  toolbar_position, real_position);
360
361   return TRUE;
362 }
363
364 static void
365 parse_item_list (EggToolbarsModel *t,
366                  xmlNodePtr        child,
367                  int               position)
368 {
369   while (child)
370     {
371       if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
372         {
373           xmlChar *name, *type;
374           char *id;
375
376           name = xmlGetProp (child, (const xmlChar*) "name");
377           type = xmlGetProp (child, (const xmlChar*) "type");
378           if (type == NULL)
379             {
380               type = xmlCharStrdup (EGG_TOOLBAR_ITEM_TYPE);
381             }
382
383           if (name != NULL && name[0] != '\0' && type != NULL)
384             {
385               id = egg_toolbars_model_get_item_id (t, (const char*)type, (const char*)name);
386               if (id != NULL)
387                 {
388                   egg_toolbars_model_add_item (t, position, -1, id, (const char*)type);
389                 }
390               g_free (id);
391             }
392           xmlFree (name);
393           xmlFree (type);
394         }
395       else if (xmlStrEqual (child->name, (const xmlChar*) "separator"))
396         {
397           egg_toolbars_model_add_separator (t, position, -1);
398         }
399
400       child = child->next;
401     }
402 }
403
404 int
405 egg_toolbars_model_add_toolbar (EggToolbarsModel *t,
406                                 int               position,
407                                 const char       *name)
408 {
409   GNode *node;
410   int real_position;
411
412   g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), -1);
413
414   node = g_node_new (toolbars_toolbar_new (name));
415   g_node_insert (t->priv->toolbars, position, node);
416
417   real_position = g_node_child_position (t->priv->toolbars, node);
418
419   g_signal_emit (G_OBJECT (t), signals[TOOLBAR_ADDED],
420                  0, real_position);
421
422   return g_node_child_position (t->priv->toolbars, node);
423 }
424
425 static void
426 parse_toolbars (EggToolbarsModel *t,
427                 xmlNodePtr        child)
428 {
429   while (child)
430     {
431       if (xmlStrEqual (child->name, (const xmlChar*) "toolbar"))
432         {
433           xmlChar *name;
434           xmlChar *style;
435           int position;
436
437           name = xmlGetProp (child, (const xmlChar*) "name");
438           position = egg_toolbars_model_add_toolbar (t, -1, (const char*) name);
439           xmlFree (name);
440
441           style = xmlGetProp (child, (const xmlChar*) "style");
442           if (style && xmlStrEqual (style, (const xmlChar*) "icons-only"))
443             {
444               /* FIXME: use toolbar position instead of 0 */
445               egg_toolbars_model_set_flags (t, 0, EGG_TB_MODEL_ICONS);
446             }
447           xmlFree (style);
448
449           parse_item_list (t, child->children, position);
450         }
451
452       child = child->next;
453     }
454 }
455
456 gboolean
457 egg_toolbars_model_load (EggToolbarsModel *t,
458                          const char *xml_file)
459 {
460   xmlDocPtr doc;
461   xmlNodePtr root;
462
463   g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
464
465   if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
466
467   doc = xmlParseFile (xml_file);
468   if (doc == NULL)
469   {
470     g_warning ("Failed to load XML data from %s", xml_file);
471     return FALSE;
472   }
473   root = xmlDocGetRootElement (doc);
474
475   parse_toolbars (t, root->children);
476
477   xmlFreeDoc (doc);
478
479   return TRUE;
480 }
481
482 static char *
483 impl_get_item_id (EggToolbarsModel *t,
484                   const char       *type,
485                   const char       *data)
486 {
487   if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
488     {
489       return g_strdup (data);
490     }
491
492   return NULL;
493 }
494
495 static char *
496 impl_get_item_data (EggToolbarsModel *t,
497                     const char       *type,
498                     const char       *id)
499 {
500   if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
501     {
502       return g_strdup (id);
503     }
504
505   return NULL;
506 }
507
508 static char *
509 impl_get_item_type (EggToolbarsModel *t,
510                     GdkAtom type)
511 {
512   if (gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE) == type)
513     {
514       return g_strdup (EGG_TOOLBAR_ITEM_TYPE);
515     }
516
517   return NULL;
518 }
519
520 static gboolean
521 _egg_accumulator_STRING (GSignalInvocationHint *ihint,
522                          GValue                *return_accu,
523                          const GValue          *handler_return,
524                          gpointer               dummy)
525 {
526   gboolean continue_emission;
527   const char *retval;
528
529   retval = g_value_get_string (handler_return);
530   g_value_set_string (return_accu, retval);
531   continue_emission = !retval || !retval[0];
532   
533   return continue_emission;
534 }
535
536
537 static void
538 egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
539 {
540   GObjectClass *object_class = G_OBJECT_CLASS (klass);
541
542   parent_class = g_type_class_peek_parent (klass);
543
544   object_class->finalize = egg_toolbars_model_finalize;
545
546   klass->add_item = impl_add_item;
547   klass->get_item_id = impl_get_item_id;
548   klass->get_item_data = impl_get_item_data;
549   klass->get_item_type = impl_get_item_type;
550
551   signals[ITEM_ADDED] =
552     g_signal_new ("item_added",
553                   G_OBJECT_CLASS_TYPE (object_class),
554                   G_SIGNAL_RUN_LAST,
555                   G_STRUCT_OFFSET (EggToolbarsModelClass, item_added),
556                   NULL, NULL, _egg_marshal_VOID__INT_INT,
557                   G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
558   signals[TOOLBAR_ADDED] =
559     g_signal_new ("toolbar_added",
560                   G_OBJECT_CLASS_TYPE (object_class),
561                   G_SIGNAL_RUN_LAST,
562                   G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_added),
563                   NULL, NULL, g_cclosure_marshal_VOID__INT,
564                   G_TYPE_NONE, 1, G_TYPE_INT);
565   signals[ITEM_REMOVED] =
566     g_signal_new ("item_removed",
567                   G_OBJECT_CLASS_TYPE (object_class),
568                   G_SIGNAL_RUN_LAST,
569                   G_STRUCT_OFFSET (EggToolbarsModelClass, item_removed),
570                   NULL, NULL, _egg_marshal_VOID__INT_INT,
571                   G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
572   signals[TOOLBAR_REMOVED] =
573     g_signal_new ("toolbar_removed",
574                   G_OBJECT_CLASS_TYPE (object_class),
575                   G_SIGNAL_RUN_LAST,
576                   G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_removed),
577                   NULL, NULL, g_cclosure_marshal_VOID__INT,
578                   G_TYPE_NONE, 1, G_TYPE_INT);
579   signals[TOOLBAR_CHANGED] =
580     g_signal_new ("toolbar_changed",
581                   G_OBJECT_CLASS_TYPE (object_class),
582                   G_SIGNAL_RUN_LAST,
583                   G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed),
584                   NULL, NULL, g_cclosure_marshal_VOID__INT,
585                   G_TYPE_NONE, 1, G_TYPE_INT);
586   signals[GET_ITEM_TYPE] =
587     g_signal_new ("get_item_type",
588                   G_OBJECT_CLASS_TYPE (object_class),
589                   G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
590                   G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_type),
591                   _egg_accumulator_STRING, NULL,
592                   _egg_marshal_STRING__POINTER,
593                   G_TYPE_STRING, 1, G_TYPE_POINTER);
594   signals[GET_ITEM_ID] =
595     g_signal_new ("get_item_id",
596                   G_OBJECT_CLASS_TYPE (object_class),
597                   G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
598                   G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_id),
599                   _egg_accumulator_STRING, NULL,
600                   _egg_marshal_STRING__STRING_STRING,
601                   G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
602   signals[GET_ITEM_DATA] =
603     g_signal_new ("get_item_data",
604                   G_OBJECT_CLASS_TYPE (object_class),
605                   G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
606                   G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_data),
607                   _egg_accumulator_STRING, NULL,
608                   _egg_marshal_STRING__STRING_STRING,
609                   G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
610
611   g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate));
612 }
613
614 static void
615 egg_toolbars_model_init (EggToolbarsModel *t)
616 {
617   t->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (t);
618
619   t->priv->toolbars = g_node_new (NULL);
620 }
621
622 static void
623 free_toolbar (GNode *toolbar_node)
624 {
625   g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
626                            (GNodeForeachFunc) free_item_node, NULL);
627   free_toolbar_node (toolbar_node);
628 }
629
630 static void
631 egg_toolbars_model_finalize (GObject *object)
632 {
633   EggToolbarsModel *t = EGG_TOOLBARS_MODEL (object);
634
635   g_node_children_foreach (t->priv->toolbars, G_TRAVERSE_ALL,
636                            (GNodeForeachFunc) free_toolbar, NULL);
637   g_node_destroy (t->priv->toolbars);
638
639   G_OBJECT_CLASS (parent_class)->finalize (object);
640 }
641
642 EggToolbarsModel *
643 egg_toolbars_model_new (void)
644 {
645   return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
646 }
647
648 void
649 egg_toolbars_model_remove_toolbar (EggToolbarsModel   *t,
650                                    int                 position)
651 {
652   GNode *node;
653   EggTbModelFlags flags;
654
655   g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
656
657   flags = egg_toolbars_model_get_flags (t, position);
658
659   if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
660     {
661       node = g_node_nth_child (t->priv->toolbars, position);
662       g_return_if_fail (node != NULL);
663
664       free_toolbar_node (node);
665
666       g_signal_emit (G_OBJECT (t), signals[TOOLBAR_REMOVED],
667                      0, position);
668     }
669 }
670
671 void
672 egg_toolbars_model_remove_item (EggToolbarsModel *t,
673                                 int               toolbar_position,
674                                 int               position)
675 {
676   GNode *node, *toolbar;
677
678   g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
679
680   toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
681   g_return_if_fail (toolbar != NULL);
682
683   node = g_node_nth_child (toolbar, position);
684   g_return_if_fail (node != NULL);
685
686   free_item_node (node);
687
688   g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
689                  toolbar_position, position);
690 }
691
692 void
693 egg_toolbars_model_move_item (EggToolbarsModel *t,
694                               int               toolbar_position,
695                               int               position,
696                               int               new_toolbar_position,
697                               int               new_position)
698 {
699   GNode *node, *toolbar, *new_toolbar;
700
701   g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
702
703   toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
704   g_return_if_fail (toolbar != NULL);
705
706   new_toolbar = g_node_nth_child (t->priv->toolbars, new_toolbar_position);
707   g_return_if_fail (new_toolbar != NULL);
708
709   node = g_node_nth_child (toolbar, position);
710   g_return_if_fail (node != NULL);
711
712   g_node_unlink (node);
713
714   g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
715                  toolbar_position, position);
716
717   g_node_insert (new_toolbar, new_position, node);
718
719   g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
720                  new_toolbar_position, new_position);
721 }
722
723 int
724 egg_toolbars_model_n_items (EggToolbarsModel *t,
725                             int               toolbar_position)
726 {
727   GNode *toolbar;
728
729   toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
730   g_return_val_if_fail (toolbar != NULL, -1);
731
732   return g_node_n_children (toolbar);
733 }
734
735 void
736 egg_toolbars_model_item_nth (EggToolbarsModel *t,
737                              int               toolbar_position,
738                              int               position,
739                              gboolean         *is_separator,
740                              const char      **id,
741                              const char      **type)
742 {
743   GNode *toolbar;
744   GNode *item;
745   EggToolbarsItem *idata;
746
747   toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
748   g_return_if_fail (toolbar != NULL);
749
750   item = g_node_nth_child (toolbar, position);
751   g_return_if_fail (item != NULL);
752
753   idata = item->data;
754
755   *is_separator = idata->separator;
756
757   if (id)
758     {
759       *id = idata->id;
760     }
761
762   if (type)
763     {
764       *type = idata->type;
765     }
766 }
767
768 int
769 egg_toolbars_model_n_toolbars (EggToolbarsModel *t)
770 {
771   return g_node_n_children (t->priv->toolbars);
772 }
773
774 const char *
775 egg_toolbars_model_toolbar_nth (EggToolbarsModel *t,
776                                 int               position)
777 {
778   GNode *toolbar;
779   EggToolbarsToolbar *tdata;
780
781   toolbar = g_node_nth_child (t->priv->toolbars, position);
782   g_return_val_if_fail (toolbar != NULL, NULL);
783
784   tdata = toolbar->data;
785
786   return tdata->name;
787 }
788
789 gboolean
790 egg_toolbars_model_add_item (EggToolbarsModel *t,
791                              int               toolbar_position,
792                              int               position,
793                              const char       *id,
794                              const char       *type)
795 {
796   EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (t);
797   return klass->add_item (t, toolbar_position, position, id, type);
798 }
799
800 char *
801 egg_toolbars_model_get_item_id (EggToolbarsModel *t,
802                                 const char       *type,
803                                 const char       *name)
804 {
805   char *retval;
806
807   g_signal_emit (t, signals[GET_ITEM_ID], 0, type, name, &retval);
808
809   return retval;
810 }
811
812 char *
813 egg_toolbars_model_get_item_data (EggToolbarsModel *t,
814                                   const char       *type,
815                                   const char       *id)
816 {
817   char *retval;
818
819   g_signal_emit (t, signals[GET_ITEM_DATA], 0, type, id, &retval);
820
821   return retval;
822 }
823
824 char *
825 egg_toolbars_model_get_item_type (EggToolbarsModel *t,
826                                   GdkAtom type)
827 {
828   char *retval;
829
830   g_signal_emit (t, signals[GET_ITEM_TYPE], 0, type, &retval);
831
832   return retval;
833 }