Code

added fix from Dale Harvey to expand incomplete JIDs specified in user
[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 "algorithms/find-if-before.h"
16 #include "xml/composite-node-observer.h"
17 #include "xml/node-event-vector.h"
18 #include "debug/event-tracker.h"
19 #include "debug/simple-event.h"
21 namespace Inkscape {
23 namespace XML {
25 void CompositeNodeObserver::notifyChildAdded(Node &node, Node &child, Node *prev)
26 {
27     _startIteration();
28     for ( ObserverRecordList::iterator iter=_active.begin() ;
29           iter != _active.end() ; ++iter )
30     {
31         if (!iter->marked) {
32             iter->observer.notifyChildAdded(node, child, prev);
33         }
34     }
35     _finishIteration();
36 }
38 void CompositeNodeObserver::notifyChildRemoved(Node &node, Node &child,
39                                                            Node *prev)
40 {
41     _startIteration();
42     for ( ObserverRecordList::iterator iter=_active.begin() ;
43           iter != _active.end() ; ++iter )
44     {
45         if (!iter->marked) {
46             iter->observer.notifyChildRemoved(node, child, prev);
47         }
48     }
49     _finishIteration();
50 }
52 void CompositeNodeObserver::notifyChildOrderChanged(Node &node, Node &child,
53                                                                 Node *old_prev,
54                                                                 Node *new_prev)
55 {
56     _startIteration();
57     for ( ObserverRecordList::iterator iter=_active.begin() ;
58           iter != _active.end() ; ++iter )
59     {
60         if (!iter->marked) {
61             iter->observer.notifyChildOrderChanged(node, child, old_prev, new_prev);
62         }
63     }
64     _finishIteration();
65 }
67 void CompositeNodeObserver::notifyContentChanged(
68     Node &node,
69     Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content
70 ) {
71     _startIteration();
72     for ( ObserverRecordList::iterator iter=_active.begin() ;
73           iter != _active.end() ; ++iter )
74     {
75         if (!iter->marked) {
76             iter->observer.notifyContentChanged(node, old_content, new_content);
77         }
78     }
79     _finishIteration();
80 }
82 void CompositeNodeObserver::notifyAttributeChanged(
83     Node &node, GQuark name,
84     Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value
85 ) {
86     _startIteration();
87     for ( ObserverRecordList::iterator iter=_active.begin() ;
88           iter != _active.end() ; ++iter )
89     {
90         if (!iter->marked) {
91             iter->observer.notifyAttributeChanged(node, name, old_value, new_value);
92         }
93     }
94     _finishIteration();
95 }
97 void CompositeNodeObserver::add(NodeObserver &observer) {
98     if (_iterating) {
99         _pending.push_back(ObserverRecord(observer));
100     } else {
101         _active.push_back(ObserverRecord(observer));
102     }
105 namespace {
107 class VectorNodeObserver : public NodeObserver, public GC::Managed<> {
108 public:
109     VectorNodeObserver(NodeEventVector const &v, void *d)
110     : vector(v), data(d) {}
112     NodeEventVector const &vector;
113     void * const data;
115     void notifyChildAdded(Node &node, Node &child, Node *prev) {
116         if (vector.child_added) {
117             vector.child_added(&node, &child, prev, data);
118         }
119     }
121     void notifyChildRemoved(Node &node, Node &child, Node *prev) {
122         if (vector.child_removed) {
123             vector.child_removed(&node, &child, prev, data);
124         }
125     }
127     void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev) {
128         if (vector.order_changed) {
129             vector.order_changed(&node, &child, old_prev, new_prev, data);
130         }
131     }
133     void notifyContentChanged(Node &node, Util::ptr_shared<char> old_content, Util::ptr_shared<char> new_content) {
134         if (vector.content_changed) {
135             vector.content_changed(&node, old_content, new_content, data);
136         }
137     }
139     void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared<char> old_value, Util::ptr_shared<char> new_value) {
140         if (vector.attr_changed) {
141             vector.attr_changed(&node, g_quark_to_string(name), old_value, new_value, false, data);
142         }
143     }
144 };
148 void CompositeNodeObserver::addListener(NodeEventVector const &vector,
149                                         void *data)
151     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("add-listener");
152     add(*(new VectorNodeObserver(vector, data)));
155 namespace {
157 using std::find_if;
158 using Algorithms::find_if_before;
159 typedef CompositeNodeObserver::ObserverRecord ObserverRecord;
160 typedef CompositeNodeObserver::ObserverRecordList ObserverRecordList;
162 template <typename ObserverPredicate>
163 struct unmarked_record_satisfying {
164     ObserverPredicate predicate;
165     unmarked_record_satisfying(ObserverPredicate p) : predicate(p) {}
166     bool operator()(ObserverRecord const &record) {
167         return !record.marked && predicate(record.observer);
168     }
169 };
171 template <typename Predicate>
172 bool mark_one(ObserverRecordList &observers, unsigned &marked_count,
173               Predicate p)
175     ObserverRecordList::iterator found=std::find_if(
176         observers.begin(), observers.end(),
177         unmarked_record_satisfying<Predicate>(p)
178     );
180     if ( found != observers.end() ) {
181         found->marked = true;
182         return true;
183     } else {
184         return false;
185     }
188 template <typename Predicate>
189 bool remove_one(ObserverRecordList &observers, unsigned &marked_count,
190                 Predicate p)
192     if (observers.empty()) {
193         return false;
194     }
196     if (unmarked_record_satisfying<Predicate>(p)(observers.front())) {
197         observers.pop_front();
198         return true;
199     }
201     ObserverRecordList::iterator found=find_if_before(
202         observers.begin(), observers.end(),
203         unmarked_record_satisfying<Predicate>(p)
204     );
206     if ( found != observers.end() ) {
207         observers.erase_after(found);
208         return true;
209     } else {
210         return false;
211     }
214 bool is_marked(ObserverRecord const &record) { return record.marked; }
216 void remove_all_marked(ObserverRecordList &observers, unsigned &marked_count)
218     ObserverRecordList::iterator iter;
220     g_assert( !observers.empty() || !marked_count );
222     while ( marked_count && observers.front().marked ) {
223         observers.pop_front();
224         --marked_count;
225     }
227     iter = observers.begin();
228     while (marked_count) {
229         iter = find_if_before(iter, observers.end(), is_marked);
230         observers.erase_after(iter);
231         --marked_count;
232     }
237 void CompositeNodeObserver::_finishIteration() {
238     if (!--_iterating) {
239         remove_all_marked(_active, _active_marked);
240         remove_all_marked(_pending, _pending_marked);
241         _active.insert(_active.end(), _pending.begin(), _pending.end());
242         _pending.clear();
243     }
246 namespace {
248 struct eql_observer {
249     NodeObserver const &observer;
250     eql_observer(NodeObserver const &o) : observer(o) {}
251     bool operator()(NodeObserver const &other) {
252         return &observer == &other;
253     }
254 };
258 void CompositeNodeObserver::remove(NodeObserver &observer) {
259     eql_observer p(observer);
260     if (_iterating) {
261         mark_one(_active, _active_marked, p) ||
262         mark_one(_pending, _pending_marked, p);
263     } else {
264         remove_one(_active, _active_marked, p) ||
265         remove_one(_pending, _pending_marked, p);
266     }
269 namespace {
271 struct vector_data_matches {
272     void * const data;
273     vector_data_matches(void *d) : data(d) {}
274     
275     bool operator()(NodeObserver const &observer) {
276         VectorNodeObserver const *vo=dynamic_cast<VectorNodeObserver const *>(&observer);
277         return vo && vo->data == data;
278     }
279 };
283 void CompositeNodeObserver::removeListenerByData(void *data) {
284     Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("remove-listener-by-data");
285     vector_data_matches p(data);
286     if (_iterating) {
287         mark_one(_active, _active_marked, p) ||
288         mark_one(_pending, _pending_marked, p);
289     } else {
290         remove_one(_active, _active_marked, p) ||
291         remove_one(_pending, _pending_marked, p);
292     }
294     
299 /*
300   Local Variables:
301   mode:c++
302   c-file-style:"stroustrup"
303   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
304   indent-tabs-mode:nil
305   fill-column:99
306   End:
307 */
308 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :