Code

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