~mc.../inkscape/inkscape

« back to all changes in this revision

Viewing changes to src/xml/composite-node-observer.cpp

  • Committer: mental
  • Date: 2006-01-16 02:36:01 UTC
  • Revision ID: mental@users.sourceforge.net-20060116023601-wkr0h7edl5veyudq
moving trunk for module inkscape

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
14
 
 
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"
 
20
 
 
21
namespace Inkscape {
 
22
 
 
23
namespace XML {
 
24
 
 
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
}
 
37
 
 
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
}
 
51
 
 
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
}
 
66
 
 
67
void CompositeNodeObserver::notifyContentChanged(
 
68
    Node &node,
 
69
    Util::SharedCStringPtr old_content, Util::SharedCStringPtr 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
}
 
81
 
 
82
void CompositeNodeObserver::notifyAttributeChanged(
 
83
    Node &node, GQuark name,
 
84
    Util::SharedCStringPtr old_value, Util::SharedCStringPtr 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
}
 
96
 
 
97
void CompositeNodeObserver::add(NodeObserver &observer) {
 
98
    if (_iterating) {
 
99
        _pending.push_back(ObserverRecord(observer));
 
100
    } else {
 
101
        _active.push_back(ObserverRecord(observer));
 
102
    }
 
103
}
 
104
 
 
105
namespace {
 
106
 
 
107
class VectorNodeObserver : public NodeObserver, public GC::Managed<> {
 
108
public:
 
109
    VectorNodeObserver(NodeEventVector const &v, void *d)
 
110
    : vector(v), data(d) {}
 
111
 
 
112
    NodeEventVector const &vector;
 
113
    void * const data;
 
114
 
 
115
    void notifyChildAdded(Node &node, Node &child, Node *prev) {
 
116
        if (vector.child_added) {
 
117
            vector.child_added(&node, &child, prev, data);
 
118
        }
 
119
    }
 
120
 
 
121
    void notifyChildRemoved(Node &node, Node &child, Node *prev) {
 
122
        if (vector.child_removed) {
 
123
            vector.child_removed(&node, &child, prev, data);
 
124
        }
 
125
    }
 
126
 
 
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
    }
 
132
 
 
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);
 
136
        }
 
137
    }
 
138
 
 
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);
 
142
        }
 
143
    }
 
144
};
 
145
 
 
146
}
 
147
 
 
148
void CompositeNodeObserver::addListener(NodeEventVector const &vector,
 
149
                                        void *data)
 
150
{
 
151
    Debug::EventTracker<Debug::SimpleEvent<Debug::Event::XML> > tracker("add-listener");
 
152
    add(*(new VectorNodeObserver(vector, data)));
 
153
}
 
154
 
 
155
namespace {
 
156
 
 
157
using std::find_if;
 
158
using Algorithms::find_if_before;
 
159
typedef CompositeNodeObserver::ObserverRecord ObserverRecord;
 
160
typedef CompositeNodeObserver::ObserverRecordList ObserverRecordList;
 
161
 
 
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
};
 
170
 
 
171
template <typename Predicate>
 
172
bool mark_one(ObserverRecordList &observers, unsigned &marked_count,
 
173
              Predicate p)
 
174
{
 
175
    ObserverRecordList::iterator found=std::find_if(
 
176
        observers.begin(), observers.end(),
 
177
        unmarked_record_satisfying<Predicate>(p)
 
178
    );
 
179
 
 
180
    if ( found != observers.end() ) {
 
181
        found->marked = true;
 
182
        return true;
 
183
    } else {
 
184
        return false;
 
185
    }
 
186
}
 
187
 
 
188
template <typename Predicate>
 
189
bool remove_one(ObserverRecordList &observers, unsigned &marked_count,
 
190
                Predicate p)
 
191
{
 
192
    if (observers.empty()) {
 
193
        return false;
 
194
    }
 
195
 
 
196
    if (unmarked_record_satisfying<Predicate>(p)(observers.front())) {
 
197
        observers.pop_front();
 
198
        return true;
 
199
    }
 
200
 
 
201
    ObserverRecordList::iterator found=find_if_before(
 
202
        observers.begin(), observers.end(),
 
203
        unmarked_record_satisfying<Predicate>(p)
 
204
    );
 
205
 
 
206
    if ( found != observers.end() ) {
 
207
        observers.erase_after(found);
 
208
        return true;
 
209
    } else {
 
210
        return false;
 
211
    }
 
212
}
 
213
 
 
214
bool is_marked(ObserverRecord const &record) { return record.marked; }
 
215
 
 
216
void remove_all_marked(ObserverRecordList &observers, unsigned &marked_count)
 
217
{
 
218
    ObserverRecordList::iterator iter;
 
219
 
 
220
    g_assert( !observers.empty() || !marked_count );
 
221
 
 
222
    while ( marked_count && observers.front().marked ) {
 
223
        observers.pop_front();
 
224
        --marked_count;
 
225
    }
 
226
 
 
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
    }
 
233
}
 
234
 
 
235
}
 
236
 
 
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
    }
 
244
}
 
245
 
 
246
namespace {
 
247
 
 
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
};
 
255
 
 
256
}
 
257
 
 
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
    }
 
267
}
 
268
 
 
269
namespace {
 
270
 
 
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
};
 
280
 
 
281
}
 
282
 
 
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
    }
 
293
}
 
294
    
 
295
}
 
296
 
 
297
}
 
298
 
 
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 :