1 #define __SP_SWITCH_CPP__
3 /*
4 * SVG <switch> implementation
5 *
6 * Authors:
7 * Andrius R. <knutux@gmail.com>
8 *
9 * Copyright (C) 2006 authors
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #include <glibmm/i18n.h>
20 #include "sp-switch.h"
21 #include "display/nr-arena-group.h"
22 #include "conditions.h"
24 static void sp_switch_class_init (SPSwitchClass *klass);
25 static void sp_switch_init (SPSwitch *group);
27 static SPGroupClass * parent_class;
29 GType CSwitch::getType (void)
30 {
31 static GType switch_type = 0;
32 if (!switch_type) {
33 GTypeInfo switch_info = {
34 sizeof (SPSwitchClass),
35 NULL, /* base_init */
36 NULL, /* base_finalize */
37 (GClassInitFunc) sp_switch_class_init,
38 NULL, /* class_finalize */
39 NULL, /* class_data */
40 sizeof (SPSwitch),
41 16, /* n_preallocs */
42 (GInstanceInitFunc) sp_switch_init,
43 NULL, /* value_table */
44 };
45 switch_type = g_type_register_static (SP_TYPE_GROUP, "SPSwitch", &switch_info, (GTypeFlags)0);
46 }
47 return switch_type;
48 }
50 static void
51 sp_switch_class_init (SPSwitchClass *) {
52 parent_class = (SPGroupClass *)g_type_class_ref (SP_TYPE_GROUP);
53 }
55 static void sp_switch_init (SPSwitch *group)
56 {
57 if (group->group)
58 delete group->group;
60 group->group = new CSwitch(group);
61 }
63 CSwitch::CSwitch(SPGroup *group) : CGroup(group), _cached_item(NULL), _release_handler_id(0) {
64 }
66 CSwitch::~CSwitch() {
67 _releaseLastItem(_cached_item);
68 }
70 SPObject *CSwitch::_evaluateFirst() {
71 for (SPObject *child = sp_object_first_child(_group) ; child != NULL ; child = SP_OBJECT_NEXT(child) ) {
72 if (SP_IS_ITEM(child) && sp_item_evaluate(SP_ITEM(child)))
73 return child;
74 }
75 return NULL;
76 }
78 GSList *CSwitch::_childList(bool add_ref, SPObject::Action action) {
79 if ( action != SPObject::ActionGeneral ) {
80 return _group->childList(add_ref, action);
81 }
83 SPObject *child = _evaluateFirst();
84 if (NULL == child)
85 return NULL;
87 if (add_ref)
88 g_object_ref (G_OBJECT (child));
90 return g_slist_prepend (NULL, child);
91 }
93 gchar *CSwitch::getDescription() {
94 gint len = getItemCount();
95 return g_strdup_printf(
96 ngettext("<b>Conditional group</b> of <b>%d</b> object",
97 "<b>Conditional group</b> of <b>%d</b> objects",
98 len), len);
99 }
101 void CSwitch::onChildAdded(Inkscape::XML::Node *) {
102 _reevaluate(true);
103 }
105 void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
106 _reevaluate();
107 }
109 void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
110 {
111 _reevaluate();
112 }
114 void CSwitch::_reevaluate(bool add_to_arena) {
115 SPObject *evaluated_child = _evaluateFirst();
116 if (!evaluated_child || _cached_item == evaluated_child) {
117 return;
118 }
120 _releaseLastItem(_cached_item);
122 SPItem * child;
123 for ( GSList *l = _childList(false, SPObject::ActionShow);
124 NULL != l ; l = g_slist_remove (l, l->data))
125 {
126 SPObject *o = SP_OBJECT (l->data);
127 if ( !SP_IS_ITEM (o) ) {
128 continue;
129 }
131 child = SP_ITEM (o);
132 child->setEvaluated(o == evaluated_child);
133 }
135 _cached_item = evaluated_child;
136 _release_handler_id = g_signal_connect(
137 G_OBJECT(evaluated_child), "release",
138 G_CALLBACK(&CSwitch::_releaseItem),
139 this);
141 _group->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
142 }
144 void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
145 {
146 selection->_releaseLastItem(obj);
147 }
149 void CSwitch::_releaseLastItem(SPObject *obj)
150 {
151 if (NULL == _cached_item || _cached_item != obj)
152 return;
154 g_signal_handler_disconnect(G_OBJECT(_cached_item), _release_handler_id);
155 _release_handler_id = 0;
156 _cached_item = NULL;
157 }
159 void CSwitch::_showChildren (NRArena *arena, NRArenaItem *ai, unsigned int key, unsigned int flags) {
160 SPObject *evaluated_child = _evaluateFirst();
162 NRArenaItem *ac = NULL;
163 NRArenaItem *ar = NULL;
164 SPItem * child;
165 GSList *l = _childList(false, SPObject::ActionShow);
166 while (l) {
167 SPObject *o = SP_OBJECT (l->data);
168 if (SP_IS_ITEM (o)) {
169 child = SP_ITEM (o);
170 child->setEvaluated(o == evaluated_child);
171 ac = sp_item_invoke_show (child, arena, key, flags);
172 if (ac) {
173 nr_arena_item_add_child (ai, ac, ar);
174 ar = ac;
175 nr_arena_item_unref (ac);
176 }
177 }
178 l = g_slist_remove (l, o);
179 }
180 }