Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
composite-node-observer.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
/*
5 * Authors: see git history
6 *
7 * Copyright (C) 2018 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10/*
11 * Inkscape::XML::CompositeNodeObserver - combine multiple observers
12 *
13 * Copyright 2005 MenTaLguY <mental@rydia.net>
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * See the file COPYING for details.
21 *
22 */
23
24#include <algorithm>
25#include <cstring>
26#include <glib.h>
27
29#include "debug/event-tracker.h"
30#include "debug/simple-event.h"
31
32namespace Inkscape {
33
34namespace XML {
35
37{
39 for (auto & iter : _active)
40 {
41 if (!iter.marked) {
42 iter.observer->notifyChildAdded(node, child, prev);
43 }
44 }
46}
47
49 Node *prev)
50{
52 for (auto & iter : _active)
53 {
54 if (!iter.marked) {
55 iter.observer->notifyChildRemoved(node, child, prev);
56 }
57 }
59}
60
62 Node *old_prev,
63 Node *new_prev)
64{
66 for (auto & iter : _active)
67 {
68 if (!iter.marked) {
69 iter.observer->notifyChildOrderChanged(node, child, old_prev, new_prev);
70 }
71 }
73}
74
76 Node &node,
77 Util::ptr_shared old_content, Util::ptr_shared new_content
78) {
80 for (auto & iter : _active)
81 {
82 if (!iter.marked) {
83 iter.observer->notifyContentChanged(node, old_content, new_content);
84 }
85 }
87}
88
91 Util::ptr_shared old_value, Util::ptr_shared new_value
92) {
94 for (auto & iter : _active)
95 {
96 if (!iter.marked) {
97 iter.observer->notifyAttributeChanged(node, name, old_value, new_value);
98 }
99 }
101}
102
104{
106 for (auto& iter : _active) {
107 if (!iter.marked) {
108 iter.observer->notifyElementNameChanged(node, old_name, new_name);
109 }
110 }
112}
113
115 if (_iterating) {
116 _pending.emplace_back(&observer);
117 } else {
118 _active.emplace_back(&observer);
119 }
120}
121
122namespace {
123
124typedef CompositeNodeObserver::ObserverRecord ObserverRecord;
125typedef CompositeNodeObserver::ObserverRecordList ObserverRecordList;
126
127template <typename ObserverPredicate>
128struct unmarked_record_satisfying {
129 ObserverPredicate predicate;
130 unmarked_record_satisfying(ObserverPredicate p) : predicate(p) {}
131 bool operator()(ObserverRecord const &record) {
132 return !record.marked && predicate(record.observer);
133 }
134};
135
136template <typename Predicate>
137bool mark_one(ObserverRecordList &observers, unsigned &marked_count,
138 Predicate p)
139{
140 auto found = std::find_if(
141 observers.begin(), observers.end(),
142 unmarked_record_satisfying<Predicate>(p)
143 );
144
145 if ( found != observers.end() ) {
146 ++marked_count;
147 found->marked = true;
148 return true;
149 } else {
150 return false;
151 }
152}
153
154template <typename Predicate>
155bool remove_one(ObserverRecordList &observers, unsigned &/*marked_count*/,
156 Predicate p)
157{
158 auto found = std::find_if(
159 observers.begin(), observers.end(),
160 unmarked_record_satisfying<Predicate>(p)
161 );
162
163 if ( found != observers.end() ) {
164 // for O(1) removal
165 if (observers.size() > 3) {
166 *found = std::move(observers.back());
167 observers.pop_back();
168 } else {
169 observers.erase(found);
170 }
171 return true;
172 } else {
173 return false;
174 }
175}
176
177bool is_marked(ObserverRecord const &record) { return record.marked; }
178
179void remove_all_marked(ObserverRecordList &observers, unsigned &marked_count)
180{
181 if (marked_count) {
182 g_assert(!observers.empty());
183
184 auto newEnd = std::remove_if(observers.begin(), observers.end(), is_marked);
185 observers.erase(newEnd, observers.end());
186 marked_count = 0;
187 }
188}
189
190}
191
193 if (!--_iterating) {
194 remove_all_marked(_active, _active_marked);
195 remove_all_marked(_pending, _pending_marked);
196 _active.insert(_active.end(), _pending.begin(), _pending.end());
197 _pending.clear();
198
199 g_assert(_pending.empty());
200 }
201}
202
203namespace {
204
205struct eql_observer {
206 NodeObserver const *observer;
207 eql_observer(NodeObserver const *o) : observer(o) {}
208 bool operator()(NodeObserver const *other) {
209 return observer == other;
210 }
211};
212
213}
214
216 eql_observer p(&observer);
217 if (_iterating) {
218 mark_one(_active, _active_marked, p) ||
219 mark_one(_pending, _pending_marked, p);
220 } else {
221 remove_one(_active, _active_marked, p) ||
222 remove_one(_pending, _pending_marked, p);
223 }
224}
225
226} // namespace XML
227} // namespace Inkscape
228/*
229 Local Variables:
230 mode:c++
231 c-file-style:"stroustrup"
232 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
233 indent-tabs-mode:nil
234 fill-column:99
235 End:
236*/
237// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
void add(NodeObserver &observer)
Add an observer to the list.
void remove(NodeObserver &observer)
Remove an observer from the list.
void notifyContentChanged(Node &node, Util::ptr_shared old_content, Util::ptr_shared new_content) override
Content change callback.
void notifyChildOrderChanged(Node &node, Node &child, Node *old_prev, Node *new_prev) override
Child order change callback.
void notifyElementNameChanged(Node &node, GQuark old_name, GQuark new_name) override
Element name change callback.
void notifyChildRemoved(Node &node, Node &child, Node *prev) override
Child removal callback.
void notifyChildAdded(Node &node, Node &child, Node *prev) override
Child addition callback.
void notifyAttributeChanged(Node &node, GQuark name, Util::ptr_shared old_value, Util::ptr_shared new_value) override
Attribute change callback.
std::vector< ObserverRecord, Inkscape::GC::Alloc< ObserverRecord, Inkscape::GC::ATOMIC > > ObserverRecordList
Interface for XML node observers.
Interface for refcounted XML nodes.
Definition node.h:80
ObserverPredicate predicate
NodeObserver const * observer
Inkscape::XML::CompositeNodeObserver - combine multiple observers.
Inkscape::XML::Node * node
Helper class to stream background task notifications as a series of messages.
Ocnode * child[8]
Definition quantize.cpp:33
guint32 GQuark
Glib::ustring name
Definition toolbars.cpp:55