~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/document-subset.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Inkscape::DocumentSubset - view of a document including only a subset
 
3
 *                            of nodes
 
4
 *
 
5
 * Copyright 2006  MenTaLguY  <mental@rydia.net>
 
6
 *
 
7
 * Released under GNU GPL, read the file 'COPYING' for more information
 
8
 */
 
9
 
 
10
#include "gc-finalized.h"
 
11
#include "document-subset.h"
 
12
#include "document.h"
 
13
#include "sp-object.h"
 
14
 
 
15
#include <glib/gmessages.h>
 
16
 
 
17
#include <sigc++/signal.h>
 
18
#include <sigc++/functors/mem_fun.h>
 
19
 
 
20
#include "util/list.h"
 
21
#include "util/reverse-list.h"
 
22
 
 
23
#include <vector>
 
24
#include <map>
 
25
#include <algorithm>
 
26
#include <iterator>
 
27
 
 
28
namespace Inkscape {
 
29
 
 
30
struct DocumentSubset::Relations : public GC::Managed<GC::ATOMIC>,
 
31
                                   public GC::Finalized
 
32
{
 
33
    typedef std::vector<SPObject *> Siblings;
 
34
 
 
35
    struct Record {
 
36
        SPObject *parent;
 
37
        Siblings children;
 
38
 
 
39
        sigc::connection release_connection;
 
40
        sigc::connection position_changed_connection;
 
41
 
 
42
        Record() : parent(NULL) {}
 
43
 
 
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();
 
49
            } else {
 
50
                return 0;
 
51
            }
 
52
        }
 
53
 
 
54
        unsigned findInsertIndex(SPObject *obj) const {
 
55
            if (children.empty()) {
 
56
                return 0;
 
57
            } else {
 
58
                Siblings::const_iterator first=children.begin();
 
59
                Siblings::const_iterator last=children.end() - 1;
 
60
 
 
61
                while ( first != last ) {
 
62
                    Siblings::const_iterator mid = first + ( last - first + 1 ) / 2;
 
63
                    int pos = sp_object_compare_position(*mid, obj);
 
64
                    if ( pos < 0 ) {
 
65
                        first = mid;
 
66
                    } else if ( pos > 0 ) {
 
67
                        if ( last == mid ) {
 
68
                            last = mid - 1; // already at the top limit
 
69
                        } else {
 
70
                            last = mid;
 
71
                        }
 
72
                    } else {
 
73
                        g_assert_not_reached();
 
74
                    }
 
75
                }
 
76
 
 
77
                if ( first == last ) {
 
78
                    // compare to the single possiblity left
 
79
                    int pos = sp_object_compare_position(*last, obj);
 
80
                    if ( pos < 0 ) {
 
81
                        last++;
 
82
                    }
 
83
                }
 
84
 
 
85
                return last - children.begin();
 
86
            }
 
87
        }
 
88
 
 
89
        void addChild(SPObject *obj) {
 
90
            unsigned index=findInsertIndex(obj);
 
91
            children.insert(children.begin()+index, obj);
 
92
        }
 
93
 
 
94
        template <typename OutputIterator>
 
95
        void extractDescendants(OutputIterator descendants,
 
96
                                SPObject *obj)
 
97
        {
 
98
            Siblings new_children;
 
99
            bool found_one=false;
 
100
            for ( Siblings::iterator iter=children.begin()
 
101
                ; iter != children.end() ; iter++ )
 
102
            {
 
103
                if (obj->isAncestorOf(*iter)) {
 
104
                    if (!found_one) {
 
105
                        found_one = true;
 
106
                        new_children.insert(new_children.end(),
 
107
                                            children.begin(), iter);
 
108
                    }
 
109
                    *descendants++ = *iter;
 
110
                } else if (found_one) {
 
111
                    new_children.push_back(*iter);
 
112
                }
 
113
            }
 
114
            if (found_one) {
 
115
                children.swap(new_children);
 
116
            }
 
117
        }
 
118
 
 
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);
 
125
            }
 
126
            return index;
 
127
        }
 
128
    };
 
129
 
 
130
    typedef std::map<SPObject *, Record> Map;
 
131
    Map records;
 
132
 
 
133
    sigc::signal<void> changed_signal;
 
134
    sigc::signal<void, SPObject *> added_signal;
 
135
    sigc::signal<void, SPObject *> removed_signal;
 
136
 
 
137
    Relations() { records[NULL]; }
 
138
 
 
139
    ~Relations() {
 
140
        for ( Map::iterator iter=records.begin()
 
141
            ; iter != records.end() ; ++iter )
 
142
        {
 
143
            if ((*iter).first) {
 
144
                sp_object_unref((*iter).first);
 
145
                Record &record=(*iter).second;
 
146
                record.release_connection.disconnect();
 
147
                record.position_changed_connection.disconnect();
 
148
            }
 
149
        }
 
150
    }
 
151
 
 
152
    Record *get(SPObject *obj) {
 
153
        Map::iterator found=records.find(obj);
 
154
        if ( found != records.end() ) {
 
155
            return &(*found).second;
 
156
        } else {
 
157
            return NULL;
 
158
        }
 
159
    }
 
160
 
 
161
    void addOne(SPObject *obj);
 
162
    void remove(SPObject *obj, bool subtree);
 
163
    void reorder(SPObject *obj);
 
164
    void clear();
 
165
 
 
166
private:
 
167
    Record &_doAdd(SPObject *obj) {
 
168
        sp_object_ref(obj);
 
169
        Record &record=records[obj];
 
170
        record.release_connection
 
171
          = obj->connectRelease(
 
172
              sigc::mem_fun(this, &Relations::_release_object)
 
173
            );
 
174
        record.position_changed_connection
 
175
          = obj->connectPositionChanged(
 
176
              sigc::mem_fun(this, &Relations::reorder)
 
177
            );
 
178
        return record;
 
179
    }
 
180
 
 
181
    void _notifyAdded(SPObject *obj) {
 
182
        added_signal.emit(obj);
 
183
    }
 
184
 
 
185
    void _doRemove(SPObject *obj) {
 
186
        Record &record=records[obj];
 
187
        record.release_connection.disconnect();
 
188
        record.position_changed_connection.disconnect();
 
189
        records.erase(obj);
 
190
 
 
191
        if ( record.parent == NULL ) {
 
192
            Record &root = records[NULL];
 
193
            for ( Siblings::iterator it = root.children.begin(); it != root.children.end(); ++it ) {
 
194
                if ( *it == obj ) {
 
195
                    root.children.erase( it );
 
196
                    break;
 
197
                }
 
198
            }
 
199
        }
 
200
 
 
201
        removed_signal.emit(obj);
 
202
        sp_object_unref(obj);
 
203
    }
 
204
 
 
205
    void _doRemoveSubtree(SPObject *obj) {
 
206
        Record *record=get(obj);
 
207
        if (record) {
 
208
            Siblings &children=record->children;
 
209
            for ( Siblings::iterator iter=children.begin()
 
210
                ; iter != children.end() ; ++iter )
 
211
            {
 
212
                _doRemoveSubtree(*iter);
 
213
            }
 
214
            _doRemove(obj);
 
215
        }
 
216
    }
 
217
 
 
218
    void _release_object(SPObject *obj) {
 
219
        if (get(obj)) {
 
220
            remove(obj, true);
 
221
        }
 
222
    }
 
223
};
 
224
 
 
225
DocumentSubset::DocumentSubset()
 
226
: _relations(new DocumentSubset::Relations())
 
227
{
 
228
}
 
229
 
 
230
void DocumentSubset::Relations::addOne(SPObject *obj) {
 
231
    g_return_if_fail( obj != NULL );
 
232
    g_return_if_fail( get(obj) == NULL );
 
233
 
 
234
    Record &record=_doAdd(obj);
 
235
 
 
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 )
 
240
    {
 
241
        parent_record = get(parent_iter);
 
242
        if (parent_record) {
 
243
            record.parent = parent_iter;
 
244
        }
 
245
    }
 
246
    if (!parent_record) {
 
247
        parent_record = get(NULL);
 
248
        g_assert( parent_record != NULL );
 
249
    }
 
250
 
 
251
    Siblings &children=record.children;
 
252
 
 
253
    /* reparent descendants of obj to obj */
 
254
    parent_record->extractDescendants(
 
255
        std::back_insert_iterator<Siblings>(children),
 
256
        obj
 
257
    );
 
258
    for ( Siblings::iterator iter=children.begin()
 
259
        ; iter != children.end() ; ++iter )
 
260
    {
 
261
        Record *child_record=get(*iter);
 
262
        g_assert( child_record != NULL );
 
263
        child_record->parent = obj;
 
264
    }
 
265
 
 
266
    /* add obj to the child list */
 
267
    parent_record->addChild(obj);
 
268
 
 
269
    _notifyAdded(obj);
 
270
    changed_signal.emit();
 
271
}
 
272
 
 
273
void DocumentSubset::Relations::remove(SPObject *obj, bool subtree) {
 
274
    g_return_if_fail( obj != NULL );
 
275
 
 
276
    Record *record=get(obj);
 
277
    g_return_if_fail( record != NULL );
 
278
 
 
279
    Record *parent_record=get(record->parent);
 
280
    g_assert( parent_record != NULL );
 
281
 
 
282
    unsigned index=parent_record->removeChild(obj);
 
283
 
 
284
    if (subtree) {
 
285
        _doRemoveSubtree(obj);
 
286
    } else {
 
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());
 
292
 
 
293
        for ( Siblings::iterator iter=children.begin()
 
294
            ; iter != children.end() ; iter++ )
 
295
        {
 
296
            Record *child_record=get(*iter);
 
297
            g_assert( child_record != NULL );
 
298
            child_record->parent = record->parent;
 
299
        }
 
300
 
 
301
        /* remove obj's record */
 
302
        _doRemove(obj);
 
303
    }
 
304
    
 
305
    changed_signal.emit();
 
306
}
 
307
 
 
308
void DocumentSubset::Relations::clear() {
 
309
    Record &root=records[NULL];
 
310
 
 
311
    while (!root.children.empty()) {
 
312
        _doRemoveSubtree(root.children.front());
 
313
    }
 
314
 
 
315
    changed_signal.emit();
 
316
}
 
317
 
 
318
void DocumentSubset::Relations::reorder(SPObject *obj) {
 
319
    SPObject::ParentIterator parent=obj;
 
320
 
 
321
    /* find nearest ancestor in the subset */
 
322
    Record *parent_record=NULL;
 
323
    while (!parent_record) {
 
324
        parent_record = get(++parent);
 
325
    }
 
326
 
 
327
    if (get(obj)) {
 
328
        /* move the object if it's in the subset */
 
329
        parent_record->removeChild(obj);
 
330
        parent_record->addChild(obj);
 
331
        changed_signal.emit();
 
332
    } else {
 
333
        /* otherwise, move any top-level descendants */
 
334
        Siblings descendants;
 
335
        parent_record->extractDescendants(
 
336
            std::back_insert_iterator<Siblings>(descendants),
 
337
            obj
 
338
        );
 
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();
 
345
        }
 
346
    }
 
347
}
 
348
 
 
349
void DocumentSubset::_addOne(SPObject *obj) {
 
350
    _relations->addOne(obj);
 
351
}
 
352
 
 
353
void DocumentSubset::_remove(SPObject *obj, bool subtree) {
 
354
    _relations->remove(obj, subtree);
 
355
}
 
356
 
 
357
void DocumentSubset::_clear() {
 
358
    _relations->clear();
 
359
}
 
360
 
 
361
bool DocumentSubset::includes(SPObject *obj) const {
 
362
    return _relations->get(obj);
 
363
}
 
364
 
 
365
SPObject *DocumentSubset::parentOf(SPObject *obj) const {
 
366
    Relations::Record *record=_relations->get(obj);
 
367
    return ( record ? record->parent : NULL );
 
368
}
 
369
 
 
370
unsigned DocumentSubset::childCount(SPObject *obj) const {
 
371
    Relations::Record *record=_relations->get(obj);
 
372
    return ( record ? record->children.size() : 0 );
 
373
}
 
374
 
 
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 );
 
379
}
 
380
 
 
381
SPObject *DocumentSubset::nthChildOf(SPObject *obj, unsigned n) const {
 
382
    Relations::Record *record=_relations->get(obj);
 
383
    return ( record ? record->children[n] : NULL );
 
384
}
 
385
 
 
386
sigc::connection DocumentSubset::connectChanged(sigc::slot<void> slot) const {
 
387
    return _relations->changed_signal.connect(slot);
 
388
}
 
389
 
 
390
sigc::connection
 
391
DocumentSubset::connectAdded(sigc::slot<void, SPObject *> slot) const {
 
392
    return _relations->added_signal.connect(slot);
 
393
}
 
394
 
 
395
sigc::connection
 
396
DocumentSubset::connectRemoved(sigc::slot<void, SPObject *> slot) const {
 
397
    return _relations->removed_signal.connect(slot);
 
398
}
 
399
 
 
400
}
 
401
 
 
402
/*
 
403
  Local Variables:
 
404
  mode:c++
 
405
  c-file-style:"stroustrup"
 
406
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
 
407
  indent-tabs-mode:nil
 
408
  fill-column:99
 
409
  End:
 
410
*/
 
411
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :