Code

Add signal for notification of object position changes
[inkscape.git] / src / sp-object.h
1 #ifndef __SP_OBJECT_H__
2 #define __SP_OBJECT_H__
4 /** \file
5  * Abstract base class for all nodes
6  *
7  * Authors:
8  *   Lauris Kaplinski <lauris@kaplinski.com>
9  *
10  * Copyright (C) 1999-2002 authors
11  * Copyright (C) 2001-2002 Ximian, Inc.
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 /* SPObject flags */
18 /* Async modification flags */
19 #define SP_OBJECT_MODIFIED_FLAG (1 << 0)
20 #define SP_OBJECT_CHILD_MODIFIED_FLAG (1 << 1)
21 #define SP_OBJECT_PARENT_MODIFIED_FLAG (1 << 2)
22 #define SP_OBJECT_STYLE_MODIFIED_FLAG (1 << 3)
23 #define SP_OBJECT_VIEWPORT_MODIFIED_FLAG (1 << 4)
24 #define SP_OBJECT_USER_MODIFIED_FLAG_A (1 << 5)
25 #define SP_OBJECT_USER_MODIFIED_FLAG_B (1 << 6)
26 #define SP_OBJECT_USER_MODIFIED_FLAG_C (1 << 7)
28 /* Conveneience */
29 #define SP_OBJECT_FLAGS_ALL 0xff
31 /* Flags that mark object as modified */
32 /* Object, Child, Style, Viewport, User */
33 #define SP_OBJECT_MODIFIED_STATE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_PARENT_MODIFIED_FLAG))
35 /* Flags that will propagate downstreams */
36 /* Parent, Style, Viewport, User */
37 #define SP_OBJECT_MODIFIED_CASCADE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))
39 /* Generic */
40 #define SP_OBJECT_IS_CLONED(o) (((SPObject *) (o))->cloned)
42 /* Write flags */
43 #define SP_OBJECT_WRITE_BUILD (1 << 0)
44 #define SP_OBJECT_WRITE_EXT (1 << 1)
45 #define SP_OBJECT_WRITE_ALL (1 << 2)
47 /* Convenience stuff */
48 #define SP_OBJECT_ID(o) (((SPObject *) (o))->id)
49 #define SP_OBJECT_REPR(o) (((SPObject *) (o))->repr)
50 #define SP_OBJECT_DOCUMENT(o) (((SPObject *) (o))->document)
51 #define SP_OBJECT_PARENT(o) (((SPObject *) (o))->parent)
52 #define SP_OBJECT_NEXT(o) (((SPObject *) (o))->next)
53 #define SP_OBJECT_PREV(o) (sp_object_prev((SPObject *) (o)))
54 #define SP_OBJECT_HREFCOUNT(o) (((SPObject *) (o))->hrefcount)
55 #define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style)
56 #define SP_OBJECT_TITLE(o) sp_object_title_get((SPObject *) (o))
57 #define SP_OBJECT_DESCRIPTION(o) sp_object_description_get((SPObject *) (o))
60 #include <glib-object.h>
61 #include <sigc++/connection.h>
62 #include <sigc++/functors/slot.h>
63 #include <sigc++/signal.h>
65 #include "forward.h"
66 #include "version.h"
67 #include "util/forward-pointer-iterator.h"
69 namespace Inkscape {
70 namespace XML {
71 class Node;
72 }
73 }
76 typedef enum {
77     SP_NO_EXCEPTION,
78     SP_INDEX_SIZE_ERR,
79     SP_DOMSTRING_SIZE_ERR,
80     SP_HIERARCHY_REQUEST_ERR,
81     SP_WRONG_DOCUMENT_ERR,
82     SP_INVALID_CHARACTER_ERR,
83     SP_NO_DATA_ALLOWED_ERR,
84     SP_NO_MODIFICATION_ALLOWED_ERR,
85     SP_NOT_FOUND_ERR,
86     SP_NOT_SUPPORTED_ERR,
87     SP_INUSE_ATTRIBUTE_ERR,
88     SP_INVALID_STATE_ERR,
89     SP_SYNTAX_ERR,
90     SP_INVALID_MODIFICATION_ERR,
91     SP_NAMESPACE_ERR,
92     SP_INVALID_ACCESS_ERR
93 } SPExceptionType;
95 class SPException;
97 /// An attempt to implement exceptions, unused?
98 struct SPException {
99     SPExceptionType code;
100 };
102 #define SP_EXCEPTION_INIT(ex) {(ex)->code = SP_NO_EXCEPTION;}
103 #define SP_EXCEPTION_IS_OK(ex) (!(ex) || ((ex)->code == SP_NO_EXCEPTION))
105 class SPCtx;
107 /// Unused
108 struct SPCtx {
109     unsigned int flags;
110 };
112 enum {
113     SP_XML_SPACE_DEFAULT,
114     SP_XML_SPACE_PRESERVE
115 };
117 class SPIXmlSpace;
119 /// Internal class consisting of two bits.
120 struct SPIXmlSpace {
121     guint set : 1;
122     guint value : 1;
123 };
125 class SPObject;
127 /*
128  * Refcounting
129  *
130  * Owner is here for debug reasons, you can set it to NULL safely
131  * Ref should return object, NULL is error, unref return always NULL
132  */
134 SPObject *sp_object_ref(SPObject *object, SPObject *owner=NULL);
135 SPObject *sp_object_unref(SPObject *object, SPObject *owner=NULL);
137 SPObject *sp_object_href(SPObject *object, gpointer owner);
138 SPObject *sp_object_hunref(SPObject *object, gpointer owner);
140 /// A refcounting tree node object.
141 struct SPObject : public GObject {
142     enum CollectionPolicy {
143         COLLECT_WITH_PARENT,
144         ALWAYS_COLLECT
145     };
147     unsigned int cloned : 1;
148     unsigned int uflags : 8;
149     unsigned int mflags : 8;
150     SPIXmlSpace xml_space;
151     unsigned int hrefcount; /* number of xlink:href references */
152     unsigned int _total_hrefcount; /* our hrefcount + total descendants */
153     SPDocument *document; /* Document we are part of */
154     SPObject *parent; /* Our parent (only one allowed) */
155     SPObject *children; /* Our children */
156     SPObject *_last_child; /* Remembered last child */
157     SPObject *next; /* Next object in linked list */
158     Inkscape::XML::Node *repr; /* Our xml representation */
159     gchar *id; /* Our very own unique id */
161     /**
162      * Represents the style properties, whether from presentation attributes, the <tt>style</tt>
163      * attribute, or inherited.
164      *
165      * sp_object_private_set doesn't handle SP_ATTR_STYLE or any presentation attributes at the
166      * time of writing, so this is probably NULL for all SPObject's that aren't an SPItem.
167      *
168      * However, this gives rise to the bugs mentioned in sp_object_get_style_property.
169      * Note that some non-SPItem SPObject's, such as SPStop, do need styling information,
170      * and need to inherit properties even through other non-SPItem parents like \<defs\>.
171      */
172     SPStyle *style;
174     /// Switch containing next() method.
175     struct ParentIteratorStrategy {
176         static SPObject const *next(SPObject const *object) {
177             return object->parent;
178         }
179     };
180     /// Switch containing next() method.
181     struct SiblingIteratorStrategy {
182         static SPObject const *next(SPObject const *object) {
183             return object->next;
184         }
185     };
187     typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator;
188     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator;
189     typedef Inkscape::Util::ForwardPointerIterator<SPObject, SiblingIteratorStrategy> SiblingIterator;
190     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, SiblingIteratorStrategy> ConstSiblingIterator;
192     bool isSiblingOf(SPObject const *object) const {
193         g_return_val_if_fail(object != NULL, false);
194         return this->parent && this->parent == object->parent;
195     }
196     bool isAncestorOf(SPObject const *object) const;
198     SPObject const *nearestCommonAncestor(SPObject const *object) const;
199     /* A non-const version can be similarly constructed if you want one.
200      * (Don't just cast away the constness, which would be ill-formed.) */
202     bool hasChildren() const { return ( children != NULL ); }
204     SPObject *firstChild() { return children; }
205     SPObject const *firstChild() const { return children; }
206     SPObject *lastChild() { return _last_child; }
207     SPObject const *lastChild() const { return _last_child; }
209     SPObject *appendChildRepr(Inkscape::XML::Node *repr);
211     /** @brief Gets the author-visible label for this object. */ 
212     gchar const *label() const;
213     /** @brief Returns a default label for this object. */ 
214     gchar const *defaultLabel() const;
215     /** @brief Sets the author-visible label for this object.
216      *
217      * Sets the author-visible label for the object.
218      *
219      * @param label the new label
220      */
221     void setLabel(gchar const *label);
223     /** Retrieves the title of this object */
224     gchar const *title() const { return NULL; /* TODO */ }
225     /** Sets the title of this object */
226     void setTitle(gchar const *title) { /* TODO */ }
228     /** Retrieves the description of this object */
229     gchar const *desc() const { return NULL; /* TODO */ }
230     /** Sets the description of this object */
231     void setDesc(gchar const *desc) { /* TODO */ }
233     /** @brief Set the policy under which this object will be
234      *         orphan-collected.
235      *
236      * Orphan-collection is the process of deleting all objects which no longer have
237      * hyper-references pointing to them.  The policy determines when this happens.  Many objects
238      * should not be deleted simply because they are no longer referred to; other objects (like
239      * "intermediate" gradients) are more or less throw-away and should always be collected when no
240      * longer in use.
241      *
242      * Along these lines, there are currently two orphan-collection policies:
243      *
244      *  COLLECT_WITH_PARENT - don't worry about the object's hrefcount;
245      *                        if its parent is collected, this object
246      *                        will be too
247      *
248      *  COLLECT_ALWAYS - always collect the object as soon as its
249      *                   hrefcount reaches zero
250      *
251      * @returns the current collection policy in effect for this object
252      */
253     CollectionPolicy collectionPolicy() const { return _collection_policy; }
255     /** @brief Sets the orphan-collection policy in effect for this object.
256      *
257      * @see SPObject::collectionPolicy
258      *
259      * @param policy the new policy to adopt
260      */
261     void setCollectionPolicy(CollectionPolicy policy) {
262         _collection_policy = policy;
263     }
265     /** @brief Requests a later automatic call to collectOrphan().
266      *
267      * This method requests that collectOrphan() be called during the document update cycle,
268      * deleting the object if it is no longer used.
269      *
270      * If the current collection policy is COLLECT_WITH_PARENT, this function has no effect.
271      *
272      * @see SPObject::collectOrphan
273      */
274     void requestOrphanCollection();
276     /** @brief Unconditionally delete the object if it is not referenced.
277      *
278      * Unconditionally delete the object if there are no outstanding hyper-references to it.
279      * Observers are not notified of the object's deletion (at the SPObject level; XML tree
280      * notifications still fire).
281      *
282      * @see SPObject::deleteObject
283      */
284     void collectOrphan() {
285         if ( _total_hrefcount == 0 ) {
286             deleteObject(false);
287         }
288     }
290     /** @brief Deletes an object.
291      *
292      * Detaches the object's repr, and optionally sends notification that the object has been
293      * deleted.
294      *
295      * @param propagate notify observers that the object has been deleted?
296      *
297      * @param propagate_descendants notify observers of children that they have been deleted?
298      */
299     void deleteObject(bool propagate, bool propagate_descendants);
301     /** @brief Deletes on object.
302      *
303      * @param propagate Notify observers of this object and its children that they have been
304      *                  deleted?
305      */
306     void deleteObject(bool propagate=true) {
307         deleteObject(propagate, propagate);
308     }
310     /** @brief Connects a slot to be called when an object is deleted.
311      *
312      * This connects a slot to an object's internal delete signal, which is invoked when the object
313      * is deleted
314      *
315      * The signal is mainly useful for e.g. knowing when to break hrefs or dissociate clones.
316      *
317      * @param slot the slot to connect
318      *
319      * @see SPObject::deleteObject
320      */
321     sigc::connection connectDelete(sigc::slot<void, SPObject *> slot) {
322         return _delete_signal.connect(slot);
323     }
325     sigc::connection connectPositionChanged(sigc::slot<void, SPObject *> slot) {
326         return _position_changed_signal.connect(slot);
327     }
329     /** @brief Returns the object which supercedes this one (if any).
330      *
331      * This is mainly useful for ensuring we can correctly perform a series of moves or deletes,
332      * even if the objects in question have been replaced in the middle of the sequence.
333      */
334     SPObject *successor() { return _successor; }
336     /** @brief Indicates that another object supercedes this one. */
337     void setSuccessor(SPObject *successor) {
338         g_assert(successor != NULL);
339         g_assert(_successor == NULL);
340         g_assert(successor->_successor == NULL);
341         sp_object_ref(successor, NULL);
342         _successor = successor;
343     }
345     /* modifications; all three sets of methods should probably ultimately be protected, as they
346      * are not really part of its public interface.  However, other parts of the code to
347      * occasionally use them at present. */
349     /* the no-argument version of updateRepr() is intended to be a bit more public, however -- it
350      * essentially just flushes any changes back to the backing store (the repr layer); maybe it
351      * should be called something else and made public at that point. */
353     /** @brief Updates the object's repr based on the object's state.
354      *
355      *  This method updates the the repr attached to the object to reflect the object's current
356      *  state; see the two-argument version for details.
357      *
358      *  @param flags object write flags that apply to this update
359      *
360      *  @return the updated repr
361      */
362     Inkscape::XML::Node *updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT);
364     /** @brief Updates the given repr based on the object's state.
365      *
366      *  This method updates the given repr to reflect the object's current state.  There are
367      *  several flags that affect this:
368      *
369      *   SP_OBJECT_WRITE_BUILD - create new reprs
370      *
371      *   SP_OBJECT_WRITE_EXT   - write elements and attributes
372      *                           which are not part of pure SVG
373      *                           (i.e. the Inkscape and Sodipodi
374      *                           namespaces)
375      *
376      *   SP_OBJECT_WRITE_ALL   - create all nodes and attributes,
377      *                           even those which might be redundant
378      *
379      *  @param repr the repr to update
380      *  @param flags object write flags that apply to this update
381      *
382      *  @return the updated repr
383      */
384     Inkscape::XML::Node *updateRepr(Inkscape::XML::Node *repr, unsigned int flags);
386     /** @brief Queues an deferred update of this object's display.
387      *
388      *  This method sets flags to indicate updates to be performed later, during the idle loop.
389      *
390      *  There are several flags permitted here:
391      *
392      *   SP_OBJECT_MODIFIED_FLAG - the object has been modified
393      *
394      *   SP_OBJECT_CHILD_MODIFIED_FLAG - a child of the object has been
395      *                                   modified
396      *
397      *   SP_OBJECT_STYLE_MODIFIED_FLAG - the object's style has been
398      *                                   modified
399      *
400      *  There are also some subclass-specific modified flags which are hardly ever used.
401      *
402      *  One of either MODIFIED or CHILD_MODIFIED is required.
403      *
404      *  @param flags flags indicating what to update
405      */
406     void requestDisplayUpdate(unsigned int flags);
408     /** @brief Updates the object's display immediately
409      *
410      *  This method is called during the idle loop by SPDocument in order to update the object's
411      *  display.
412      *
413      *  One additional flag is legal here:
414      *
415      *   SP_OBJECT_PARENT_MODIFIED_FLAG - the parent has been
416      *                                    modified
417      *
418      *  @param ctx an SPCtx which accumulates various state
419      *             during the recursive update -- beware! some
420      *             subclasses try to cast this to an SPItemCtx *
421      *
422      *  @param flags flags indicating what to update (in addition
423      *               to any already set flags)
424      */
425     void updateDisplay(SPCtx *ctx, unsigned int flags);
427     /** @brief Requests that a modification notification signal
428      *         be emitted later (e.g. during the idle loop)
429      *
430      *  @param flags flags indicating what has been modified
431      */
432     void requestModified(unsigned int flags);
434     /** @brief Emits a modification notification signal
435      *
436      *  @param flags indicating what has been modified
437      */
438     void emitModified(unsigned int flags);
440     void _sendDeleteSignalRecursive();
441     void _updateTotalHRefCount(int increment);
443     void _requireSVGVersion(unsigned major, unsigned minor) {
444         _requireSVGVersion(Inkscape::Version(major, minor));
445     }
446     void _requireSVGVersion(Inkscape::Version version);
448     sigc::signal<void, SPObject *> _delete_signal;
449     sigc::signal<void, SPObject *> _position_changed_signal;
450     SPObject *_successor;
451     CollectionPolicy _collection_policy;
452     gchar *_label;
453     mutable gchar *_default_label;
454 };
456 /// The SPObject vtable.
457 struct SPObjectClass {
458     GObjectClass parent_class;
460     void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr);
461     void (* release) (SPObject *object);
463     /* Virtual handlers of repr signals */
464     void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
465     void (* remove_child) (SPObject *object, Inkscape::XML::Node *child);
467     void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr);
469     void (* set) (SPObject *object, unsigned int key, gchar const *value);
471     void (* read_content) (SPObject *object);
473     /* Update handler */
474     void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags);
475     /* Modification handler */
476     void (* modified) (SPObject *object, unsigned int flags);
478     Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Node *repr, unsigned int flags);
479 };
482 /*
483  * Attaching/detaching
484  */
486 void sp_object_attach(SPObject *parent, SPObject *object, SPObject *prev);
487 void sp_object_reorder(SPObject *object, SPObject *prev);
488 void sp_object_detach(SPObject *parent, SPObject *object);
490 inline SPObject *sp_object_first_child(SPObject *parent) {
491     return parent->firstChild();
493 SPObject *sp_object_get_child_by_repr(SPObject *object, Inkscape::XML::Node *repr);
495 void sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned);
496 void sp_object_invoke_release(SPObject *object);
498 void sp_object_set(SPObject *object, unsigned int key, gchar const *value);
500 void sp_object_read_attr(SPObject *object, gchar const *key);
502 /*
503  * Get and set descriptive parameters.
504  *
505  * These are inefficent, so they are not intended to be used interactively.
506  */
508 gchar const *sp_object_title_get(SPObject *object);
509 gchar const *sp_object_description_get(SPObject *object);
510 unsigned int sp_object_title_set(SPObject *object, gchar const *title);
511 unsigned int sp_object_description_set(SPObject *object, gchar const *desc);
513 /* Public */
515 gchar const *sp_object_tagName_get(SPObject const *object, SPException *ex);
516 gchar const *sp_object_getAttribute(SPObject const *object, gchar const *key, SPException *ex);
517 void sp_object_setAttribute(SPObject *object, gchar const *key, gchar const *value, SPException *ex);
518 void sp_object_removeAttribute(SPObject *object, gchar const *key, SPException *ex);
520 /* Style */
522 gchar const *sp_object_get_style_property(SPObject const *object,
523                                           gchar const *key, gchar const *def);
525 Inkscape::Version sp_object_get_sodipodi_version(SPObject *object);
527 int sp_object_compare_position(SPObject const *first, SPObject const *second);
529 SPObject *sp_object_prev(SPObject *child);
532 #endif
535 /*
536   Local Variables:
537   mode:c++
538   c-file-style:"stroustrup"
539   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
540   indent-tabs-mode:nil
541   fill-column:99
542   End:
543 */
544 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :