Code

979462cef0b81c06a88e43b91d9aafc430a8f78e
[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>
17 #include "algorithms/find-if-before.h"
18 #include "xml/composite-node-observer.h"
19 #include "xml/node-event-vector.h"
20 #include "debug/event-tracker.h"
21 #include "debug/simple-event.h"
23 namespace Inkscape {
25 namespace XML {
27 void CompositeNodeObserver::notifyChildAdded(Node &node, Node &child, Node *prev)
28 {
29     _startIteration();
30     for ( ObserverRecordList::iterator iter=_active.begin() ;
31           iter != _active.end() ; ++iter )
32     {
33         if (!iter->marked) {
34             iter->observer.notifyChildAdded(node, child, prev);
35         }
36     }
37     _finishIteration();
38 }
40 void CompositeNodeObserver::notifyChildRemoved(Node &node, Node &child,
41                                                            Node *prev)
42 {
43     _startIteration();
44     for ( ObserverRecordList::iterator iter=_active.begin() ;
45           iter != _active.end() ; ++iter )
46     {
47         if (!iter->marked) {
48             iter->observer.notifyChildRemoved(node, child, prev);
49         }
50     }
51     _finishIteration();
52 }
54 void CompositeNodeObserver::notifyChildOrderChanged(Node &node, Node &child,
55                                                                 Node *old_prev,
56                                                                 Node *new_prev)
57 {
58     _startIteration();
59     for ( ObserverRecordList::iterator iter=_active.begin() ;
60           iter != _active.end() ; ++iter )
61     {
62         if (!iter->marked) {
63             iter->observer.notifyChildOrderChanged(node, child, old_prev, new_prev);
64         }
65     }
66     _finishIteration();
67 }
69 void CompositeNodeObserver::notifyContentChanged(
70     Node &node,
71     Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content
72 ) {
73     _startIteration();
74     for ( ObserverRecordList::iterator iter=_active.begin() ;
75           iter != _active.end() ; ++iter )
76     {
77         if (!iter->marked) {
78             iter->observer.notifyContentChanged(node, old_content, new_content);
79         }
80     }
81     _finishIteration();
82 }
84 void CompositeNodeObserver::notifyAttributeChanged(
85     Node &node, GQuark name,
86     Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value
87 ) {
88     _startIteration();
89     for ( ObserverRecordList::iterator iter=_active.begin() ;
90           iter != _active.end() ; ++iter )
91     {
92         if (!iter->marked) {
93             iter->observer.notifyAttributeChanged(node, name, old_value, new_value);
94         }
95     }
96     _finishIteration();
97 }
99 void CompositeNodeObserver::add(NodeObserver &observer) {
100     if (_iterating) {
101         _pending.push_back(ObserverRecord(observer));
102     } else {
103         _active.push_back(ObserverRecord(observer));
104     }
107 namespace {
109 class VectorNodeObserver : public NodeObserver, public GC::Managed<> {
110 public:
111     VectorNodeObserver(NodeEventVector const &v, void *d)
112     : vector(v), data(d) {}
114     NodeEventVector const &vector;
115     void * const data;
117     void notifyChildAdded(Node &node, Node &child, Node *prev) {
118         if (vector.child_added) {
119             vector.child_added(&node, &child, prev, data);
120         }
121     }
123     void notifyChildRemoved(Node &node, Node &child, Node *prev) {
124         if (vector.child_removed) {
125             vector.child_removed(&node, &child, prev, data);
126         }
127     }
129     void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev) {
130         if (vector.order_changed) {
131             vector.order_changed(&node, &child, old_prev, new_prev, data);
132         }
133     }
135     void notifyContentChanged(Node &node, Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content) {
136         if (vector.content_changed) {
137             vector.content_changed(&node, old_content, new_content, data);
138         }
139     }
141     void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value) {
142         if (vector.attr_changed) {
143             vector.attr_changed(&node, g_quark_to_string(name), old_value, new_value, false, data);
144         }
145     }
146 };
150 void CompositeNodeObserver::addListener(NodeEventVector const &vector,
151                                         void *data)
153     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("add-listener");
154     add(*(new VectorNodeObserver(vector, data)));
157 namespace {
159 using std::find_if;
160 using Algorithms::find_if_before;
161 typedef CompositeNodeObserver::ObserverRecord ObserverRecord;
162 typedef CompositeNodeObserver::ObserverRecordList ObserverRecordList;
164 template <typename ObserverPredicate>
165 struct unmarked_record_satisfying {
166     ObserverPredicate predicate;
167     unmarked_record_satisfying(ObserverPredicate p) : predicate(p) {}
168     bool operator()(ObserverRecord const &record) {
169         return !record.marked && predicate(record.observer);
170     }
171 };
173 template <typename Predicate>
174 bool mark_one(ObserverRecordList &observers, unsigned &marked_count,
175               Predicate p)
177     ObserverRecordList::iterator found=std::find_if(
178         observers.begin(), observers.end(),
179         unmarked_record_satisfying<Predicate>(p)
180     );
182     if ( found != observers.end() ) {
183         found->marked = true;
184         return true;
185     } else {
186         return false;
187     }
190 template <typename Predicate>
191 bool remove_one(ObserverRecordList &observers, unsigned &marked_count,
192                 Predicate p)
194     if (observers.empty()) {
195         return false;
196     }
198     if (unmarked_record_satisfying<Predicate>(p)(observers.front())) {
199         observers.pop_front();
200         return true;
201     }
203     ObserverRecordList::iterator found=find_if_before(
204         observers.begin(), observers.end(),
205         unmarked_record_satisfying<Predicate>(p)
206     );
208     if ( found != observers.end() ) {
209         observers.erase_after(found);
210         return true;
211     } else {
212         return false;
213     }
216 bool is_marked(ObserverRecord const &record) { return record.marked; }
218 void remove_all_marked(ObserverRecordList &observers, unsigned &marked_count)
220     ObserverRecordList::iterator iter;
222     g_assert( !observers.empty() || !marked_count );
224     while ( marked_count && observers.front().marked ) {
225         observers.pop_front();
226         --marked_count;
227     }
229     iter = observers.begin();
230     while (marked_count) {
231         iter = find_if_before(iter, observers.end(), is_marked);
232         observers.erase_after(iter);
233         --marked_count;
234     }
239 void CompositeNodeObserver::_finishIteration() {
240     if (!--_iterating) {
241         remove_all_marked(_active, _active_marked);
242         remove_all_marked(_pending, _pending_marked);
243         _active.insert(_active.end(), _pending.begin(), _pending.end());
244         _pending.clear();
245     }
248 namespace {
250 struct eql_observer {
251     NodeObserver const &observer;
252     eql_observer(NodeObserver const &o) : observer(o) {}
253     bool operator()(NodeObserver const &other) {
254         return &observer == &other;
255     }
256 };
260 void CompositeNodeObserver::remove(NodeObserver &observer) {
261     eql_observer p(observer);
262     if (_iterating) {
263         mark_one(_active, _active_marked, p) ||
264         mark_one(_pending, _pending_marked, p);
265     } else {
266         remove_one(_active, _active_marked, p) ||
267         remove_one(_pending, _pending_marked, p);
268     }
271 namespace {
273 struct vector_data_matches {
274     void * const data;
275     vector_data_matches(void *d) : data(d) {}
276     
277     bool operator()(NodeObserver const &observer) {
278         VectorNodeObserver const *vo=dynamic_cast<VectorNodeObserver const *>(&observer);
279         return vo && vo->data == data;
280     }
281 };
285 void CompositeNodeObserver::removeListenerByData(void *data) {
286     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("remove-listener-by-data");
287     vector_data_matches p(data);
288     if (_iterating) {
289         mark_one(_active, _active_marked, p) ||
290         mark_one(_pending, _pending_marked, p);
291     } else {
292         remove_one(_active, _active_marked, p) ||
293         remove_one(_pending, _pending_marked, p);
294     }
296     
301 /*
302   Local Variables:
303   mode:c++
304   c-file-style:"stroustrup"
305   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
306   indent-tabs-mode:nil
307   fill-column:99
308   End:
309 */
310 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :