2
* Inkscape::DocumentSubset - view of a document including only a subset
5
* Copyright 2006 MenTaLguY <mental@rydia.net>
7
* Released under GNU GPL, read the file 'COPYING' for more information
10
#include "gc-finalized.h"
11
#include "document-subset.h"
13
#include "sp-object.h"
15
#include <glib/gmessages.h>
17
#include <sigc++/signal.h>
18
#include <sigc++/functors/mem_fun.h>
20
#include "util/list.h"
21
#include "util/reverse-list.h"
30
struct DocumentSubset::Relations : public GC::Managed<GC::ATOMIC>,
33
typedef std::vector<SPObject *> Siblings;
39
sigc::connection release_connection;
40
sigc::connection position_changed_connection;
42
Record() : parent(NULL) {}
44
unsigned childIndex(SPObject *obj) {
45
Siblings::iterator found;
46
found = std::find(children.begin(), children.end(), obj);
47
if ( found != children.end() ) {
48
return found - children.begin();
54
unsigned findInsertIndex(SPObject *obj) const {
55
if (children.empty()) {
58
Siblings::const_iterator first=children.begin();
59
Siblings::const_iterator last=children.end() - 1;
61
while ( first != last ) {
62
Siblings::const_iterator mid = first + ( last - first + 1 ) / 2;
63
int pos = sp_object_compare_position(*mid, obj);
66
} else if ( pos > 0 ) {
68
last = mid - 1; // already at the top limit
73
g_assert_not_reached();
77
if ( first == last ) {
78
// compare to the single possiblity left
79
int pos = sp_object_compare_position(*last, obj);
85
return last - children.begin();
89
void addChild(SPObject *obj) {
90
unsigned index=findInsertIndex(obj);
91
children.insert(children.begin()+index, obj);
94
template <typename OutputIterator>
95
void extractDescendants(OutputIterator descendants,
98
Siblings new_children;
100
for ( Siblings::iterator iter=children.begin()
101
; iter != children.end() ; iter++ )
103
if (obj->isAncestorOf(*iter)) {
106
new_children.insert(new_children.end(),
107
children.begin(), iter);
109
*descendants++ = *iter;
110
} else if (found_one) {
111
new_children.push_back(*iter);
115
children.swap(new_children);
119
unsigned removeChild(SPObject *obj) {
120
Siblings::iterator found;
121
found = std::find(children.begin(), children.end(), obj);
122
unsigned index = found - children.begin();
123
if ( found != children.end() ) {
124
children.erase(found);
130
typedef std::map<SPObject *, Record> Map;
133
sigc::signal<void> changed_signal;
134
sigc::signal<void, SPObject *> added_signal;
135
sigc::signal<void, SPObject *> removed_signal;
137
Relations() { records[NULL]; }
140
for ( Map::iterator iter=records.begin()
141
; iter != records.end() ; ++iter )
144
sp_object_unref((*iter).first);
145
Record &record=(*iter).second;
146
record.release_connection.disconnect();
147
record.position_changed_connection.disconnect();
152
Record *get(SPObject *obj) {
153
Map::iterator found=records.find(obj);
154
if ( found != records.end() ) {
155
return &(*found).second;
161
void addOne(SPObject *obj);
162
void remove(SPObject *obj, bool subtree);
163
void reorder(SPObject *obj);
167
Record &_doAdd(SPObject *obj) {
169
Record &record=records[obj];
170
record.release_connection
171
= obj->connectRelease(
172
sigc::mem_fun(this, &Relations::_release_object)
174
record.position_changed_connection
175
= obj->connectPositionChanged(
176
sigc::mem_fun(this, &Relations::reorder)
181
void _notifyAdded(SPObject *obj) {
182
added_signal.emit(obj);
185
void _doRemove(SPObject *obj) {
186
Record &record=records[obj];
187
record.release_connection.disconnect();
188
record.position_changed_connection.disconnect();
191
if ( record.parent == NULL ) {
192
Record &root = records[NULL];
193
for ( Siblings::iterator it = root.children.begin(); it != root.children.end(); ++it ) {
195
root.children.erase( it );
201
removed_signal.emit(obj);
202
sp_object_unref(obj);
205
void _doRemoveSubtree(SPObject *obj) {
206
Record *record=get(obj);
208
Siblings &children=record->children;
209
for ( Siblings::iterator iter=children.begin()
210
; iter != children.end() ; ++iter )
212
_doRemoveSubtree(*iter);
218
void _release_object(SPObject *obj) {
225
DocumentSubset::DocumentSubset()
226
: _relations(new DocumentSubset::Relations())
230
void DocumentSubset::Relations::addOne(SPObject *obj) {
231
g_return_if_fail( obj != NULL );
232
g_return_if_fail( get(obj) == NULL );
234
Record &record=_doAdd(obj);
236
/* find the nearest ancestor in the subset */
237
Record *parent_record=NULL;
238
for ( SPObject::ParentIterator parent_iter=obj->parent
239
; !parent_record && parent_iter ; ++parent_iter )
241
parent_record = get(parent_iter);
243
record.parent = parent_iter;
246
if (!parent_record) {
247
parent_record = get(NULL);
248
g_assert( parent_record != NULL );
251
Siblings &children=record.children;
253
/* reparent descendants of obj to obj */
254
parent_record->extractDescendants(
255
std::back_insert_iterator<Siblings>(children),
258
for ( Siblings::iterator iter=children.begin()
259
; iter != children.end() ; ++iter )
261
Record *child_record=get(*iter);
262
g_assert( child_record != NULL );
263
child_record->parent = obj;
266
/* add obj to the child list */
267
parent_record->addChild(obj);
270
changed_signal.emit();
273
void DocumentSubset::Relations::remove(SPObject *obj, bool subtree) {
274
g_return_if_fail( obj != NULL );
276
Record *record=get(obj);
277
g_return_if_fail( record != NULL );
279
Record *parent_record=get(record->parent);
280
g_assert( parent_record != NULL );
282
unsigned index=parent_record->removeChild(obj);
285
_doRemoveSubtree(obj);
287
/* reparent obj's orphaned children to their grandparent */
288
Siblings &siblings=parent_record->children;
289
Siblings &children=record->children;
290
siblings.insert(siblings.begin()+index,
291
children.begin(), children.end());
293
for ( Siblings::iterator iter=children.begin()
294
; iter != children.end() ; iter++ )
296
Record *child_record=get(*iter);
297
g_assert( child_record != NULL );
298
child_record->parent = record->parent;
301
/* remove obj's record */
305
changed_signal.emit();
308
void DocumentSubset::Relations::clear() {
309
Record &root=records[NULL];
311
while (!root.children.empty()) {
312
_doRemoveSubtree(root.children.front());
315
changed_signal.emit();
318
void DocumentSubset::Relations::reorder(SPObject *obj) {
319
SPObject::ParentIterator parent=obj;
321
/* find nearest ancestor in the subset */
322
Record *parent_record=NULL;
323
while (!parent_record) {
324
parent_record = get(++parent);
328
/* move the object if it's in the subset */
329
parent_record->removeChild(obj);
330
parent_record->addChild(obj);
331
changed_signal.emit();
333
/* otherwise, move any top-level descendants */
334
Siblings descendants;
335
parent_record->extractDescendants(
336
std::back_insert_iterator<Siblings>(descendants),
339
if (!descendants.empty()) {
340
unsigned index=parent_record->findInsertIndex(obj);
341
Siblings &family=parent_record->children;
342
family.insert(family.begin()+index,
343
descendants.begin(), descendants.end());
344
changed_signal.emit();
349
void DocumentSubset::_addOne(SPObject *obj) {
350
_relations->addOne(obj);
353
void DocumentSubset::_remove(SPObject *obj, bool subtree) {
354
_relations->remove(obj, subtree);
357
void DocumentSubset::_clear() {
361
bool DocumentSubset::includes(SPObject *obj) const {
362
return _relations->get(obj);
365
SPObject *DocumentSubset::parentOf(SPObject *obj) const {
366
Relations::Record *record=_relations->get(obj);
367
return ( record ? record->parent : NULL );
370
unsigned DocumentSubset::childCount(SPObject *obj) const {
371
Relations::Record *record=_relations->get(obj);
372
return ( record ? record->children.size() : 0 );
375
unsigned DocumentSubset::indexOf(SPObject *obj) const {
376
SPObject *parent=parentOf(obj);
377
Relations::Record *record=_relations->get(parent);
378
return ( record ? record->childIndex(obj) : 0 );
381
SPObject *DocumentSubset::nthChildOf(SPObject *obj, unsigned n) const {
382
Relations::Record *record=_relations->get(obj);
383
return ( record ? record->children[n] : NULL );
386
sigc::connection DocumentSubset::connectChanged(sigc::slot<void> slot) const {
387
return _relations->changed_signal.connect(slot);
391
DocumentSubset::connectAdded(sigc::slot<void, SPObject *> slot) const {
392
return _relations->added_signal.connect(slot);
396
DocumentSubset::connectRemoved(sigc::slot<void, SPObject *> slot) const {
397
return _relations->removed_signal.connect(slot);
405
c-file-style:"stroustrup"
406
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
411
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :