2 * Copyright (C) 2002-2004 Marco Pesenti Gritti
3 * Copyright (C) 2004 Christian Persch
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)
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.
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.
24 #include "egg-toolbars-model.h"
25 #include "eggtypebuiltins.h"
26 #include "eggmarshalers.h"
30 #include <libxml/tree.h>
31 #include <gdk/gdkproperty.h>
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);
53 EggTbModelFlags flags;
63 static guint signals[LAST_SIGNAL] = { 0 };
65 static GObjectClass *parent_class = NULL;
67 #define EGG_TOOLBARS_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_TOOLBARS_MODEL, EggToolbarsModelPrivate))
69 struct EggToolbarsModelPrivate
75 egg_toolbars_model_get_type (void)
77 static GType type = 0;
79 if (G_UNLIKELY (type == 0))
81 static const GTypeInfo our_info = {
82 sizeof (EggToolbarsModelClass),
84 NULL, /* base_finalize */
85 (GClassInitFunc) egg_toolbars_model_class_init,
87 NULL, /* class_data */
88 sizeof (EggToolbarsModel),
90 (GInstanceInitFunc) egg_toolbars_model_init
92 volatile GType flags_type; /* work around gcc's optimiser */
94 /* make sure the flags type is known */
95 flags_type = EGG_TYPE_TB_MODEL_FLAGS;
97 type = g_type_register_static (G_TYPE_OBJECT,
106 egg_toolbars_model_to_xml (EggToolbarsModel *t)
111 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), NULL);
113 tl = t->priv->toolbars;
115 xmlIndentTreeOutput = TRUE;
116 doc = xmlNewDoc ((const xmlChar*) "1.0");
117 doc->children = xmlNewDocNode (doc, NULL, (const xmlChar*) "toolbars", NULL);
119 for (l1 = tl->children; l1 != NULL; l1 = l1->next)
122 EggToolbarsToolbar *toolbar = l1->data;
124 tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL);
125 xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name);
127 for (l2 = l1->children; l2 != NULL; l2 = l2->next)
130 EggToolbarsItem *item = l2->data;
134 node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL);
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);
153 safe_save_xml (const char *xml_file, xmlDocPtr doc)
158 gboolean retval = TRUE;
160 tmp_file = g_strconcat (xml_file, ".tmp", NULL);
161 old_file = g_strconcat (xml_file, ".old", NULL);
163 if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
165 g_warning ("Failed to write XML data to %s", tmp_file);
169 old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
173 if (rename (xml_file, old_file) < 0)
175 g_warning ("Failed to rename %s to %s", xml_file, old_file);
181 if (rename (tmp_file, xml_file) < 0)
183 g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
185 if (rename (old_file, xml_file) < 0)
187 g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
195 if (unlink (old_file) < 0)
197 g_warning ("Failed to delete old file %s", old_file);
209 egg_toolbars_model_save (EggToolbarsModel *t,
210 const char *xml_file,
216 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
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);
225 static EggToolbarsToolbar *
226 toolbars_toolbar_new (const char *name)
228 EggToolbarsToolbar *toolbar;
230 toolbar = g_new (EggToolbarsToolbar, 1);
231 toolbar->name = g_strdup (name);
237 static EggToolbarsItem *
238 toolbars_item_new (const char *id,
242 EggToolbarsItem *item;
244 g_return_val_if_fail (id != NULL, NULL);
245 g_return_val_if_fail (type != NULL, NULL);
247 item = g_new (EggToolbarsItem, 1);
248 item->id = g_strdup (id);
249 item->type = g_strdup (type);
250 item->separator = separator;
256 free_toolbar_node (GNode *toolbar_node)
258 EggToolbarsToolbar *toolbar = toolbar_node->data;
260 g_free (toolbar->name);
263 g_node_destroy (toolbar_node);
267 free_item_node (GNode *item_node)
269 EggToolbarsItem *item = item_node->data;
275 g_node_destroy (item_node);
279 egg_toolbars_model_get_flags (EggToolbarsModel *t,
280 int toolbar_position)
283 EggToolbarsToolbar *toolbar;
285 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
286 g_return_val_if_fail (toolbar_node != NULL, 0);
288 toolbar = toolbar_node->data;
290 return toolbar->flags;
294 egg_toolbars_model_set_flags (EggToolbarsModel *t,
295 int toolbar_position,
296 EggTbModelFlags flags)
299 EggToolbarsToolbar *toolbar;
301 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
302 g_return_if_fail (toolbar_node != NULL);
304 toolbar = toolbar_node->data;
306 toolbar->flags = flags;
308 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_CHANGED],
309 0, toolbar_position);
313 egg_toolbars_model_add_separator (EggToolbarsModel *t,
314 int toolbar_position,
319 EggToolbarsItem *item;
322 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
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);
329 real_position = g_node_child_position (parent_node, node);
331 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
332 toolbar_position, real_position);
336 impl_add_item (EggToolbarsModel *t,
337 int toolbar_position,
344 EggToolbarsItem *item;
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);
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);
356 real_position = g_node_child_position (parent_node, node);
358 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
359 toolbar_position, real_position);
365 parse_item_list (EggToolbarsModel *t,
371 if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
373 xmlChar *name, *type;
376 name = xmlGetProp (child, (const xmlChar*) "name");
377 type = xmlGetProp (child, (const xmlChar*) "type");
380 type = xmlCharStrdup (EGG_TOOLBAR_ITEM_TYPE);
383 if (name != NULL && name[0] != '\0' && type != NULL)
385 id = egg_toolbars_model_get_item_id (t, (const char*)type, (const char*)name);
388 egg_toolbars_model_add_item (t, position, -1, id, (const char*)type);
395 else if (xmlStrEqual (child->name, (const xmlChar*) "separator"))
397 egg_toolbars_model_add_separator (t, position, -1);
405 egg_toolbars_model_add_toolbar (EggToolbarsModel *t,
412 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), -1);
414 node = g_node_new (toolbars_toolbar_new (name));
415 g_node_insert (t->priv->toolbars, position, node);
417 real_position = g_node_child_position (t->priv->toolbars, node);
419 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_ADDED],
422 return g_node_child_position (t->priv->toolbars, node);
426 parse_toolbars (EggToolbarsModel *t,
431 if (xmlStrEqual (child->name, (const xmlChar*) "toolbar"))
437 name = xmlGetProp (child, (const xmlChar*) "name");
438 position = egg_toolbars_model_add_toolbar (t, -1, (const char*) name);
441 style = xmlGetProp (child, (const xmlChar*) "style");
442 if (style && xmlStrEqual (style, (const xmlChar*) "icons-only"))
444 /* FIXME: use toolbar position instead of 0 */
445 egg_toolbars_model_set_flags (t, 0, EGG_TB_MODEL_ICONS);
449 parse_item_list (t, child->children, position);
457 egg_toolbars_model_load (EggToolbarsModel *t,
458 const char *xml_file)
463 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
465 if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
467 doc = xmlParseFile (xml_file);
470 g_warning ("Failed to load XML data from %s", xml_file);
473 root = xmlDocGetRootElement (doc);
475 parse_toolbars (t, root->children);
483 impl_get_item_id (EggToolbarsModel *t,
487 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
489 return g_strdup (data);
496 impl_get_item_data (EggToolbarsModel *t,
500 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
502 return g_strdup (id);
509 impl_get_item_type (EggToolbarsModel *t,
512 if (gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE) == type)
514 return g_strdup (EGG_TOOLBAR_ITEM_TYPE);
521 _egg_accumulator_STRING (GSignalInvocationHint *ihint,
523 const GValue *handler_return,
526 gboolean continue_emission;
529 retval = g_value_get_string (handler_return);
530 g_value_set_string (return_accu, retval);
531 continue_emission = !retval || !retval[0];
533 return continue_emission;
538 egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
540 GObjectClass *object_class = G_OBJECT_CLASS (klass);
542 parent_class = g_type_class_peek_parent (klass);
544 object_class->finalize = egg_toolbars_model_finalize;
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;
551 signals[ITEM_ADDED] =
552 g_signal_new ("item_added",
553 G_OBJECT_CLASS_TYPE (object_class),
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),
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),
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),
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),
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);
611 g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate));
615 egg_toolbars_model_init (EggToolbarsModel *t)
617 t->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (t);
619 t->priv->toolbars = g_node_new (NULL);
623 free_toolbar (GNode *toolbar_node)
625 g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
626 (GNodeForeachFunc) free_item_node, NULL);
627 free_toolbar_node (toolbar_node);
631 egg_toolbars_model_finalize (GObject *object)
633 EggToolbarsModel *t = EGG_TOOLBARS_MODEL (object);
635 g_node_children_foreach (t->priv->toolbars, G_TRAVERSE_ALL,
636 (GNodeForeachFunc) free_toolbar, NULL);
637 g_node_destroy (t->priv->toolbars);
639 G_OBJECT_CLASS (parent_class)->finalize (object);
643 egg_toolbars_model_new (void)
645 return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
649 egg_toolbars_model_remove_toolbar (EggToolbarsModel *t,
653 EggTbModelFlags flags;
655 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
657 flags = egg_toolbars_model_get_flags (t, position);
659 if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
661 node = g_node_nth_child (t->priv->toolbars, position);
662 g_return_if_fail (node != NULL);
664 free_toolbar_node (node);
666 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_REMOVED],
672 egg_toolbars_model_remove_item (EggToolbarsModel *t,
673 int toolbar_position,
676 GNode *node, *toolbar;
678 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
680 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
681 g_return_if_fail (toolbar != NULL);
683 node = g_node_nth_child (toolbar, position);
684 g_return_if_fail (node != NULL);
686 free_item_node (node);
688 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
689 toolbar_position, position);
693 egg_toolbars_model_move_item (EggToolbarsModel *t,
694 int toolbar_position,
696 int new_toolbar_position,
699 GNode *node, *toolbar, *new_toolbar;
701 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
703 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
704 g_return_if_fail (toolbar != NULL);
706 new_toolbar = g_node_nth_child (t->priv->toolbars, new_toolbar_position);
707 g_return_if_fail (new_toolbar != NULL);
709 node = g_node_nth_child (toolbar, position);
710 g_return_if_fail (node != NULL);
712 g_node_unlink (node);
714 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
715 toolbar_position, position);
717 g_node_insert (new_toolbar, new_position, node);
719 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
720 new_toolbar_position, new_position);
724 egg_toolbars_model_n_items (EggToolbarsModel *t,
725 int toolbar_position)
729 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
730 g_return_val_if_fail (toolbar != NULL, -1);
732 return g_node_n_children (toolbar);
736 egg_toolbars_model_item_nth (EggToolbarsModel *t,
737 int toolbar_position,
739 gboolean *is_separator,
745 EggToolbarsItem *idata;
747 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
748 g_return_if_fail (toolbar != NULL);
750 item = g_node_nth_child (toolbar, position);
751 g_return_if_fail (item != NULL);
755 *is_separator = idata->separator;
769 egg_toolbars_model_n_toolbars (EggToolbarsModel *t)
771 return g_node_n_children (t->priv->toolbars);
775 egg_toolbars_model_toolbar_nth (EggToolbarsModel *t,
779 EggToolbarsToolbar *tdata;
781 toolbar = g_node_nth_child (t->priv->toolbars, position);
782 g_return_val_if_fail (toolbar != NULL, NULL);
784 tdata = toolbar->data;
790 egg_toolbars_model_add_item (EggToolbarsModel *t,
791 int toolbar_position,
796 EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (t);
797 return klass->add_item (t, toolbar_position, position, id, type);
801 egg_toolbars_model_get_item_id (EggToolbarsModel *t,
807 g_signal_emit (t, signals[GET_ITEM_ID], 0, type, name, &retval);
813 egg_toolbars_model_get_item_data (EggToolbarsModel *t,
819 g_signal_emit (t, signals[GET_ITEM_DATA], 0, type, id, &retval);
825 egg_toolbars_model_get_item_type (EggToolbarsModel *t,
830 g_signal_emit (t, signals[GET_ITEM_TYPE], 0, type, &retval);