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 "eggmarshalers.h"
29 #include <libxml/tree.h>
30 #include <gdk/gdkproperty.h>
32 static void egg_toolbars_model_class_init (EggToolbarsModelClass *klass);
33 static void egg_toolbars_model_init (EggToolbarsModel *t);
34 static void egg_toolbars_model_finalize (GObject *object);
52 EggTbModelFlags flags;
62 static guint signals[LAST_SIGNAL] = { 0 };
64 static GObjectClass *parent_class = NULL;
66 #define EGG_TOOLBARS_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_TOOLBARS_MODEL, EggToolbarsModelPrivate))
68 struct EggToolbarsModelPrivate
74 egg_toolbars_model_get_type (void)
76 static GType type = 0;
78 if (G_UNLIKELY (type == 0))
80 static const GTypeInfo our_info = {
81 sizeof (EggToolbarsModelClass),
83 NULL, /* base_finalize */
84 (GClassInitFunc) egg_toolbars_model_class_init,
86 NULL, /* class_data */
87 sizeof (EggToolbarsModel),
89 (GInstanceInitFunc) egg_toolbars_model_init
92 type = g_type_register_static (G_TYPE_OBJECT,
101 egg_toolbars_model_to_xml (EggToolbarsModel *t)
106 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), NULL);
108 tl = t->priv->toolbars;
110 xmlIndentTreeOutput = TRUE;
111 doc = xmlNewDoc ((const xmlChar*) "1.0");
112 doc->children = xmlNewDocNode (doc, NULL, (const xmlChar*) "toolbars", NULL);
114 for (l1 = tl->children; l1 != NULL; l1 = l1->next)
117 EggToolbarsToolbar *toolbar = l1->data;
119 tnode = xmlNewChild (doc->children, NULL, (const xmlChar*) "toolbar", NULL);
120 xmlSetProp (tnode, (const xmlChar*) "name", (const xmlChar*) toolbar->name);
122 for (l2 = l1->children; l2 != NULL; l2 = l2->next)
125 EggToolbarsItem *item = l2->data;
129 node = xmlNewChild (tnode, NULL, (const xmlChar*) "separator", NULL);
135 node = xmlNewChild (tnode, NULL, (const xmlChar*) "toolitem", NULL);
136 data = egg_toolbars_model_get_item_data (t, item->type, item->id);
137 xmlSetProp (node, (const xmlChar*) "type", (const xmlChar*) item->type);
138 xmlSetProp (node, (const xmlChar*) "name", (const xmlChar*) data);
148 safe_save_xml (const char *xml_file, xmlDocPtr doc)
153 gboolean retval = TRUE;
155 tmp_file = g_strconcat (xml_file, ".tmp", NULL);
156 old_file = g_strconcat (xml_file, ".old", NULL);
158 if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
160 g_warning ("Failed to write XML data to %s", tmp_file);
164 old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
168 if (rename (xml_file, old_file) < 0)
170 g_warning ("Failed to rename %s to %s", xml_file, old_file);
176 if (rename (tmp_file, xml_file) < 0)
178 g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
180 if (rename (old_file, xml_file) < 0)
182 g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
190 if (unlink (old_file) < 0)
192 g_warning ("Failed to delete old file %s", old_file);
204 egg_toolbars_model_save (EggToolbarsModel *t,
205 const char *xml_file,
211 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
213 doc = egg_toolbars_model_to_xml (t);
214 root = xmlDocGetRootElement (doc);
215 xmlSetProp (root, (const xmlChar*) "version", (const xmlChar*) version);
216 safe_save_xml (xml_file, doc);
220 static EggToolbarsToolbar *
221 toolbars_toolbar_new (const char *name)
223 EggToolbarsToolbar *toolbar;
225 toolbar = g_new (EggToolbarsToolbar, 1);
226 toolbar->name = g_strdup (name);
232 static EggToolbarsItem *
233 toolbars_item_new (const char *id,
237 EggToolbarsItem *item;
239 g_return_val_if_fail (id != NULL, NULL);
240 g_return_val_if_fail (type != NULL, NULL);
242 item = g_new (EggToolbarsItem, 1);
243 item->id = g_strdup (id);
244 item->type = g_strdup (type);
245 item->separator = separator;
251 free_toolbar_node (GNode *toolbar_node)
253 EggToolbarsToolbar *toolbar = toolbar_node->data;
255 g_free (toolbar->name);
258 g_node_destroy (toolbar_node);
262 free_item_node (GNode *item_node)
264 EggToolbarsItem *item = item_node->data;
270 g_node_destroy (item_node);
274 egg_toolbars_model_get_flags (EggToolbarsModel *t,
275 int toolbar_position)
278 EggToolbarsToolbar *toolbar;
280 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
281 g_return_val_if_fail (toolbar_node != NULL, 0);
283 toolbar = toolbar_node->data;
285 return toolbar->flags;
289 egg_toolbars_model_set_flags (EggToolbarsModel *t,
290 int toolbar_position,
291 EggTbModelFlags flags)
294 EggToolbarsToolbar *toolbar;
296 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
297 g_return_if_fail (toolbar_node != NULL);
299 toolbar = toolbar_node->data;
301 toolbar->flags = flags;
303 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_CHANGED],
304 0, toolbar_position);
308 egg_toolbars_model_add_separator (EggToolbarsModel *t,
309 int toolbar_position,
314 EggToolbarsItem *item;
317 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
319 parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
320 item = toolbars_item_new ("separator", EGG_TOOLBAR_ITEM_TYPE, TRUE);
321 node = g_node_new (item);
322 g_node_insert (parent_node, position, node);
324 real_position = g_node_child_position (parent_node, node);
326 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
327 toolbar_position, real_position);
331 impl_add_item (EggToolbarsModel *t,
332 int toolbar_position,
339 EggToolbarsItem *item;
342 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
343 g_return_val_if_fail (id != NULL, FALSE);
344 g_return_val_if_fail (type != NULL, FALSE);
346 parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
347 item = toolbars_item_new (id, type, FALSE);
348 node = g_node_new (item);
349 g_node_insert (parent_node, position, node);
351 real_position = g_node_child_position (parent_node, node);
353 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
354 toolbar_position, real_position);
360 parse_item_list (EggToolbarsModel *t,
366 if (xmlStrEqual (child->name, (const xmlChar*) "toolitem"))
368 xmlChar *name, *type;
371 name = xmlGetProp (child, (const xmlChar*) "name");
372 type = xmlGetProp (child, (const xmlChar*) "type");
375 type = xmlCharStrdup (EGG_TOOLBAR_ITEM_TYPE);
378 if (name != NULL && name[0] != '\0' && type != NULL)
380 id = egg_toolbars_model_get_item_id (t, (const char*)type, (const char*)name);
383 egg_toolbars_model_add_item (t, position, -1, id, (const char*)type);
390 else if (xmlStrEqual (child->name, (const xmlChar*) "separator"))
392 egg_toolbars_model_add_separator (t, position, -1);
400 egg_toolbars_model_add_toolbar (EggToolbarsModel *t,
407 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), -1);
409 node = g_node_new (toolbars_toolbar_new (name));
410 g_node_insert (t->priv->toolbars, position, node);
412 real_position = g_node_child_position (t->priv->toolbars, node);
414 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_ADDED],
417 return g_node_child_position (t->priv->toolbars, node);
421 parse_toolbars (EggToolbarsModel *t,
426 if (xmlStrEqual (child->name, (const xmlChar*) "toolbar"))
432 name = xmlGetProp (child, (const xmlChar*) "name");
433 position = egg_toolbars_model_add_toolbar (t, -1, (const char*) name);
436 style = xmlGetProp (child, (const xmlChar*) "style");
437 if (style && xmlStrEqual (style, (const xmlChar*) "icons-only"))
439 /* FIXME: use toolbar position instead of 0 */
440 egg_toolbars_model_set_flags (t, 0, EGG_TB_MODEL_ICONS);
444 parse_item_list (t, child->children, position);
452 egg_toolbars_model_load (EggToolbarsModel *t,
453 const char *xml_file)
458 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
460 if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
462 doc = xmlParseFile (xml_file);
465 g_warning ("Failed to load XML data from %s", xml_file);
468 root = xmlDocGetRootElement (doc);
470 parse_toolbars (t, root->children);
478 impl_get_item_id (EggToolbarsModel *t,
482 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
484 return g_strdup (data);
491 impl_get_item_data (EggToolbarsModel *t,
495 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
497 return g_strdup (id);
504 impl_get_item_type (EggToolbarsModel *t,
507 if (gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE) == type)
509 return g_strdup (EGG_TOOLBAR_ITEM_TYPE);
516 _egg_accumulator_STRING (GSignalInvocationHint *ihint,
518 const GValue *handler_return,
521 gboolean continue_emission;
524 retval = g_value_get_string (handler_return);
525 g_value_set_string (return_accu, retval);
526 continue_emission = !retval || !retval[0];
528 return continue_emission;
533 egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
535 GObjectClass *object_class = G_OBJECT_CLASS (klass);
537 parent_class = g_type_class_peek_parent (klass);
539 object_class->finalize = egg_toolbars_model_finalize;
541 klass->add_item = impl_add_item;
542 klass->get_item_id = impl_get_item_id;
543 klass->get_item_data = impl_get_item_data;
544 klass->get_item_type = impl_get_item_type;
546 signals[ITEM_ADDED] =
547 g_signal_new ("item_added",
548 G_OBJECT_CLASS_TYPE (object_class),
550 G_STRUCT_OFFSET (EggToolbarsModelClass, item_added),
551 NULL, NULL, _egg_marshal_VOID__INT_INT,
552 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
553 signals[TOOLBAR_ADDED] =
554 g_signal_new ("toolbar_added",
555 G_OBJECT_CLASS_TYPE (object_class),
557 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_added),
558 NULL, NULL, g_cclosure_marshal_VOID__INT,
559 G_TYPE_NONE, 1, G_TYPE_INT);
560 signals[ITEM_REMOVED] =
561 g_signal_new ("item_removed",
562 G_OBJECT_CLASS_TYPE (object_class),
564 G_STRUCT_OFFSET (EggToolbarsModelClass, item_removed),
565 NULL, NULL, _egg_marshal_VOID__INT_INT,
566 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
567 signals[TOOLBAR_REMOVED] =
568 g_signal_new ("toolbar_removed",
569 G_OBJECT_CLASS_TYPE (object_class),
571 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_removed),
572 NULL, NULL, g_cclosure_marshal_VOID__INT,
573 G_TYPE_NONE, 1, G_TYPE_INT);
574 signals[TOOLBAR_CHANGED] =
575 g_signal_new ("toolbar_changed",
576 G_OBJECT_CLASS_TYPE (object_class),
578 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed),
579 NULL, NULL, g_cclosure_marshal_VOID__INT,
580 G_TYPE_NONE, 1, G_TYPE_INT);
581 signals[GET_ITEM_TYPE] =
582 g_signal_new ("get_item_type",
583 G_OBJECT_CLASS_TYPE (object_class),
584 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
585 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_type),
586 _egg_accumulator_STRING, NULL,
587 _egg_marshal_STRING__POINTER,
588 G_TYPE_STRING, 1, G_TYPE_POINTER);
589 signals[GET_ITEM_ID] =
590 g_signal_new ("get_item_id",
591 G_OBJECT_CLASS_TYPE (object_class),
592 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
593 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_id),
594 _egg_accumulator_STRING, NULL,
595 _egg_marshal_STRING__STRING_STRING,
596 G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
597 signals[GET_ITEM_DATA] =
598 g_signal_new ("get_item_data",
599 G_OBJECT_CLASS_TYPE (object_class),
600 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
601 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_data),
602 _egg_accumulator_STRING, NULL,
603 _egg_marshal_STRING__STRING_STRING,
604 G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
606 g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate));
610 egg_toolbars_model_init (EggToolbarsModel *t)
612 t->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (t);
614 t->priv->toolbars = g_node_new (NULL);
618 free_toolbar (GNode *toolbar_node)
620 g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
621 (GNodeForeachFunc) free_item_node, NULL);
622 free_toolbar_node (toolbar_node);
626 egg_toolbars_model_finalize (GObject *object)
628 EggToolbarsModel *t = EGG_TOOLBARS_MODEL (object);
630 g_node_children_foreach (t->priv->toolbars, G_TRAVERSE_ALL,
631 (GNodeForeachFunc) free_toolbar, NULL);
632 g_node_destroy (t->priv->toolbars);
634 G_OBJECT_CLASS (parent_class)->finalize (object);
638 egg_toolbars_model_new (void)
640 return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
644 egg_toolbars_model_remove_toolbar (EggToolbarsModel *t,
648 EggTbModelFlags flags;
650 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
652 flags = egg_toolbars_model_get_flags (t, position);
654 if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
656 node = g_node_nth_child (t->priv->toolbars, position);
657 g_return_if_fail (node != NULL);
659 free_toolbar_node (node);
661 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_REMOVED],
667 egg_toolbars_model_remove_item (EggToolbarsModel *t,
668 int toolbar_position,
671 GNode *node, *toolbar;
673 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
675 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
676 g_return_if_fail (toolbar != NULL);
678 node = g_node_nth_child (toolbar, position);
679 g_return_if_fail (node != NULL);
681 free_item_node (node);
683 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
684 toolbar_position, position);
688 egg_toolbars_model_move_item (EggToolbarsModel *t,
689 int toolbar_position,
691 int new_toolbar_position,
694 GNode *node, *toolbar, *new_toolbar;
696 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
698 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
699 g_return_if_fail (toolbar != NULL);
701 new_toolbar = g_node_nth_child (t->priv->toolbars, new_toolbar_position);
702 g_return_if_fail (new_toolbar != NULL);
704 node = g_node_nth_child (toolbar, position);
705 g_return_if_fail (node != NULL);
707 g_node_unlink (node);
709 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
710 toolbar_position, position);
712 g_node_insert (new_toolbar, new_position, node);
714 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
715 new_toolbar_position, new_position);
719 egg_toolbars_model_n_items (EggToolbarsModel *t,
720 int toolbar_position)
724 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
725 g_return_val_if_fail (toolbar != NULL, -1);
727 return g_node_n_children (toolbar);
731 egg_toolbars_model_item_nth (EggToolbarsModel *t,
732 int toolbar_position,
734 gboolean *is_separator,
740 EggToolbarsItem *idata;
742 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
743 g_return_if_fail (toolbar != NULL);
745 item = g_node_nth_child (toolbar, position);
746 g_return_if_fail (item != NULL);
750 *is_separator = idata->separator;
764 egg_toolbars_model_n_toolbars (EggToolbarsModel *t)
766 return g_node_n_children (t->priv->toolbars);
770 egg_toolbars_model_toolbar_nth (EggToolbarsModel *t,
774 EggToolbarsToolbar *tdata;
776 toolbar = g_node_nth_child (t->priv->toolbars, position);
777 g_return_val_if_fail (toolbar != NULL, NULL);
779 tdata = toolbar->data;
785 egg_toolbars_model_add_item (EggToolbarsModel *t,
786 int toolbar_position,
791 EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (t);
792 return klass->add_item (t, toolbar_position, position, id, type);
796 egg_toolbars_model_get_item_id (EggToolbarsModel *t,
802 g_signal_emit (t, signals[GET_ITEM_ID], 0, type, name, &retval);
808 egg_toolbars_model_get_item_data (EggToolbarsModel *t,
814 g_signal_emit (t, signals[GET_ITEM_DATA], 0, type, id, &retval);
820 egg_toolbars_model_get_item_type (EggToolbarsModel *t,
825 g_signal_emit (t, signals[GET_ITEM_TYPE], 0, type, &retval);