Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / xml / composite-node-observer.cpp
1 /*
2  * Inkscape::XML::CompositeNodeObserver - combine multiple observers
3  *
4  * Copyright 2005 MenTaLguY <mental@rydia.net>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * See the file COPYING for details.
12  *
13  */
15 #include <cstring>
16 #include <glib.h>
18 #include "util/find-if-before.h"
19 #include "xml/composite-node-observer.h"
20 #include "xml/node-event-vector.h"
21 #include "debug/event-tracker.h"
22 #include "debug/simple-event.h"
24 namespace Inkscape {
26 namespace XML {
28 void CompositeNodeObserver::notifyChildAdded(Node &node, Node &child, Node *prev)
29 {
30     _startIteration();
31     for ( ObserverRecordList::iterator iter=_active.begin() ;
32           iter != _active.end() ; ++iter )
33     {
34         if (!iter->marked) {
35             iter->observer.notifyChildAdded(node, child, prev);
36         }
37     }
38     _finishIteration();
39 }
41 void CompositeNodeObserver::notifyChildRemoved(Node &node, Node &child,
42                                                            Node *prev)
43 {
44     _startIteration();
45     for ( ObserverRecordList::iterator iter=_active.begin() ;
46           iter != _active.end() ; ++iter )
47     {
48         if (!iter->marked) {
49             iter->observer.notifyChildRemoved(node, child, prev);
50         }
51     }
52     _finishIteration();
53 }
55 void CompositeNodeObserver::notifyChildOrderChanged(Node &node, Node &child,
56                                                                 Node *old_prev,
57                                                                 Node *new_prev)
58 {
59     _startIteration();
60     for ( ObserverRecordList::iterator iter=_active.begin() ;
61           iter != _active.end() ; ++iter )
62     {
63         if (!iter->marked) {
64             iter->observer.notifyChildOrderChanged(node, child, old_prev, new_prev);
65         }
66     }
67     _finishIteration();
68 }
70 void CompositeNodeObserver::notifyContentChanged(
71     Node &node,
72     Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content
73 ) {
74     _startIteration();
75     for ( ObserverRecordList::iterator iter=_active.begin() ;
76           iter != _active.end() ; ++iter )
77     {
78         if (!iter->marked) {
79             iter->observer.notifyContentChanged(node, old_content, new_content);
80         }
81     }
82     _finishIteration();
83 }
85 void CompositeNodeObserver::notifyAttributeChanged(
86     Node &node, GQuark name,
87     Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value
88 ) {
89     _startIteration();
90     for ( ObserverRecordList::iterator iter=_active.begin() ;
91           iter != _active.end() ; ++iter )
92     {
93         if (!iter->marked) {
94             iter->observer.notifyAttributeChanged(node, name, old_value, new_value);
95         }
96     }
97     _finishIteration();
98 }
100 void CompositeNodeObserver::add(NodeObserver &observer) {
101     if (_iterating) {
102         _pending.push_back(ObserverRecord(observer));
103     } else {
104         _active.push_back(ObserverRecord(observer));
105     }
108 namespace {
110 class VectorNodeObserver : public NodeObserver, public GC::Managed<> {
111 public:
112     VectorNodeObserver(NodeEventVector const &v, void *d)
113     : vector(v), data(d) {}
115     NodeEventVector const &vector;
116     void * const data;
118     void notifyChildAdded(Node &node, Node &child, Node *prev) {
119         if (vector.child_added) {
120             vector.child_added(&node, &child, prev, data);
121         }
122     }
124     void notifyChildRemoved(Node &node, Node &child, Node *prev) {
125         if (vector.child_removed) {
126             vector.child_removed(&node, &child, prev, data);
127         }
128     }
130     void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev) {
131         if (vector.order_changed) {
132             vector.order_changed(&node, &child, old_prev, new_prev, data);
133         }
134     }
136     void notifyContentChanged(Node &node, Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content) {
137         if (vector.content_changed) {
138             vector.content_changed(&node, old_content, new_content, data);
139         }
140     }
142     void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value) {
143         if (vector.attr_changed) {
144             vector.attr_changed(&node, g_quark_to_string(name), old_value, new_value, false, data);
145         }
146     }
147 };
151 void CompositeNodeObserver::addListener(NodeEventVector const &vector,
152                                         void *data)
154     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("add-listener");
155     add(*(new VectorNodeObserver(vector, data)));
158 namespace {
160 using std::find_if;
161 using Algorithms::find_if_before;
162 typedef CompositeNodeObserver::ObserverRecord ObserverRecord;
163 typedef CompositeNodeObserver::ObserverRecordList ObserverRecordList;
165 template <typename ObserverPredicate>
166 struct unmarked_record_satisfying {
167     ObserverPredicate predicate;
168     unmarked_record_satisfying(ObserverPredicate p) : predicate(p) {}
169     bool operator()(ObserverRecord const &record) {
170         return !record.marked && predicate(record.observer);
171     }
172 };
174 template <typename Predicate>
175 bool mark_one(ObserverRecordList &observers, unsigned &/*marked_count*/,
176               Predicate p)
178     ObserverRecordList::iterator found=std::find_if(
179         observers.begin(), observers.end(),
180         unmarked_record_satisfying<Predicate>(p)
181     );
183     if ( found != observers.end() ) {
184         found->marked = true;
185         return true;
186     } else {
187         return false;
188     }
191 template <typename Predicate>
192 bool remove_one(ObserverRecordList &observers, unsigned &/*marked_count*/,
193                 Predicate p)
195     if (observers.empty()) {
196         return false;
197     }
199     if (unmarked_record_satisfying<Predicate>(p)(observers.front())) {
200         observers.pop_front();
201         return true;
202     }
204     ObserverRecordList::iterator found=find_if_before(
205         observers.begin(), observers.end(),
206         unmarked_record_satisfying<Predicate>(p)
207     );
209     if ( found != observers.end() ) {
210         observers.erase_after(found);
211         return true;
212     } else {
213         return false;
214     }
217 bool is_marked(ObserverRecord const &record) { return record.marked; }
219 void remove_all_marked(ObserverRecordList &observers, unsigned &marked_count)
221     ObserverRecordList::iterator iter;
223     g_assert( !observers.empty() || !marked_count );
225     while ( marked_count && observers.front().marked ) {
226         observers.pop_front();
227         --marked_count;
228     }
230     iter = observers.begin();
231     while (marked_count) {
232         iter = find_if_before(iter, observers.end(), is_marked);
233         observers.erase_after(iter);
234         --marked_count;
235     }
240 void CompositeNodeObserver::_finishIteration() {
241     if (!--_iterating) {
242         remove_all_marked(_active, _active_marked);
243         remove_all_marked(_pending, _pending_marked);
244         _active.insert(_active.end(), _pending.begin(), _pending.end());
245         _pending.clear();
246     }
249 namespace {
251 struct eql_observer {
252     NodeObserver const &observer;
253     eql_observer(NodeObserver const &o) : observer(o) {}
254     bool operator()(NodeObserver const &other) {
255         return &observer == &other;
256     }
257 };
261 void CompositeNodeObserver::remove(NodeObserver &observer) {
262     eql_observer p(observer);
263     if (_iterating) {
264         mark_one(_active, _active_marked, p) ||
265         mark_one(_pending, _pending_marked, p);
266     } else {
267         remove_one(_active, _active_marked, p) ||
268         remove_one(_pending, _pending_marked, p);
269     }
272 namespace {
274 struct vector_data_matches {
275     void * const data;
276     vector_data_matches(void *d) : data(d) {}
277     
278     bool operator()(NodeObserver const &observer) {
279         VectorNodeObserver const *vo=dynamic_cast<VectorNodeObserver const *>(&observer);
280         return vo && vo->data == data;
281     }
282 };
286 void CompositeNodeObserver::removeListenerByData(void *data) {
287     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("remove-listener-by-data");
288     vector_data_matches p(data);
289     if (_iterating) {
290         mark_one(_active, _active_marked, p) ||
291         mark_one(_pending, _pending_marked, p);
292     } else {
293         remove_one(_active, _active_marked, p) ||
294         remove_one(_pending, _pending_marked, p);
295     }
297     
302 /*
303   Local Variables:
304   mode:c++
305   c-file-style:"stroustrup"
306   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
307   indent-tabs-mode:nil
308   fill-column:99
309   End:
310 */
311 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :