Code

Fix change in revision 9947 to be consistent with rest of the codebase.
[inkscape.git] / src / object-hierarchy.cpp
1 /** \file
2  * Object hierarchy implementation.
3  *
4  * Authors:
5  *   MenTaLguY <mental@rydia.net>
6  *
7  * Copyright (C) 2004 MenTaLguY
8  *
9  * Released under GNU GPL, read the file 'COPYING' for more information
10  */
12 #include "sp-object.h"
13 #include "object-hierarchy.h"
15 #include <sigc++/functors/mem_fun.h>
17 namespace Inkscape {
19 /**
20  * Create new object hierarchy.
21  * \param top The first entry if non-NULL.
22  */
23 ObjectHierarchy::ObjectHierarchy(SPObject *top) {
24     if (top) {
25         _addBottom(top);
26     }
27 }
29 ObjectHierarchy::~ObjectHierarchy() {
30     _clear();
31 }
33 /**
34  * Remove all entries.
35  */
36 void ObjectHierarchy::clear() {
37     _clear();
38     _changed_signal.emit(NULL, NULL);
39 }
41 /**
42  * Trim or expand hierarchy on top such that object becomes top entry.
43  */
44 void ObjectHierarchy::setTop(SPObject *object) {
45     g_return_if_fail(object != NULL);
47     if ( top() == object ) {
48         return;
49     }
51     if (!top()) {
52         _addTop(object);
53     } else if (object->isAncestorOf(top())) {
54         _addTop(object, top());
55     } else if ( object == bottom() || object->isAncestorOf(bottom()) ) {
56         _trimAbove(object);
57     } else {
58         _clear();
59         _addTop(object);
60     }
62     _changed_signal.emit(top(), bottom());
63 }
65 /**
66  * Add hierarchy from junior's parent to senior to this
67  * hierarchy's top.
68  */
69 void ObjectHierarchy::_addTop(SPObject *senior, SPObject *junior) {
70     g_assert(junior != NULL);
71     g_assert(senior != NULL);
73     SPObject *object=SP_OBJECT_PARENT(junior);
74     do {
75         _addTop(object);
76         object = SP_OBJECT_PARENT(object);
77     } while ( object != senior );
78 }
80 /**
81  * Add object to top of hierarchy.
82  * \pre object!=NULL
83  */
84 void ObjectHierarchy::_addTop(SPObject *object) {
85     g_assert(object != NULL);
86     _hierarchy.push_back(_attach(object));
87     _added_signal.emit(object);
88 }
90 /**
91  * Remove all objects above limit from hierarchy.
92  */
93 void ObjectHierarchy::_trimAbove(SPObject *limit) {
94     while ( !_hierarchy.empty() && _hierarchy.back().object != limit ) {
95         SPObject *object=_hierarchy.back().object;
97         sp_object_ref(object, NULL);
98         _detach(_hierarchy.back());
99         _hierarchy.pop_back();
100         _removed_signal.emit(object);
101         sp_object_unref(object, NULL);
102     }
105 /**
106  * Trim or expand hierarchy at bottom such that object becomes bottom entry.
107  */
108 void ObjectHierarchy::setBottom(SPObject *object) {
109     g_return_if_fail(object != NULL);
111     if ( bottom() == object ) {
112         return;
113     }
115     if (!top()) {
116         _addBottom(object);
117     } else if (bottom()->isAncestorOf(object)) {
118         _addBottom(bottom(), object);
119     } else if ( top() == object ) {
120         _trimBelow(top());
121     } else if (top()->isAncestorOf(object)) {
122         if (object->isAncestorOf(bottom())) {
123             _trimBelow(object);
124         } else { // object is a sibling or cousin of bottom()
125             SPObject *saved_top=top();
126             sp_object_ref(saved_top, NULL);
127             _clear();
128             _addBottom(saved_top);
129             _addBottom(saved_top, object);
130             sp_object_unref(saved_top, NULL);
131         }
132     } else {
133         _clear();
134         _addBottom(object);
135     }
137     _changed_signal.emit(top(), bottom());
140 /**
141  * Remove all objects under given object.
142  * \param limit If NULL, remove all.
143  */
144 void ObjectHierarchy::_trimBelow(SPObject *limit) {
145     while ( !_hierarchy.empty() && _hierarchy.front().object != limit ) {
146         SPObject *object=_hierarchy.front().object;
147         sp_object_ref(object, NULL);
148         _detach(_hierarchy.front());
149         _hierarchy.pop_front();
150         _removed_signal.emit(object);
151         sp_object_unref(object, NULL);
152     }
155 /**
156  * Add hierarchy from senior to junior to this hierarchy's bottom.
157  */
158 void ObjectHierarchy::_addBottom(SPObject *senior, SPObject *junior) {
159     g_assert(junior != NULL);
160     g_assert(senior != NULL);
162     if ( junior != senior ) {
163         _addBottom(senior, SP_OBJECT_PARENT(junior));
164         _addBottom(junior);
165     }
168 /**
169  * Add object at bottom of hierarchy.
170  * \pre object!=NULL
171  */
172 void ObjectHierarchy::_addBottom(SPObject *object) {
173     g_assert(object != NULL);
174     _hierarchy.push_front(_attach(object));
175     _added_signal.emit(object);
178 void ObjectHierarchy::_trim_for_release(SPObject *object) {
179     this->_trimBelow(object);
180     g_assert(!this->_hierarchy.empty());
181     g_assert(this->_hierarchy.front().object == object);
183     sp_object_ref(object, NULL);
184     this->_detach(this->_hierarchy.front());
185     this->_hierarchy.pop_front();
186     this->_removed_signal.emit(object);
187     sp_object_unref(object, NULL);
189     this->_changed_signal.emit(this->top(), this->bottom());
192 ObjectHierarchy::Record ObjectHierarchy::_attach(SPObject *object) {
193     sp_object_ref(object, NULL);
194     sigc::connection connection
195       = object->connectRelease(
196           sigc::mem_fun(*this, &ObjectHierarchy::_trim_for_release)
197         );
198     return Record(object, connection);
201 void ObjectHierarchy::_detach(ObjectHierarchy::Record &rec) {
202     rec.connection.disconnect();
203     sp_object_unref(rec.object, NULL);
208 /*
209   Local Variables:
210   mode:c++
211   c-file-style:"stroustrup"
212   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
213   indent-tabs-mode:nil
214   fill-column:99
215   End:
216 */
217 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :