Code

switch to sigc++ signal for "release"
[inkscape.git] / src / sp-switch.cpp
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);
105 void CSwitch::onChildRemoved(Inkscape::XML::Node *) {
106     _reevaluate();
109 void CSwitch::onOrderChanged (Inkscape::XML::Node *, Inkscape::XML::Node *, Inkscape::XML::Node *)
111     _reevaluate();
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);
144 void CSwitch::_releaseItem(SPObject *obj, CSwitch *selection)
146     selection->_releaseLastItem(obj);
149 void CSwitch::_releaseLastItem(SPObject *obj)
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;
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     }