1 /** \file
2 * Inkscape::ObjectHierarchy - tracks a hierarchy of active SPObjects
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 #ifndef SEEN_INKSCAPE_OBJECT_HIERARCHY_H
13 #define SEEN_INKSCAPE_OBJECT_HIERARCHY_H
15 #include <exception>
16 #include <list>
17 #include <sigc++/connection.h>
18 #include <sigc++/signal.h>
19 #include <glib/gmessages.h>
21 class SPObject;
23 namespace Inkscape {
25 /**
26 * An Inkscape::ObjectHierarchy is useful for situations where one wishes
27 * to keep a reference to an SPObject, but fall back on one of its ancestors
28 * when that object is removed.
29 *
30 * That cannot be accomplished simply by hooking the "release" signal of the
31 * SPObject, as by the time that signal is emitted, the object's parent
32 * field has already been cleared.
33 *
34 * There are also some subtle refcounting issues to take into account.
35 *
36 * @see SPObject
37 */
39 class ObjectHierarchy {
40 public:
41 ObjectHierarchy(SPObject *top=NULL);
42 ~ObjectHierarchy();
44 bool contains(SPObject *object);
46 sigc::connection connectAdded(const sigc::slot<void, SPObject *> &slot) {
47 return _added_signal.connect(slot);
48 }
49 sigc::connection connectRemoved(const sigc::slot<void, SPObject *> &slot) {
50 return _removed_signal.connect(slot);
51 }
52 sigc::connection connectChanged(const sigc::slot<void, SPObject *, SPObject *> &slot)
53 {
54 return _changed_signal.connect(slot);
55 }
57 void clear();
59 SPObject *top() {
60 return !_hierarchy.empty() ? _hierarchy.back().object : NULL;
61 }
62 void setTop(SPObject *object);
64 SPObject *bottom() {
65 return !_hierarchy.empty() ? _hierarchy.front().object : NULL;
66 }
67 void setBottom(SPObject *object);
69 private:
70 struct Record {
71 Record(SPObject *o, sigc::connection c)
72 : object(o), connection(c) {}
74 SPObject *object;
75 sigc::connection connection;
76 };
78 ObjectHierarchy(ObjectHierarchy const &); // no copy
79 void operator=(ObjectHierarchy const &); // no assign
81 /// @brief adds objects in range [senior, junior) to the top
82 void _addTop(SPObject *senior, SPObject *junior);
83 /// @brief adds one object to the top
84 void _addTop(SPObject *object);
85 /// @brief removes all objects above the limit object
86 void _trimAbove(SPObject *limit);
88 /// @brief adds objects in range (senior, junior] to the bottom
89 void _addBottom(SPObject *senior, SPObject *junior);
90 /// @brief adds one object to the bottom
91 void _addBottom(SPObject *object);
92 /// @brief removes all objects below the limit object
93 void _trimBelow(SPObject *limit);
95 Record _attach(SPObject *object);
96 void _detach(Record &record);
98 void _clear() { _trimBelow(NULL); }
100 void _trim_for_release(SPObject *released);
102 std::list<Record> _hierarchy;
103 sigc::signal<void, SPObject *> _added_signal;
104 sigc::signal<void, SPObject *> _removed_signal;
105 sigc::signal<void, SPObject *, SPObject *> _changed_signal;
106 };
108 }
110 #endif
111 /*
112 Local Variables:
113 mode:c++
114 c-file-style:"stroustrup"
115 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
116 indent-tabs-mode:nil
117 fill-column:99
118 End:
119 */
120 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :