Code

Add a warning to sp-object.h to not use some of the new methods
[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  *   Jon A. Cruz <jon@joncruz.org>
10  *   Abhishek Sharma
11  *
12  * Copyright (C) 1999-2002 authors
13  * Copyright (C) 2001-2002 Ximian, Inc.
14  *
15  * Released under GNU GPL, read the file 'COPYING' for more information
16  */
18 /* SPObject flags */
20 class SPObject;
21 class SPObjectClass;
23 #define SP_TYPE_OBJECT (SPObject::sp_object_get_type ())
24 #define SP_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_OBJECT, SPObject))
25 #define SP_OBJECT_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST((clazz), SP_TYPE_OBJECT, SPObjectClass))
26 #define SP_IS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_OBJECT))
28 /* Async modification flags */
29 #define SP_OBJECT_MODIFIED_FLAG (1 << 0)
30 #define SP_OBJECT_CHILD_MODIFIED_FLAG (1 << 1)
31 #define SP_OBJECT_PARENT_MODIFIED_FLAG (1 << 2)
32 #define SP_OBJECT_STYLE_MODIFIED_FLAG (1 << 3)
33 #define SP_OBJECT_VIEWPORT_MODIFIED_FLAG (1 << 4)
34 #define SP_OBJECT_USER_MODIFIED_FLAG_A (1 << 5)
35 #define SP_OBJECT_USER_MODIFIED_FLAG_B (1 << 6)
36 #define SP_OBJECT_USER_MODIFIED_FLAG_C (1 << 7)
38 /* Conveneience */
39 #define SP_OBJECT_FLAGS_ALL 0xff
41 /* Flags that mark object as modified */
42 /* Object, Child, Style, Viewport, User */
43 #define SP_OBJECT_MODIFIED_STATE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_PARENT_MODIFIED_FLAG))
45 /* Flags that will propagate downstreams */
46 /* Parent, Style, Viewport, User */
47 #define SP_OBJECT_MODIFIED_CASCADE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))
49 /* Generic */
50 #define SP_OBJECT_IS_CLONED(o) (((SPObject *) (o))->cloned)
52 /* Write flags */
53 #define SP_OBJECT_WRITE_BUILD (1 << 0)
54 #define SP_OBJECT_WRITE_EXT (1 << 1)
55 #define SP_OBJECT_WRITE_ALL (1 << 2)
57 /* Convenience stuff */
58 #define SP_OBJECT_REPR(o) (((SPObject *) (o))->getRepr())
59 #define SP_OBJECT_DOCUMENT(o) (((SPObject *) (o))->document)
60 #define SP_OBJECT_PARENT(o) (((SPObject *) (o))->parent)
61 #define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style)
63 #include <glib-object.h>
64 #include <sigc++/connection.h>
65 #include <sigc++/functors/slot.h>
66 #include <sigc++/signal.h>
68 #include "forward.h"
69 #include "version.h"
70 #include "util/forward-pointer-iterator.h"
71 #include "desktop-style.h"
73 namespace Inkscape {
74 namespace XML {
75 class Node;
76 class Document;
77 }
78 }
81 typedef enum {
82     SP_NO_EXCEPTION,
83     SP_INDEX_SIZE_ERR,
84     SP_DOMSTRING_SIZE_ERR,
85     SP_HIERARCHY_REQUEST_ERR,
86     SP_WRONG_DOCUMENT_ERR,
87     SP_INVALID_CHARACTER_ERR,
88     SP_NO_DATA_ALLOWED_ERR,
89     SP_NO_MODIFICATION_ALLOWED_ERR,
90     SP_NOT_FOUND_ERR,
91     SP_NOT_SUPPORTED_ERR,
92     SP_INUSE_ATTRIBUTE_ERR,
93     SP_INVALID_STATE_ERR,
94     SP_SYNTAX_ERR,
95     SP_INVALID_MODIFICATION_ERR,
96     SP_NAMESPACE_ERR,
97     SP_INVALID_ACCESS_ERR
98 } SPExceptionType;
100 class SPException;
102 /// An attempt to implement exceptions, unused?
103 struct SPException {
104     SPExceptionType code;
105 };
107 #define SP_EXCEPTION_INIT(ex) {(ex)->code = SP_NO_EXCEPTION;}
108 #define SP_EXCEPTION_IS_OK(ex) (!(ex) || ((ex)->code == SP_NO_EXCEPTION))
110 class SPCtx;
112 /// Unused
113 struct SPCtx {
114     unsigned int flags;
115 };
117 enum {
118     SP_XML_SPACE_DEFAULT,
119     SP_XML_SPACE_PRESERVE
120 };
122 class SPIXmlSpace;
124 /// Internal class consisting of two bits.
125 struct SPIXmlSpace {
126     guint set : 1;
127     guint value : 1;
128 };
130 class SPObject;
132 /*
133  * Refcounting
134  *
135  * Owner is here for debug reasons, you can set it to NULL safely
136  * Ref should return object, NULL is error, unref return always NULL
137  */
139 SPObject *sp_object_ref(SPObject *object, SPObject *owner=NULL);
140 SPObject *sp_object_unref(SPObject *object, SPObject *owner=NULL);
142 SPObject *sp_object_href(SPObject *object, gpointer owner);
143 SPObject *sp_object_hunref(SPObject *object, gpointer owner);
145 /// A refcounting tree node object.
146 class SPObject : public GObject {
147 public:
148     enum CollectionPolicy {
149         COLLECT_WITH_PARENT,
150         ALWAYS_COLLECT
151     };
153     unsigned int cloned : 1;
154     unsigned int uflags : 8;
155     unsigned int mflags : 8;
156     SPIXmlSpace xml_space;
157     unsigned int hrefcount; /* number of xlink:href references */
158     unsigned int _total_hrefcount; /* our hrefcount + total descendants */
159     SPDocument *document; /* Document we are part of */
160     SPObject *parent; /* Our parent (only one allowed) */
161     SPObject *children; /* Our children */
162     SPObject *_last_child; /* Remembered last child */
163     SPObject *next; /* Next object in linked list */
165 private:
166     gchar *id; /* Our very own unique id */
167     Inkscape::XML::Node *repr; /* Our xml representation */
168 public:
170     /**
171      * Returns the objects current ID string.
172      */
173     gchar const* getId() const;
175     /**
176      * Returns the XML representation of tree
177      */
178     //Inkscape::XML::Node const* getRepr() const;
179 //protected:
180     Inkscape::XML::Node * getRepr();
182     /**
183      * Returns the XML representation of tree
184      */
185     Inkscape::XML::Node const* getRepr() const;
187 public:
189     /** @brief cleans up an SPObject, releasing its references and
190      *         requesting that references to it be released
191      */
192     void releaseReferences();
194     /** @brief connects to the release request signal
195      *
196      *  @param slot the slot to connect
197      *
198      *  @returns the sigc::connection formed
199      */
200     sigc::connection connectRelease(sigc::slot<void, SPObject *> slot) {
201         return _release_signal.connect(slot);
202     }
204     /**
205      * Represents the style properties, whether from presentation attributes, the <tt>style</tt>
206      * attribute, or inherited.
207      *
208      * sp_object_private_set doesn't handle SP_ATTR_STYLE or any presentation attributes at the
209      * time of writing, so this is probably NULL for all SPObject's that aren't an SPItem.
210      *
211      * However, this gives rise to the bugs mentioned in sp_object_get_style_property.
212      * Note that some non-SPItem SPObject's, such as SPStop, do need styling information,
213      * and need to inherit properties even through other non-SPItem parents like \<defs\>.
214      */
215     SPStyle *style;
217     /// Switch containing next() method.
218     struct ParentIteratorStrategy {
219         static SPObject const *next(SPObject const *object) {
220             return object->parent;
221         }
222     };
223     /// Switch containing next() method.
224     struct SiblingIteratorStrategy {
225         static SPObject const *next(SPObject const *object) {
226             return object->next;
227         }
228     };
230     typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator;
231     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator;
232     typedef Inkscape::Util::ForwardPointerIterator<SPObject, SiblingIteratorStrategy> SiblingIterator;
233     typedef Inkscape::Util::ForwardPointerIterator<SPObject const, SiblingIteratorStrategy> ConstSiblingIterator;
235     bool isSiblingOf(SPObject const *object) const {
236         g_return_val_if_fail(object != NULL, false);
237         return this->parent && this->parent == object->parent;
238     }
239     bool isAncestorOf(SPObject const *object) const;
241     SPObject const *nearestCommonAncestor(SPObject const *object) const;
242     /* A non-const version can be similarly constructed if you want one.
243      * (Don't just cast away the constness, which would be ill-formed.) */
245     SPObject *getNext() {return next;}
246     SPObject const *getNext() const {return next;}
248     /**
249      * Returns previous object in sibling list or NULL.
250      */
251     SPObject *getPrev();
253     bool hasChildren() const { return ( children != NULL ); }
255     SPObject *firstChild() { return children; }
256     SPObject const *firstChild() const { return children; }
258     SPObject *lastChild() { return _last_child; }
259     SPObject const *lastChild() const { return _last_child; }
261     enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow };
263     /**
264      * Retrieves the children as a GSList object, optionally ref'ing the children
265      * in the process, if add_ref is specified.
266      */
267     GSList *childList(bool add_ref, Action action = ActionGeneral);
269     SPObject *appendChildRepr(Inkscape::XML::Node *repr);
271     /** @brief Gets the author-visible label for this object. */
272     gchar const *label() const;
273     /** @brief Returns a default label for this object. */
274     gchar const *defaultLabel() const;
275     /** @brief Sets the author-visible label for this object.
276      *
277      * Sets the author-visible label for the object.
278      *
279      * @param label the new label
280      */
281     void setLabel(gchar const *label);
283     /** Retrieves the title of this object */
284     gchar *title() const;
285     /** Sets the title of this object */
286     bool setTitle(gchar const *title, bool verbatim=false);
288     /** Retrieves the description of this object */
289     gchar *desc() const;
290     /** Sets the description of this object */
291     bool setDesc(gchar const *desc, bool verbatim=false);
293     /** @brief Set the policy under which this object will be
294      *         orphan-collected.
295      *
296      * Orphan-collection is the process of deleting all objects which no longer have
297      * hyper-references pointing to them.  The policy determines when this happens.  Many objects
298      * should not be deleted simply because they are no longer referred to; other objects (like
299      * "intermediate" gradients) are more or less throw-away and should always be collected when no
300      * longer in use.
301      *
302      * Along these lines, there are currently two orphan-collection policies:
303      *
304      *  COLLECT_WITH_PARENT - don't worry about the object's hrefcount;
305      *                        if its parent is collected, this object
306      *                        will be too
307      *
308      *  COLLECT_ALWAYS - always collect the object as soon as its
309      *                   hrefcount reaches zero
310      *
311      * @returns the current collection policy in effect for this object
312      */
313     CollectionPolicy collectionPolicy() const { return _collection_policy; }
315     /** @brief Sets the orphan-collection policy in effect for this object.
316      *
317      * @see SPObject::collectionPolicy
318      *
319      * @param policy the new policy to adopt
320      */
321     void setCollectionPolicy(CollectionPolicy policy) {
322         _collection_policy = policy;
323     }
325     /** @brief Requests a later automatic call to collectOrphan().
326      *
327      * This method requests that collectOrphan() be called during the document update cycle,
328      * deleting the object if it is no longer used.
329      *
330      * If the current collection policy is COLLECT_WITH_PARENT, this function has no effect.
331      *
332      * @see SPObject::collectOrphan
333      */
334     void requestOrphanCollection();
336     /** @brief Unconditionally delete the object if it is not referenced.
337      *
338      * Unconditionally delete the object if there are no outstanding hyper-references to it.
339      * Observers are not notified of the object's deletion (at the SPObject level; XML tree
340      * notifications still fire).
341      *
342      * @see SPObject::deleteObject
343      */
344     void collectOrphan() {
345         if ( _total_hrefcount == 0 ) {
346             deleteObject(false);
347         }
348     }
350     /** @brief Check if object is referenced by any other object.
351      */
352     bool isReferenced() { return ( _total_hrefcount > 0 ); }
354     /** @brief Deletes an object.
355      *
356      * Detaches the object's repr, and optionally sends notification that the object has been
357      * deleted.
358      *
359      * @param propagate notify observers that the object has been deleted?
360      *
361      * @param propagate_descendants notify observers of children that they have been deleted?
362      */
363     void deleteObject(bool propagate, bool propagate_descendants);
365     /** @brief Deletes on object.
366      *
367      * @param propagate Notify observers of this object and its children that they have been
368      *                  deleted?
369      */
370     void deleteObject(bool propagate=true) {
371         deleteObject(propagate, propagate);
372     }
374     /** @brief Connects a slot to be called when an object is deleted.
375      *
376      * This connects a slot to an object's internal delete signal, which is invoked when the object
377      * is deleted
378      *
379      * The signal is mainly useful for e.g. knowing when to break hrefs or dissociate clones.
380      *
381      * @param slot the slot to connect
382      *
383      * @see SPObject::deleteObject
384      */
385     sigc::connection connectDelete(sigc::slot<void, SPObject *> slot) {
386         return _delete_signal.connect(slot);
387     }
389     sigc::connection connectPositionChanged(sigc::slot<void, SPObject *> slot) {
390         return _position_changed_signal.connect(slot);
391     }
393     /** @brief Returns the object which supercedes this one (if any).
394      *
395      * This is mainly useful for ensuring we can correctly perform a series of moves or deletes,
396      * even if the objects in question have been replaced in the middle of the sequence.
397      */
398     SPObject *successor() { return _successor; }
400     /** @brief Indicates that another object supercedes this one. */
401     void setSuccessor(SPObject *successor) {
402         g_assert(successor != NULL);
403         g_assert(_successor == NULL);
404         g_assert(successor->_successor == NULL);
405         sp_object_ref(successor, NULL);
406         _successor = successor;
407     }
409     /* modifications; all three sets of methods should probably ultimately be protected, as they
410      * are not really part of its public interface.  However, other parts of the code to
411      * occasionally use them at present. */
413     /* the no-argument version of updateRepr() is intended to be a bit more public, however -- it
414      * essentially just flushes any changes back to the backing store (the repr layer); maybe it
415      * should be called something else and made public at that point. */
417     /** @brief Updates the object's repr based on the object's state.
418      *
419      *  This method updates the the repr attached to the object to reflect the object's current
420      *  state; see the three-argument version for details.
421      *
422      *  @param flags object write flags that apply to this update
423      *
424      *  @return the updated repr
425      */
426     Inkscape::XML::Node *updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT);
428     /** @brief Updates the given repr based on the object's state.
429      *
430      *  This method updates the given repr to reflect the object's current state.  There are
431      *  several flags that affect this:
432      *
433      *   SP_OBJECT_WRITE_BUILD - create new reprs
434      *
435      *   SP_OBJECT_WRITE_EXT   - write elements and attributes
436      *                           which are not part of pure SVG
437      *                           (i.e. the Inkscape and Sodipodi
438      *                           namespaces)
439      *
440      *   SP_OBJECT_WRITE_ALL   - create all nodes and attributes,
441      *                           even those which might be redundant
442      *
443      *  @param repr the repr to update
444      *  @param flags object write flags that apply to this update
445      *
446      *  @return the updated repr
447      */
448     Inkscape::XML::Node *updateRepr(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags);
450     /** @brief Queues an deferred update of this object's display.
451      *
452      *  This method sets flags to indicate updates to be performed later, during the idle loop.
453      *
454      *  There are several flags permitted here:
455      *
456      *   SP_OBJECT_MODIFIED_FLAG - the object has been modified
457      *
458      *   SP_OBJECT_CHILD_MODIFIED_FLAG - a child of the object has been
459      *                                   modified
460      *
461      *   SP_OBJECT_STYLE_MODIFIED_FLAG - the object's style has been
462      *                                   modified
463      *
464      *  There are also some subclass-specific modified flags which are hardly ever used.
465      *
466      *  One of either MODIFIED or CHILD_MODIFIED is required.
467      *
468      *  @param flags flags indicating what to update
469      */
470     void requestDisplayUpdate(unsigned int flags);
472     /** @brief Updates the object's display immediately
473      *
474      *  This method is called during the idle loop by SPDocument in order to update the object's
475      *  display.
476      *
477      *  One additional flag is legal here:
478      *
479      *   SP_OBJECT_PARENT_MODIFIED_FLAG - the parent has been
480      *                                    modified
481      *
482      *  @param ctx an SPCtx which accumulates various state
483      *             during the recursive update -- beware! some
484      *             subclasses try to cast this to an SPItemCtx *
485      *
486      *  @param flags flags indicating what to update (in addition
487      *               to any already set flags)
488      */
489     void updateDisplay(SPCtx *ctx, unsigned int flags);
491     /** @brief Requests that a modification notification signal
492      *         be emitted later (e.g. during the idle loop)
493      *
494      *  @param flags flags indicating what has been modified
495      */
496     void requestModified(unsigned int flags);
498     /** @brief Emits a modification notification signal
499      *
500      *  @param flags indicating what has been modified
501      */
502     void emitModified(unsigned int flags);
504     /** @brief Connects to the modification notification signal
505      *
506      *  @param slot the slot to connect
507      *
508      *  @returns the connection formed thereby
509      */
510     sigc::connection connectModified(
511       sigc::slot<void, SPObject *, unsigned int> slot
512     ) {
513         return _modified_signal.connect(slot);
514     }
516     /** Sends the delete signal to all children of this object recursively */
517     void _sendDeleteSignalRecursive();
519     void _updateTotalHRefCount(int increment);
521     void _requireSVGVersion(unsigned major, unsigned minor) {
522         _requireSVGVersion(Inkscape::Version(major, minor));
523     }
524     void _requireSVGVersion(Inkscape::Version version);
526     sigc::signal<void, SPObject *> _release_signal;
527     sigc::signal<void, SPObject *> _delete_signal;
528     sigc::signal<void, SPObject *> _position_changed_signal;
529     sigc::signal<void, SPObject *, unsigned int> _modified_signal;
530     SPObject *_successor;
531     CollectionPolicy _collection_policy;
532     gchar *_label;
533     mutable gchar *_default_label;
535     // WARNING:
536     // Methods below should not be used outside of the SP tree,
537     // as they operate directly on the XML representation.
538     // In future, they will be made protected.
539     void attach(SPObject *object, SPObject *prev);
540     void reorder(SPObject *prev);
541     void detach(SPObject *object);
542     SPObject *get_child_by_repr(Inkscape::XML::Node *repr);
543     void invoke_build(SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned);
544     long long int getIntAttribute(char const *key, long long int def);
545     unsigned getPosition();
546     gchar const * getAttribute(gchar const *name,SPException *ex=0) const;
547     void appendChild(Inkscape::XML::Node *child);
548     void addChild(Inkscape::XML::Node *child,Inkscape::XML::Node *prev=0);
549     void setKeyValue(unsigned int key, gchar const *value);
550     void setAttribute(gchar const *key, gchar const *value, SPException *ex=0);
551     void readAttr(gchar const *key);
552     gchar const *getTagName(SPException *ex) const;
553     void removeAttribute(gchar const *key, SPException *ex=0);
554     gchar const *getStyleProperty(gchar const *key, gchar const *def) const;
555     void setCSS(SPCSSAttr *css, gchar const *attr);
556     void changeCSS(SPCSSAttr *css, gchar const *attr);
557     bool storeAsDouble( gchar const *key, double *val ) const;
559 private:
560     // Private member functions used in the definitions of setTitle(),
561     // setDesc(), title() and desc().
562     bool setTitleOrDesc(gchar const *value, gchar const *svg_tagname, bool verbatim);
563     gchar * getTitleOrDesc(gchar const *svg_tagname) const;
564     SPObject * findFirstChild(gchar const *tagname) const;
565     GString * textualContent() const;
567     static void sp_object_init(SPObject *object);
568     static void sp_object_finalize(GObject *object);
570     static void sp_object_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
571     static void sp_object_remove_child(SPObject *object, Inkscape::XML::Node *child);
572     static void sp_object_order_changed(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref);
574     static void sp_object_release(SPObject *object);
575     static void sp_object_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
577     static void sp_object_private_set(SPObject *object, unsigned int key, gchar const *value);
578     static Inkscape::XML::Node *sp_object_private_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
579     static gchar *sp_object_get_unique_id(SPObject *object, gchar const *defid);
581     /* Real handlers of repr signals */
583 public:
584     static GType sp_object_get_type();
585     static void sp_object_repr_attr_changed(Inkscape::XML::Node *repr, gchar const *key, gchar const *oldval, gchar const *newval, bool is_interactive, gpointer data);
587     static void sp_object_repr_content_changed(Inkscape::XML::Node *repr, gchar const *oldcontent, gchar const *newcontent, gpointer data);
589     static void sp_object_repr_child_added(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, gpointer data);
590     static void sp_object_repr_child_removed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void *data);
592     static void sp_object_repr_order_changed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *newer, gpointer data);
595     friend class SPObjectClass;
596     friend class SPObjectImpl;
597 };
599 /// The SPObject vtable.
600 class SPObjectClass {
601 public:
602     GObjectClass parent_class;
604     void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr);
605     void (* release) (SPObject *object);
607     /* Virtual handlers of repr signals */
608     void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
609     void (* remove_child) (SPObject *object, Inkscape::XML::Node *child);
611     void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr);
613     void (* set) (SPObject *object, unsigned int key, gchar const *value);
615     void (* read_content) (SPObject *object);
617     /* Update handler */
618     void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags);
619     /* Modification handler */
620     void (* modified) (SPObject *object, unsigned int flags);
622     Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags);
624 private:
625     static GObjectClass *static_parent_class;
626     static void sp_object_class_init(SPObjectClass *klass);
628     friend class SPObject;
629 };
632 int sp_object_compare_position(SPObject const *first, SPObject const *second);
635 #endif // SP_OBJECT_H_SEEN
638 /*
639   Local Variables:
640   mode:c++
641   c-file-style:"stroustrup"
642   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
643   indent-tabs-mode:nil
644   fill-column:99
645   End:
646 */
647 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :