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.
26 #include "egg-toolbars-model.h"
27 #include "eggmarshalers.h"
31 #include <libxml/tree.h>
32 #include <gdk/gdkproperty.h>
34 static void egg_toolbars_model_class_init (EggToolbarsModelClass *klass);
35 static void egg_toolbars_model_init (EggToolbarsModel *t);
36 static void egg_toolbars_model_finalize (GObject *object);
54 EggTbModelFlags flags;
64 static guint signals[LAST_SIGNAL] = { 0 };
66 static GObjectClass *parent_class = NULL;
68 #define EGG_TOOLBARS_MODEL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EGG_TYPE_TOOLBARS_MODEL, EggToolbarsModelPrivate))
70 struct EggToolbarsModelPrivate
76 egg_toolbars_model_get_type (void)
78 static GType type = 0;
82 static const GTypeInfo our_info = {
83 sizeof (EggToolbarsModelClass),
85 NULL, /* base_finalize */
86 (GClassInitFunc) egg_toolbars_model_class_init,
88 NULL, /* class_data */
89 sizeof (EggToolbarsModel),
91 (GInstanceInitFunc) egg_toolbars_model_init
94 type = g_type_register_static (G_TYPE_OBJECT,
103 egg_toolbars_model_to_xml (EggToolbarsModel *t)
108 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), NULL);
110 tl = t->priv->toolbars;
112 xmlIndentTreeOutput = TRUE;
113 doc = xmlNewDoc ("1.0");
114 doc->children = xmlNewDocNode (doc, NULL, "toolbars", NULL);
116 for (l1 = tl->children; l1 != NULL; l1 = l1->next)
119 EggToolbarsToolbar *toolbar = l1->data;
121 tnode = xmlNewChild (doc->children, NULL, "toolbar", NULL);
122 xmlSetProp (tnode, "name", toolbar->name);
124 for (l2 = l1->children; l2 != NULL; l2 = l2->next)
127 EggToolbarsItem *item = l2->data;
131 node = xmlNewChild (tnode, NULL, "separator", NULL);
137 node = xmlNewChild (tnode, NULL, "toolitem", NULL);
138 data = egg_toolbars_model_get_item_data (t, item->type, item->id);
139 xmlSetProp (node, "type", item->type);
140 xmlSetProp (node, "name", data);
150 safe_save_xml (const char *xml_file, xmlDocPtr doc)
155 gboolean retval = TRUE;
157 tmp_file = g_strconcat (xml_file, ".tmp", NULL);
158 old_file = g_strconcat (xml_file, ".old", NULL);
160 if (xmlSaveFormatFile (tmp_file, doc, 1) <= 0)
162 g_warning ("Failed to write XML data to %s", tmp_file);
166 old_exist = g_file_test (xml_file, G_FILE_TEST_EXISTS);
170 if (rename (xml_file, old_file) < 0)
172 g_warning ("Failed to rename %s to %s", xml_file, old_file);
178 if (rename (tmp_file, xml_file) < 0)
180 g_warning ("Failed to rename %s to %s", tmp_file, xml_file);
182 if (rename (old_file, xml_file) < 0)
184 g_warning ("Failed to restore %s from %s", xml_file, tmp_file);
192 if (unlink (old_file) < 0)
194 g_warning ("Failed to delete old file %s", old_file);
206 egg_toolbars_model_save (EggToolbarsModel *t,
207 const char *xml_file,
213 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
215 doc = egg_toolbars_model_to_xml (t);
216 root = xmlDocGetRootElement (doc);
217 xmlSetProp (root, "version", version);
218 safe_save_xml (xml_file, doc);
222 static EggToolbarsToolbar *
223 toolbars_toolbar_new (const char *name)
225 EggToolbarsToolbar *toolbar;
227 toolbar = g_new (EggToolbarsToolbar, 1);
228 toolbar->name = g_strdup (name);
234 static EggToolbarsItem *
235 toolbars_item_new (const char *id,
239 EggToolbarsItem *item;
241 g_return_val_if_fail (id != NULL, NULL);
242 g_return_val_if_fail (type != NULL, NULL);
244 item = g_new (EggToolbarsItem, 1);
245 item->id = g_strdup (id);
246 item->type = g_strdup (type);
247 item->separator = separator;
253 free_toolbar_node (GNode *toolbar_node)
255 EggToolbarsToolbar *toolbar = toolbar_node->data;
257 g_free (toolbar->name);
260 g_node_destroy (toolbar_node);
264 free_item_node (GNode *item_node)
266 EggToolbarsItem *item = item_node->data;
272 g_node_destroy (item_node);
276 egg_toolbars_model_get_flags (EggToolbarsModel *t,
277 int toolbar_position)
280 EggToolbarsToolbar *toolbar;
282 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
283 g_return_val_if_fail (toolbar_node != NULL, 0);
285 toolbar = toolbar_node->data;
287 return toolbar->flags;
291 egg_toolbars_model_set_flags (EggToolbarsModel *t,
292 int toolbar_position,
293 EggTbModelFlags flags)
296 EggToolbarsToolbar *toolbar;
298 toolbar_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
299 g_return_if_fail (toolbar_node != NULL);
301 toolbar = toolbar_node->data;
303 toolbar->flags = flags;
305 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_CHANGED],
306 0, toolbar_position);
310 egg_toolbars_model_add_separator (EggToolbarsModel *t,
311 int toolbar_position,
316 EggToolbarsItem *item;
319 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
321 parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
322 item = toolbars_item_new ("separator", EGG_TOOLBAR_ITEM_TYPE, TRUE);
323 node = g_node_new (item);
324 g_node_insert (parent_node, position, node);
326 real_position = g_node_child_position (parent_node, node);
328 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
329 toolbar_position, real_position);
333 impl_add_item (EggToolbarsModel *t,
334 int toolbar_position,
341 EggToolbarsItem *item;
344 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
345 g_return_val_if_fail (id != NULL, FALSE);
346 g_return_val_if_fail (type != NULL, FALSE);
348 parent_node = g_node_nth_child (t->priv->toolbars, toolbar_position);
349 item = toolbars_item_new (id, type, FALSE);
350 node = g_node_new (item);
351 g_node_insert (parent_node, position, node);
353 real_position = g_node_child_position (parent_node, node);
355 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
356 toolbar_position, real_position);
362 parse_item_list (EggToolbarsModel *t,
368 if (xmlStrEqual (child->name, "toolitem"))
370 xmlChar *name, *type;
373 name = xmlGetProp (child, "name");
374 type = xmlGetProp (child, "type");
377 type = xmlStrdup (EGG_TOOLBAR_ITEM_TYPE);
380 if (name != NULL && name[0] != '\0' && type != NULL)
382 id = egg_toolbars_model_get_item_id (t, type, name);
385 egg_toolbars_model_add_item (t, position, -1, id, type);
392 else if (xmlStrEqual (child->name, "separator"))
394 egg_toolbars_model_add_separator (t, position, -1);
402 egg_toolbars_model_add_toolbar (EggToolbarsModel *t,
409 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), -1);
411 node = g_node_new (toolbars_toolbar_new (name));
412 g_node_insert (t->priv->toolbars, position, node);
414 real_position = g_node_child_position (t->priv->toolbars, node);
416 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_ADDED],
419 return g_node_child_position (t->priv->toolbars, node);
423 parse_toolbars (EggToolbarsModel *t,
428 if (xmlStrEqual (child->name, "toolbar"))
434 name = xmlGetProp (child, "name");
435 position = egg_toolbars_model_add_toolbar (t, -1, name);
438 style = xmlGetProp (child, "style");
439 if (style && xmlStrEqual (style, "icons-only"))
441 /* FIXME: use toolbar position instead of 0 */
442 egg_toolbars_model_set_flags (t, 0, EGG_TB_MODEL_ICONS_ONLY);
446 parse_item_list (t, child->children, position);
454 egg_toolbars_model_load (EggToolbarsModel *t,
455 const char *xml_file)
460 g_return_val_if_fail (EGG_IS_TOOLBARS_MODEL (t), FALSE);
462 if (!xml_file || !g_file_test (xml_file, G_FILE_TEST_EXISTS)) return FALSE;
464 doc = xmlParseFile (xml_file);
467 g_warning ("Failed to load XML data from %s", xml_file);
470 root = xmlDocGetRootElement (doc);
472 parse_toolbars (t, root->children);
480 impl_get_item_id (EggToolbarsModel *t,
484 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
486 return g_strdup (data);
493 impl_get_item_data (EggToolbarsModel *t,
497 if (strcmp (type, EGG_TOOLBAR_ITEM_TYPE) == 0)
499 return g_strdup (id);
506 impl_get_item_type (EggToolbarsModel *t,
509 if (gdk_atom_intern (EGG_TOOLBAR_ITEM_TYPE, FALSE) == type)
511 return g_strdup (EGG_TOOLBAR_ITEM_TYPE);
518 _egg_accumulator_STRING (GSignalInvocationHint *ihint,
520 const GValue *handler_return,
523 gboolean continue_emission;
526 retval = g_value_get_string (handler_return);
527 g_value_set_string (return_accu, retval);
528 continue_emission = !retval || !retval[0];
530 return continue_emission;
535 egg_toolbars_model_class_init (EggToolbarsModelClass *klass)
537 GObjectClass *object_class = G_OBJECT_CLASS (klass);
539 parent_class = g_type_class_peek_parent (klass);
541 object_class->finalize = egg_toolbars_model_finalize;
543 klass->add_item = impl_add_item;
544 klass->get_item_id = impl_get_item_id;
545 klass->get_item_data = impl_get_item_data;
546 klass->get_item_type = impl_get_item_type;
548 signals[ITEM_ADDED] =
549 g_signal_new ("item_added",
550 G_OBJECT_CLASS_TYPE (object_class),
552 G_STRUCT_OFFSET (EggToolbarsModelClass, item_added),
553 NULL, NULL, _egg_marshal_VOID__INT_INT,
554 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
555 signals[TOOLBAR_ADDED] =
556 g_signal_new ("toolbar_added",
557 G_OBJECT_CLASS_TYPE (object_class),
559 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_added),
560 NULL, NULL, g_cclosure_marshal_VOID__INT,
561 G_TYPE_NONE, 1, G_TYPE_INT);
562 signals[ITEM_REMOVED] =
563 g_signal_new ("item_removed",
564 G_OBJECT_CLASS_TYPE (object_class),
566 G_STRUCT_OFFSET (EggToolbarsModelClass, item_removed),
567 NULL, NULL, _egg_marshal_VOID__INT_INT,
568 G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
569 signals[TOOLBAR_REMOVED] =
570 g_signal_new ("toolbar_removed",
571 G_OBJECT_CLASS_TYPE (object_class),
573 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_removed),
574 NULL, NULL, g_cclosure_marshal_VOID__INT,
575 G_TYPE_NONE, 1, G_TYPE_INT);
576 signals[TOOLBAR_CHANGED] =
577 g_signal_new ("toolbar_changed",
578 G_OBJECT_CLASS_TYPE (object_class),
580 G_STRUCT_OFFSET (EggToolbarsModelClass, toolbar_changed),
581 NULL, NULL, g_cclosure_marshal_VOID__INT,
582 G_TYPE_NONE, 1, G_TYPE_INT);
583 signals[GET_ITEM_TYPE] =
584 g_signal_new ("get_item_type",
585 G_OBJECT_CLASS_TYPE (object_class),
586 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
587 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_type),
588 _egg_accumulator_STRING, NULL,
589 _egg_marshal_STRING__POINTER,
590 G_TYPE_STRING, 1, G_TYPE_POINTER);
591 signals[GET_ITEM_ID] =
592 g_signal_new ("get_item_id",
593 G_OBJECT_CLASS_TYPE (object_class),
594 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
595 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_id),
596 _egg_accumulator_STRING, NULL,
597 _egg_marshal_STRING__STRING_STRING,
598 G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
599 signals[GET_ITEM_DATA] =
600 g_signal_new ("get_item_data",
601 G_OBJECT_CLASS_TYPE (object_class),
602 G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST,
603 G_STRUCT_OFFSET (EggToolbarsModelClass, get_item_data),
604 _egg_accumulator_STRING, NULL,
605 _egg_marshal_STRING__STRING_STRING,
606 G_TYPE_STRING, 2, G_TYPE_STRING, G_TYPE_STRING);
608 g_type_class_add_private (object_class, sizeof (EggToolbarsModelPrivate));
612 egg_toolbars_model_init (EggToolbarsModel *t)
614 t->priv =EGG_TOOLBARS_MODEL_GET_PRIVATE (t);
616 t->priv->toolbars = g_node_new (NULL);
620 free_toolbar (GNode *toolbar_node)
622 g_node_children_foreach (toolbar_node, G_TRAVERSE_ALL,
623 (GNodeForeachFunc) free_item_node, NULL);
624 free_toolbar_node (toolbar_node);
628 egg_toolbars_model_finalize (GObject *object)
630 EggToolbarsModel *t = EGG_TOOLBARS_MODEL (object);
632 g_node_children_foreach (t->priv->toolbars, G_TRAVERSE_ALL,
633 (GNodeForeachFunc) free_toolbar, NULL);
634 g_node_destroy (t->priv->toolbars);
636 G_OBJECT_CLASS (parent_class)->finalize (object);
640 egg_toolbars_model_new (void)
642 return EGG_TOOLBARS_MODEL (g_object_new (EGG_TYPE_TOOLBARS_MODEL, NULL));
646 egg_toolbars_model_remove_toolbar (EggToolbarsModel *t,
650 EggTbModelFlags flags;
652 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
654 flags = egg_toolbars_model_get_flags (t, position);
656 if (!(flags & EGG_TB_MODEL_NOT_REMOVABLE))
658 node = g_node_nth_child (t->priv->toolbars, position);
659 g_return_if_fail (node != NULL);
661 free_toolbar_node (node);
663 g_signal_emit (G_OBJECT (t), signals[TOOLBAR_REMOVED],
669 egg_toolbars_model_remove_item (EggToolbarsModel *t,
670 int toolbar_position,
673 GNode *node, *toolbar;
675 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
677 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
678 g_return_if_fail (toolbar != NULL);
680 node = g_node_nth_child (toolbar, position);
681 g_return_if_fail (node != NULL);
683 free_item_node (node);
685 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
686 toolbar_position, position);
690 egg_toolbars_model_move_item (EggToolbarsModel *t,
691 int toolbar_position,
693 int new_toolbar_position,
696 GNode *node, *toolbar, *new_toolbar;
698 g_return_if_fail (EGG_IS_TOOLBARS_MODEL (t));
700 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
701 g_return_if_fail (toolbar != NULL);
703 new_toolbar = g_node_nth_child (t->priv->toolbars, new_toolbar_position);
704 g_return_if_fail (new_toolbar != NULL);
706 node = g_node_nth_child (toolbar, position);
707 g_return_if_fail (node != NULL);
709 g_node_unlink (node);
711 g_signal_emit (G_OBJECT (t), signals[ITEM_REMOVED], 0,
712 toolbar_position, position);
714 g_node_insert (new_toolbar, new_position, node);
716 g_signal_emit (G_OBJECT (t), signals[ITEM_ADDED], 0,
717 new_toolbar_position, new_position);
721 egg_toolbars_model_n_items (EggToolbarsModel *t,
722 int toolbar_position)
726 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
727 g_return_val_if_fail (toolbar != NULL, -1);
729 return g_node_n_children (toolbar);
733 egg_toolbars_model_item_nth (EggToolbarsModel *t,
734 int toolbar_position,
736 gboolean *is_separator,
742 EggToolbarsItem *idata;
744 toolbar = g_node_nth_child (t->priv->toolbars, toolbar_position);
745 g_return_if_fail (toolbar != NULL);
747 item = g_node_nth_child (toolbar, position);
748 g_return_if_fail (item != NULL);
752 *is_separator = idata->separator;
766 egg_toolbars_model_n_toolbars (EggToolbarsModel *t)
768 return g_node_n_children (t->priv->toolbars);
772 egg_toolbars_model_toolbar_nth (EggToolbarsModel *t,
776 EggToolbarsToolbar *tdata;
778 toolbar = g_node_nth_child (t->priv->toolbars, position);
779 g_return_val_if_fail (toolbar != NULL, NULL);
781 tdata = toolbar->data;
787 egg_toolbars_model_add_item (EggToolbarsModel *t,
788 int toolbar_position,
793 EggToolbarsModelClass *klass = EGG_TOOLBARS_MODEL_GET_CLASS (t);
794 return klass->add_item (t, toolbar_position, position, id, type);
798 egg_toolbars_model_get_item_id (EggToolbarsModel *t,
804 g_signal_emit (t, signals[GET_ITEM_ID], 0, type, name, &retval);
810 egg_toolbars_model_get_item_data (EggToolbarsModel *t,
816 g_signal_emit (t, signals[GET_ITEM_DATA], 0, type, id, &retval);
822 egg_toolbars_model_get_item_type (EggToolbarsModel *t,
827 g_signal_emit (t, signals[GET_ITEM_TYPE], 0, type, &retval);