21struct DocumentSubset::Relations
23 typedef std::vector<SPObject *> Siblings;
29 sigc::connection release_connection;
30 sigc::connection position_changed_connection;
32 Record() :
parent(nullptr) {}
35 Siblings::iterator found;
36 found = std::find(children.begin(), children.end(), obj);
37 if ( found != children.end() ) {
38 return found - children.begin();
44 unsigned findInsertIndex(
SPObject *obj)
const {
45 if (children.empty()) {
48 Siblings::const_iterator first=children.begin();
49 Siblings::const_iterator last=children.end() - 1;
51 while ( first != last ) {
52 Siblings::const_iterator mid = first + ( last - first + 1 ) / 2;
56 }
else if ( pos > 0 ) {
63 g_assert_not_reached();
67 if ( first == last ) {
75 return last - children.begin();
80 unsigned index=findInsertIndex(obj);
81 children.insert(children.begin()+
index, obj);
84 template <
typename OutputIterator>
85 void extractDescendants(OutputIterator descendants,
88 Siblings new_children;
90 for ( Siblings::iterator iter=children.begin()
91 ; iter != children.end() ; ++iter )
96 new_children.insert(new_children.end(),
97 children.begin(), iter);
99 *descendants++ = *iter;
100 }
else if (found_one) {
101 new_children.push_back(*iter);
105 children.swap(new_children);
109 unsigned removeChild(
SPObject *obj) {
110 Siblings::iterator found;
111 found = std::find(children.begin(), children.end(), obj);
112 unsigned index = found - children.begin();
113 if ( found != children.end() ) {
114 children.erase(found);
120 typedef std::map<SPObject *, Record> Map;
123 sigc::signal<void ()> changed_signal;
124 sigc::signal<void (
SPObject *)> added_signal;
125 sigc::signal<void (
SPObject *)> removed_signal;
127 Relations() { records[
nullptr]; }
130 for (
auto & iter : records)
134 Record &record=iter.second;
135 record.release_connection.disconnect();
136 record.position_changed_connection.disconnect();
142 auto found=records.find(obj);
143 if ( found != records.end() ) {
144 return &found->second;
158 Record &record=records[obj];
159 record.release_connection
161 sigc::mem_fun(*
this, &Relations::_release_object)
163 record.position_changed_connection
165 sigc::mem_fun(*
this, &Relations::reorder)
171 added_signal.emit(obj);
175 Record &record=records[obj];
177 if ( record.parent ==
nullptr ) {
178 Record &
root = records[
nullptr];
179 for ( Siblings::iterator it =
root.children.begin(); it !=
root.children.end(); ++it ) {
181 root.children.erase( it );
187 record.release_connection.disconnect();
188 record.position_changed_connection.disconnect();
190 removed_signal.emit(obj);
194 void _doRemoveSubtree(
SPObject *obj) {
195 Record *record=
get(obj);
197 Siblings &children=record->children;
198 for (
auto & iter : children)
200 _doRemoveSubtree(iter);
206 void _release_object(
SPObject *obj) {
221void DocumentSubset::Relations::addOne(
SPObject *obj) {
222 g_return_if_fail( obj !=
nullptr );
223 g_return_if_fail( get(obj) ==
nullptr );
225 Record &record=_doAdd(obj);
228 Record *parent_record=
nullptr;
230 ; !parent_record && parent_iter ; ++parent_iter )
232 parent_record = get(parent_iter);
234 record.parent = parent_iter;
237 if (!parent_record) {
238 parent_record =
get(
nullptr);
239 g_assert( parent_record !=
nullptr );
242 Siblings &children=record.children;
245 parent_record->extractDescendants(
246 std::back_insert_iterator<Siblings>(children),
249 for (
auto & iter : children)
251 Record *child_record=
get(iter);
252 g_assert( child_record !=
nullptr );
253 child_record->parent = obj;
257 parent_record->addChild(obj);
260 changed_signal.emit();
263void DocumentSubset::Relations::remove(
SPObject *obj,
bool subtree) {
264 g_return_if_fail( obj !=
nullptr );
266 Record *record=
get(obj);
267 g_return_if_fail( record !=
nullptr );
269 Record *parent_record=
get(record->parent);
270 g_assert( parent_record !=
nullptr );
272 unsigned index=parent_record->removeChild(obj);
275 _doRemoveSubtree(obj);
278 Siblings &siblings=parent_record->children;
279 Siblings &children=record->children;
280 siblings.insert(siblings.begin()+
index,
281 children.begin(), children.end());
283 for (
auto & iter : children)
285 Record *child_record=
get(iter);
286 g_assert( child_record !=
nullptr );
287 child_record->parent = record->parent;
294 changed_signal.emit();
297void DocumentSubset::Relations::clear() {
298 Record &
root=records[
nullptr];
300 while (!
root.children.empty()) {
301 _doRemoveSubtree(
root.children.front());
304 changed_signal.emit();
307void DocumentSubset::Relations::reorder(
SPObject *obj) {
311 Record *parent_record=
nullptr;
312 while (!parent_record) {
318 parent_record->removeChild(obj);
319 parent_record->addChild(obj);
320 changed_signal.emit();
323 Siblings descendants;
324 parent_record->extractDescendants(
325 std::back_insert_iterator<Siblings>(descendants),
328 if (!descendants.empty()) {
329 unsigned index=parent_record->findInsertIndex(obj);
330 Siblings &family=parent_record->children;
331 family.insert(family.begin()+
index,
332 descendants.begin(), descendants.end());
333 changed_signal.emit();
356 return ( record ? record->parent : nullptr );
361 return ( record ? record->children.size() : 0 );
367 return ( record ? record->childIndex(obj) : 0 );
372 return ( record ? record->children[n] : nullptr );
376 return _relations->changed_signal.connect(slot);
381 return _relations->added_signal.connect(slot);
386 return _relations->removed_signal.connect(slot);
std::unique_ptr< Relations > _relations
sigc::connection connectChanged(sigc::slot< void()> slot) const
void _remove(SPObject *obj, bool subtree)
SPObject * nthChildOf(SPObject *obj, unsigned n) const
void _addOne(SPObject *obj)
sigc::connection connectAdded(sigc::slot< void(SPObject *)> slot) const
unsigned indexOf(SPObject *obj) const
unsigned childCount(SPObject *obj) const
sigc::connection connectRemoved(sigc::slot< void(SPObject *)> slot) const
SPObject * parentOf(SPObject *obj) const
bool includes(SPObject *obj) const
SPObject is an abstract base class of all of the document nodes at the SVG document level.
sigc::connection connectPositionChanged(sigc::slot< void(SPObject *)> slot)
sigc::connection connectRelease(sigc::slot< void(SPObject *)> slot)
Connects to the release request signal.
bool isAncestorOf(SPObject const *object) const
True if object is non-NULL and this is some in/direct parent of object.
static char const *const parent
T * get(GValue *value)
Returns a borrowed pointer to the T held by a value if it holds one, else nullptr.
Helper class to stream background task notifications as a series of messages.
void remove(std::vector< T > &vec, T const &val)
int sp_object_compare_position(SPObject const *first, SPObject const *second)
Compares height of objects in tree.
SPObject * sp_object_unref(SPObject *object, SPObject *owner)
Decrease reference count of object, with possible debugging and finalization.
SPObject * sp_object_ref(SPObject *object, SPObject *owner)
Increase reference count of object, with possible debugging.