2
* Inkscape::XML::CompositeNodeObserver - combine multiple observers
4
* Copyright 2005 MenTaLguY <mental@rydia.net>
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.
11
* See the file COPYING for details.
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"
25
void CompositeNodeObserver::notifyChildAdded(Node &node, Node &child, Node *prev)
28
for ( ObserverRecordList::iterator iter=_active.begin() ;
29
iter != _active.end() ; ++iter )
32
iter->observer.notifyChildAdded(node, child, prev);
38
void CompositeNodeObserver::notifyChildRemoved(Node &node, Node &child,
42
for ( ObserverRecordList::iterator iter=_active.begin() ;
43
iter != _active.end() ; ++iter )
46
iter->observer.notifyChildRemoved(node, child, prev);
52
void CompositeNodeObserver::notifyChildOrderChanged(Node &node, Node &child,
57
for ( ObserverRecordList::iterator iter=_active.begin() ;
58
iter != _active.end() ; ++iter )
61
iter->observer.notifyChildOrderChanged(node, child, old_prev, new_prev);
67
void CompositeNodeObserver::notifyContentChanged(
69
Util::SharedCStringPtr old_content, Util::SharedCStringPtr new_content
72
for ( ObserverRecordList::iterator iter=_active.begin() ;
73
iter != _active.end() ; ++iter )
76
iter->observer.notifyContentChanged(node, old_content, new_content);
82
void CompositeNodeObserver::notifyAttributeChanged(
83
Node &node, GQuark name,
84
Util::SharedCStringPtr old_value, Util::SharedCStringPtr new_value
87
for ( ObserverRecordList::iterator iter=_active.begin() ;
88
iter != _active.end() ; ++iter )
91
iter->observer.notifyAttributeChanged(node, name, old_value, new_value);
97
void CompositeNodeObserver::add(NodeObserver &observer) {
99
_pending.push_back(ObserverRecord(observer));
101
_active.push_back(ObserverRecord(observer));
107
class VectorNodeObserver : public NodeObserver, public GC::Managed<> {
109
VectorNodeObserver(NodeEventVector const &v, void *d)
110
: vector(v), data(d) {}
112
NodeEventVector const &vector;
115
void notifyChildAdded(Node &node, Node &child, Node *prev) {
116
if (vector.child_added) {
117
vector.child_added(&node, &child, prev, data);
121
void notifyChildRemoved(Node &node, Node &child, Node *prev) {
122
if (vector.child_removed) {
123
vector.child_removed(&node, &child, prev, data);
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);
133
void notifyContentChanged(Node &node, Util::SharedCStringPtr old_content, Util::SharedCStringPtr new_content) {
134
if (vector.content_changed) {
135
vector.content_changed(&node, old_content, new_content, data);
139
void notifyAttributeChanged(Node &node, GQuark name, Util::SharedCStringPtr old_value, Util::SharedCStringPtr new_value) {
140
if (vector.attr_changed) {
141
vector.attr_changed(&node, g_quark_to_string(name), old_value, new_value, false, data);
148
void CompositeNodeObserver::addListener(NodeEventVector const &vector,
151
Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("add-listener");
152
add(*(new VectorNodeObserver(vector, data)));
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);
171
template <typename Predicate>
172
bool mark_one(ObserverRecordList &observers, unsigned &marked_count,
175
ObserverRecordList::iterator found=std::find_if(
176
observers.begin(), observers.end(),
177
unmarked_record_satisfying<Predicate>(p)
180
if ( found != observers.end() ) {
181
found->marked = true;
188
template <typename Predicate>
189
bool remove_one(ObserverRecordList &observers, unsigned &marked_count,
192
if (observers.empty()) {
196
if (unmarked_record_satisfying<Predicate>(p)(observers.front())) {
197
observers.pop_front();
201
ObserverRecordList::iterator found=find_if_before(
202
observers.begin(), observers.end(),
203
unmarked_record_satisfying<Predicate>(p)
206
if ( found != observers.end() ) {
207
observers.erase_after(found);
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();
227
iter = observers.begin();
228
while (marked_count) {
229
iter = find_if_before(iter, observers.end(), is_marked);
230
observers.erase_after(iter);
237
void CompositeNodeObserver::_finishIteration() {
239
remove_all_marked(_active, _active_marked);
240
remove_all_marked(_pending, _pending_marked);
241
_active.insert(_active.end(), _pending.begin(), _pending.end());
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;
258
void CompositeNodeObserver::remove(NodeObserver &observer) {
259
eql_observer p(observer);
261
mark_one(_active, _active_marked, p) ||
262
mark_one(_pending, _pending_marked, p);
264
remove_one(_active, _active_marked, p) ||
265
remove_one(_pending, _pending_marked, p);
271
struct vector_data_matches {
273
vector_data_matches(void *d) : data(d) {}
275
bool operator()(NodeObserver const &observer) {
276
VectorNodeObserver const *vo=dynamic_cast<VectorNodeObserver const *>(&observer);
277
return vo && vo->data == data;
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);
287
mark_one(_active, _active_marked, p) ||
288
mark_one(_pending, _pending_marked, p);
290
remove_one(_active, _active_marked, p) ||
291
remove_one(_pending, _pending_marked, p);
302
c-file-style:"stroustrup"
303
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
308
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :