Code

22a15a0a4b272a60ac4ce1b6ad2bd31ebd832156
[inkscape.git] / src / sp-object.h
1 #ifndef SP_OBJECT_H_SEEN
2 #define SP_OBJECT_H_SEEN
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)
58 #include <glib-object.h>
59 #include <sigc++/connection.h>
60 #include <sigc++/functors/slot.h>
61 #include <sigc++/signal.h>
63 #include "forward.h"
64 #include "version.h"
65 #include "util/forward-pointer-iterator.h"
67 namespace Inkscape {
68 namespace XML {
69 class Node;
70 class Document;
71 }
72 }
75 typedef enum {
76     SP_NO_EXCEPTION,
77     SP_INDEX_SIZE_ERR,
78     SP_DOMSTRING_SIZE_ERR,
79     SP_HIERARCHY_REQUEST_ERR,
80     SP_WRONG_DOCUMENT_ERR,
81     SP_INVALID_CHARACTER_ERR,
82     SP_NO_DATA_ALLOWED_ERR,
83     SP_NO_MODIFICATION_ALLOWED_ERR,
84     SP_NOT_FOUND_ERR,
85     SP_NOT_SUPPORTED_ERR,
86     SP_INUSE_ATTRIBUTE_ERR,
87     SP_INVALID_STATE_ERR,
88     SP_SYNTAX_ERR,
89     SP_INVALID_MODIFICATION_ERR,
90     SP_NAMESPACE_ERR,
91     SP_INVALID_ACCESS_ERR
92 } SPExceptionType;
94 class SPException;
96 /// An attempt to implement exceptions, unused?
97 struct SPException {
98     SPExceptionType code;
99 };
101 #define SP_EXCEPTION_INIT(ex) {(ex)->code = SP_NO_EXCEPTION;}
102 #define SP_EXCEPTION_IS_OK(ex) (!(ex) || ((ex)->code == SP_NO_EXCEPTION))
104 class SPCtx;
106 /// Unused
107 struct SPCtx {
108     unsigned int flags;
109 };
111 enum {
112     SP_XML_SPACE_DEFAULT,
113     SP_XML_SPACE_PRESERVE
114 };
116 class SPIXmlSpace;
118 /// Internal class consisting of two bits.
119 struct SPIXmlSpace {
120     guint set : 1;
121     guint value : 1;
122 };
124 class SPObject;
126 /*
127  * Refcounting
128  *
129  * Owner is here for debug reasons, you can set it to NULL safely
130  * Ref should return object, NULL is error, unref return always NULL
131  */
133 SPObject *sp_object_ref(SPObject *object, SPObject *owner=NULL);
134 SPObject *sp_object_unref(SPObject *object, SPObject *owner=NULL);
136 SPObject *sp_object_href(SPObject *object, gpointer owner);
137 SPObject *sp_object_hunref(SPObject *object, gpointer owner);
139 /// A refcounting tree node object.
140 struct SPObject : public GObject {
141     enum CollectionPolicy {
142         COLLECT_WITH_PARENT,
143         ALWAYS_COLLECT
144     };
146     unsigned int cloned : 1;
147     unsigned int uflags : 8;
148     unsigned int mflags : 8;
149     SPIXmlSpace xml_space;
150     unsigned int hrefcount; /* number of xlink:href references */
151     unsigned int _total_hrefcount; /* our hrefcount + total descendants */
152     SPDocument *document; /* Document we are part of */
153     SPObject *parent; /* Our parent (only one allowed) */
154     SPObject *children; /* Our children */
155     SPObject *_last_child; /* Remembered last child */
156     SPObject *next; /* Next object in linked list */
157     Inkscape::XML::Node *repr; /* Our xml representation */
159 private:
160     gchar *id; /* Our very own unique id */
161 public:
163     /**
164      * Returns the objects current ID string.
165      */
166     gchar const* getId() const;
168     /** @brief cleans up an SPObject, releasing its references and
169      *         requesting that references to it be released
170      */
171     void releaseReferences();
173     /** @brief connects to the release request signal
174      *
175      *  @param slot the slot to connect
176      *
177      *  @returns the sigc::connection formed
178      */
179     sigc::connection connectRelease(sigc::slot<void, SPObject *> slot) {
180         return _release_signal.connect(slot);
181     }
183     /**
184      * Represents the style properties, whether from presentation attributes, the <tt>style</tt>
185      * attribute, or inherited.
186      *
187      * sp_object_private_set doesn't handle SP_ATTR_STYLE or any presentation attributes at the
188      * time of writing, so this is probably NULL for all SPObject's that aren't an SPItem.
189      *
190      * However, this gives rise to the bugs mentioned in sp_object_get_style_property.
191      * Note that some non-SPItem SPObject's, such as SPStop, do need styling information,
192      * and need to inherit properties even through other non-SPItem parents like \<defs\>.
193      */
194     SPStyle *style;
196     /// Switch containing next() method.
197     struct ParentIteratorStrategy {
198         static SPObject const *next(SPObject const *object) {
199             return object->parent;
200         }
201     };
202     /// Switch containing next() method.
203     struct SiblingIteratorStrategy {
204         static SPObject const *next(SPObject const *object) {
205             return object->next;
206         }
207     };
209     typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator;
210     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator;
211     typedef Inkscape::Util::ForwardPointerIterator<SPObject, SiblingIteratorStrategy> SiblingIterator;
212     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, SiblingIteratorStrategy> ConstSiblingIterator;
214     bool isSiblingOf(SPObject const *object) const {
215         g_return_val_if_fail(object != NULL, false);
216         return this->parent && this->parent == object->parent;
217     }
218     bool isAncestorOf(SPObject const *object) const;
220     SPObject const *nearestCommonAncestor(SPObject const *object) const;
221     /* A non-const version can be similarly constructed if you want one.
222      * (Don't just cast away the constness, which would be ill-formed.) */
224     bool hasChildren() const { return ( children != NULL ); }
226     SPObject *firstChild() { return children; }
227     SPObject const *firstChild() const { return children; }
228     SPObject *lastChild() { return _last_child; }
229     SPObject const *lastChild() const { return _last_child; }
231     enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow };
232     /** @brief Retrieves children as a GSList */
233     GSList *childList(bool add_ref, Action action = ActionGeneral);
235     SPObject *appendChildRepr(Inkscape::XML::Node *repr);
237     /** @brief Gets the author-visible label for this object. */
238     gchar const *label() const;
239     /** @brief Returns a default label for this object. */
240     gchar const *defaultLabel() const;
241     /** @brief Sets the author-visible label for this object.
242      *
243      * Sets the author-visible label for the object.
244      *
245      * @param label the new label
246      */
247     void setLabel(gchar const *label);
249     /** Retrieves the title of this object */
250     gchar *title() const;
251     /** Sets the title of this object */
252     bool setTitle(gchar const *title, bool verbatim=false);
254     /** Retrieves the description of this object */
255     gchar *desc() const;
256     /** Sets the description of this object */
257     bool setDesc(gchar const *desc, bool verbatim=false);
259     /** @brief Set the policy under which this object will be
260      *         orphan-collected.
261      *
262      * Orphan-collection is the process of deleting all objects which no longer have
263      * hyper-references pointing to them.  The policy determines when this happens.  Many objects
264      * should not be deleted simply because they are no longer referred to; other objects (like
265      * "intermediate" gradients) are more or less throw-away and should always be collected when no
266      * longer in use.
267      *
268      * Along these lines, there are currently two orphan-collection policies:
269      *
270      *  COLLECT_WITH_PARENT - don't worry about the object's hrefcount;
271      *                        if its parent is collected, this object
272      *                        will be too
273      *
274      *  COLLECT_ALWAYS - always collect the object as soon as its
275      *                   hrefcount reaches zero
276      *
277      * @returns the current collection policy in effect for this object
278      */
279     CollectionPolicy collectionPolicy() const { return _collection_policy; }
281     /** @brief Sets the orphan-collection policy in effect for this object.
282      *
283      * @see SPObject::collectionPolicy
284      *
285      * @param policy the new policy to adopt
286      */
287     void setCollectionPolicy(CollectionPolicy policy) {
288         _collection_policy = policy;
289     }
291     /** @brief Requests a later automatic call to collectOrphan().
292      *
293      * This method requests that collectOrphan() be called during the document update cycle,
294      * deleting the object if it is no longer used.
295      *
296      * If the current collection policy is COLLECT_WITH_PARENT, this function has no effect.
297      *
298      * @see SPObject::collectOrphan
299      */
300     void requestOrphanCollection();
302     /** @brief Unconditionally delete the object if it is not referenced.
303      *
304      * Unconditionally delete the object if there are no outstanding hyper-references to it.
305      * Observers are not notified of the object's deletion (at the SPObject level; XML tree
306      * notifications still fire).
307      *
308      * @see SPObject::deleteObject
309      */
310     void collectOrphan() {
311         if ( _total_hrefcount == 0 ) {
312             deleteObject(false);
313         }
314     }
316     /** @brief Check if object is referenced by any other object.
317      */
318     bool isReferenced() { return ( _total_hrefcount > 0 ); }
320     /** @brief Deletes an object.
321      *
322      * Detaches the object's repr, and optionally sends notification that the object has been
323      * deleted.
324      *
325      * @param propagate notify observers that the object has been deleted?
326      *
327      * @param propagate_descendants notify observers of children that they have been deleted?
328      */
329     void deleteObject(bool propagate, bool propagate_descendants);
331     /** @brief Deletes on object.
332      *
333      * @param propagate Notify observers of this object and its children that they have been
334      *                  deleted?
335      */
336     void deleteObject(bool propagate=true) {
337         deleteObject(propagate, propagate);
338     }
340     /** @brief Connects a slot to be called when an object is deleted.
341      *
342      * This connects a slot to an object's internal delete signal, which is invoked when the object
343      * is deleted
344      *
345      * The signal is mainly useful for e.g. knowing when to break hrefs or dissociate clones.
346      *
347      * @param slot the slot to connect
348      *
349      * @see SPObject::deleteObject
350      */
351     sigc::connection connectDelete(sigc::slot<void, SPObject *> slot) {
352         return _delete_signal.connect(slot);
353     }
355     sigc::connection connectPositionChanged(sigc::slot<void, SPObject *> slot) {
356         return _position_changed_signal.connect(slot);
357     }
359     /** @brief Returns the object which supercedes this one (if any).
360      *
361      * This is mainly useful for ensuring we can correctly perform a series of moves or deletes,
362      * even if the objects in question have been replaced in the middle of the sequence.
363      */
364     SPObject *successor() { return _successor; }
366     /** @brief Indicates that another object supercedes this one. */
367     void setSuccessor(SPObject *successor) {
368         g_assert(successor != NULL);
369         g_assert(_successor == NULL);
370         g_assert(successor->_successor == NULL);
371         sp_object_ref(successor, NULL);
372         _successor = successor;
373     }
375     /* modifications; all three sets of methods should probably ultimately be protected, as they
376      * are not really part of its public interface.  However, other parts of the code to
377      * occasionally use them at present. */
379     /* the no-argument version of updateRepr() is intended to be a bit more public, however -- it
380      * essentially just flushes any changes back to the backing store (the repr layer); maybe it
381      * should be called something else and made public at that point. */
383     /** @brief Updates the object's repr based on the object's state.
384      *
385      *  This method updates the the repr attached to the object to reflect the object's current
386      *  state; see the three-argument version for details.
387      *
388      *  @param flags object write flags that apply to this update
389      *
390      *  @return the updated repr
391      */
392     Inkscape::XML::Node *updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT);
394     /** @brief Updates the given repr based on the object's state.
395      *
396      *  This method updates the given repr to reflect the object's current state.  There are
397      *  several flags that affect this:
398      *
399      *   SP_OBJECT_WRITE_BUILD - create new reprs
400      *
401      *   SP_OBJECT_WRITE_EXT   - write elements and attributes
402      *                           which are not part of pure SVG
403      *                           (i.e. the Inkscape and Sodipodi
404      *                           namespaces)
405      *
406      *   SP_OBJECT_WRITE_ALL   - create all nodes and attributes,
407      *                           even those which might be redundant
408      *
409      *  @param repr the repr to update
410      *  @param flags object write flags that apply to this update
411      *
412      *  @return the updated repr
413      */
414     Inkscape::XML::Node *updateRepr(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags);
416     /** @brief Queues an deferred update of this object's display.
417      *
418      *  This method sets flags to indicate updates to be performed later, during the idle loop.
419      *
420      *  There are several flags permitted here:
421      *
422      *   SP_OBJECT_MODIFIED_FLAG - the object has been modified
423      *
424      *   SP_OBJECT_CHILD_MODIFIED_FLAG - a child of the object has been
425      *                                   modified
426      *
427      *   SP_OBJECT_STYLE_MODIFIED_FLAG - the object's style has been
428      *                                   modified
429      *
430      *  There are also some subclass-specific modified flags which are hardly ever used.
431      *
432      *  One of either MODIFIED or CHILD_MODIFIED is required.
433      *
434      *  @param flags flags indicating what to update
435      */
436     void requestDisplayUpdate(unsigned int flags);
438     /** @brief Updates the object's display immediately
439      *
440      *  This method is called during the idle loop by SPDocument in order to update the object's
441      *  display.
442      *
443      *  One additional flag is legal here:
444      *
445      *   SP_OBJECT_PARENT_MODIFIED_FLAG - the parent has been
446      *                                    modified
447      *
448      *  @param ctx an SPCtx which accumulates various state
449      *             during the recursive update -- beware! some
450      *             subclasses try to cast this to an SPItemCtx *
451      *
452      *  @param flags flags indicating what to update (in addition
453      *               to any already set flags)
454      */
455     void updateDisplay(SPCtx *ctx, unsigned int flags);
457     /** @brief Requests that a modification notification signal
458      *         be emitted later (e.g. during the idle loop)
459      *
460      *  @param flags flags indicating what has been modified
461      */
462     void requestModified(unsigned int flags);
464     /** @brief Emits a modification notification signal
465      *
466      *  @param flags indicating what has been modified
467      */
468     void emitModified(unsigned int flags);
470     /** @brief Connects to the modification notification signal
471      *
472      *  @param slot the slot to connect
473      *
474      *  @returns the connection formed thereby
475      */
476     sigc::connection connectModified(
477       sigc::slot<void, SPObject *, unsigned int> slot
478     ) {
479         return _modified_signal.connect(slot);
480     }
482     void _sendDeleteSignalRecursive();
483     void _updateTotalHRefCount(int increment);
485     void _requireSVGVersion(unsigned major, unsigned minor) {
486         _requireSVGVersion(Inkscape::Version(major, minor));
487     }
488     void _requireSVGVersion(Inkscape::Version version);
490     sigc::signal<void, SPObject *> _release_signal;
491     sigc::signal<void, SPObject *> _delete_signal;
492     sigc::signal<void, SPObject *> _position_changed_signal;
493     sigc::signal<void, SPObject *, unsigned int> _modified_signal;
494     SPObject *_successor;
495     CollectionPolicy _collection_policy;
496     gchar *_label;
497     mutable gchar *_default_label;
499 private:
500     // Private member functions used in the definitions of setTitle(),
501     // setDesc(), title() and desc().
502     bool setTitleOrDesc(gchar const *value, gchar const *svg_tagname, bool verbatim);
503     gchar * getTitleOrDesc(gchar const *svg_tagname) const;
504     SPObject * findFirstChild(gchar const *tagname) const;
505     GString * textualContent() const;
507     friend class SPObjectImpl;
508 };
510 /// The SPObject vtable.
511 struct SPObjectClass {
512     GObjectClass parent_class;
514     void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr);
515     void (* release) (SPObject *object);
517     /* Virtual handlers of repr signals */
518     void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
519     void (* remove_child) (SPObject *object, Inkscape::XML::Node *child);
521     void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr);
523     void (* set) (SPObject *object, unsigned int key, gchar const *value);
525     void (* read_content) (SPObject *object);
527     /* Update handler */
528     void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags);
529     /* Modification handler */
530     void (* modified) (SPObject *object, unsigned int flags);
532     Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags);
533 };
536 /*
537  * Attaching/detaching
538  */
540 void sp_object_attach(SPObject *parent, SPObject *object, SPObject *prev);
541 void sp_object_reorder(SPObject *object, SPObject *prev);
542 void sp_object_detach(SPObject *parent, SPObject *object);
544 inline SPObject *sp_object_first_child(SPObject *parent) {
545     return parent->firstChild();
547 SPObject *sp_object_get_child_by_repr(SPObject *object, Inkscape::XML::Node *repr);
549 void sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned);
551 void sp_object_set(SPObject *object, unsigned int key, gchar const *value);
553 void sp_object_read_attr(SPObject *object, gchar const *key);
555 /* Public */
557 gchar const *sp_object_tagName_get(SPObject const *object, SPException *ex);
558 gchar const *sp_object_getAttribute(SPObject const *object, gchar const *key, SPException *ex);
559 void sp_object_setAttribute(SPObject *object, gchar const *key, gchar const *value, SPException *ex);
560 void sp_object_removeAttribute(SPObject *object, gchar const *key, SPException *ex);
562 /* Style */
564 gchar const *sp_object_get_style_property(SPObject const *object,
565                                           gchar const *key, gchar const *def);
567 int sp_object_compare_position(SPObject const *first, SPObject const *second);
569 SPObject *sp_object_prev(SPObject *child);
572 #endif // SP_OBJECT_H_SEEN
575 /*
576   Local Variables:
577   mode:c++
578   c-file-style:"stroustrup"
579   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
580   indent-tabs-mode:nil
581   fill-column:99
582   End:
583 */
584 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :