diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/sp-object.h | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/sp-object.h')
| -rw-r--r-- | src/sp-object.h | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/src/sp-object.h b/src/sp-object.h new file mode 100644 index 000000000..767f8b978 --- /dev/null +++ b/src/sp-object.h @@ -0,0 +1,539 @@ +#ifndef __SP_OBJECT_H__ +#define __SP_OBJECT_H__ + +/** \file + * Abstract base class for all nodes + * + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * + * Copyright (C) 1999-2002 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +/* SPObject flags */ + +/* Async modification flags */ +#define SP_OBJECT_MODIFIED_FLAG (1 << 0) +#define SP_OBJECT_CHILD_MODIFIED_FLAG (1 << 1) +#define SP_OBJECT_PARENT_MODIFIED_FLAG (1 << 2) +#define SP_OBJECT_STYLE_MODIFIED_FLAG (1 << 3) +#define SP_OBJECT_VIEWPORT_MODIFIED_FLAG (1 << 4) +#define SP_OBJECT_USER_MODIFIED_FLAG_A (1 << 5) +#define SP_OBJECT_USER_MODIFIED_FLAG_B (1 << 6) +#define SP_OBJECT_USER_MODIFIED_FLAG_C (1 << 7) + +/* Conveneience */ +#define SP_OBJECT_FLAGS_ALL 0xff + +/* Flags that mark object as modified */ +/* Object, Child, Style, Viewport, User */ +#define SP_OBJECT_MODIFIED_STATE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_PARENT_MODIFIED_FLAG)) + +/* Flags that will propagate downstreams */ +/* Parent, Style, Viewport, User */ +#define SP_OBJECT_MODIFIED_CASCADE (SP_OBJECT_FLAGS_ALL & ~(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG)) + +/* Generic */ +#define SP_OBJECT_IS_CLONED(o) (((SPObject *) (o))->cloned) + +/* Write flags */ +#define SP_OBJECT_WRITE_BUILD (1 << 0) +#define SP_OBJECT_WRITE_EXT (1 << 1) +#define SP_OBJECT_WRITE_ALL (1 << 2) + +/* Convenience stuff */ +#define SP_OBJECT_ID(o) (((SPObject *) (o))->id) +#define SP_OBJECT_REPR(o) (((SPObject *) (o))->repr) +#define SP_OBJECT_DOCUMENT(o) (((SPObject *) (o))->document) +#define SP_OBJECT_PARENT(o) (((SPObject *) (o))->parent) +#define SP_OBJECT_NEXT(o) (((SPObject *) (o))->next) +#define SP_OBJECT_PREV(o) (sp_object_prev((SPObject *) (o))) +#define SP_OBJECT_HREFCOUNT(o) (((SPObject *) (o))->hrefcount) +#define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style) +#define SP_OBJECT_TITLE(o) sp_object_title_get((SPObject *) (o)) +#define SP_OBJECT_DESCRIPTION(o) sp_object_description_get((SPObject *) (o)) + + +#include <glib-object.h> +#include <sigc++/connection.h> +#include <sigc++/functors/slot.h> +#include <sigc++/signal.h> + +#include "forward.h" +#include "version.h" +#include "util/forward-pointer-iterator.h" + +namespace Inkscape { +namespace XML { +class Node; +} +} + + +typedef enum { + SP_NO_EXCEPTION, + SP_INDEX_SIZE_ERR, + SP_DOMSTRING_SIZE_ERR, + SP_HIERARCHY_REQUEST_ERR, + SP_WRONG_DOCUMENT_ERR, + SP_INVALID_CHARACTER_ERR, + SP_NO_DATA_ALLOWED_ERR, + SP_NO_MODIFICATION_ALLOWED_ERR, + SP_NOT_FOUND_ERR, + SP_NOT_SUPPORTED_ERR, + SP_INUSE_ATTRIBUTE_ERR, + SP_INVALID_STATE_ERR, + SP_SYNTAX_ERR, + SP_INVALID_MODIFICATION_ERR, + SP_NAMESPACE_ERR, + SP_INVALID_ACCESS_ERR +} SPExceptionType; + +class SPException; + +/// An attempt to implement exceptions, unused? +struct SPException { + SPExceptionType code; +}; + +#define SP_EXCEPTION_INIT(ex) {(ex)->code = SP_NO_EXCEPTION;} +#define SP_EXCEPTION_IS_OK(ex) (!(ex) || ((ex)->code == SP_NO_EXCEPTION)) + +class SPCtx; + +/// Unused +struct SPCtx { + unsigned int flags; +}; + +enum { + SP_XML_SPACE_DEFAULT, + SP_XML_SPACE_PRESERVE +}; + +class SPIXmlSpace; + +/// Internal class consisting of two bits. +struct SPIXmlSpace { + guint set : 1; + guint value : 1; +}; + +class SPObject; + +/* + * Refcounting + * + * Owner is here for debug reasons, you can set it to NULL safely + * Ref should return object, NULL is error, unref return always NULL + */ + +SPObject *sp_object_ref(SPObject *object, SPObject *owner=NULL); +SPObject *sp_object_unref(SPObject *object, SPObject *owner=NULL); + +SPObject *sp_object_href(SPObject *object, gpointer owner); +SPObject *sp_object_hunref(SPObject *object, gpointer owner); + +/// A refcounting tree node object. +struct SPObject : public GObject { + enum CollectionPolicy { + COLLECT_WITH_PARENT, + ALWAYS_COLLECT + }; + + unsigned int cloned : 1; + unsigned int uflags : 8; + unsigned int mflags : 8; + SPIXmlSpace xml_space; + unsigned int hrefcount; /* number of xlink:href references */ + unsigned int _total_hrefcount; /* our hrefcount + total descendants */ + SPDocument *document; /* Document we are part of */ + SPObject *parent; /* Our parent (only one allowed) */ + SPObject *children; /* Our children */ + SPObject *_last_child; /* Remembered last child */ + SPObject *next; /* Next object in linked list */ + Inkscape::XML::Node *repr; /* Our xml representation */ + gchar *id; /* Our very own unique id */ + + /** + * Represents the style properties, whether from presentation attributes, the <tt>style</tt> + * attribute, or inherited. + * + * sp_object_private_set doesn't handle SP_ATTR_STYLE or any presentation attributes at the + * time of writing, so this is probably NULL for all SPObject's that aren't an SPItem. + * + * However, this gives rise to the bugs mentioned in sp_object_get_style_property. + * Note that some non-SPItem SPObject's, such as SPStop, do need styling information, + * and need to inherit properties even through other non-SPItem parents like \<defs\>. + */ + SPStyle *style; + + /// Switch containing next() method. + struct ParentIteratorStrategy { + static SPObject const *next(SPObject const *object) { + return object->parent; + } + }; + /// Switch containing next() method. + struct SiblingIteratorStrategy { + static SPObject const *next(SPObject const *object) { + return object->next; + } + }; + + typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator; + typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator; + typedef Inkscape::Util::ForwardPointerIterator<SPObject, SiblingIteratorStrategy> SiblingIterator; + typedef Inkscape::Util::ForwardPointerIterator<SPObject const, SiblingIteratorStrategy> ConstSiblingIterator; + + bool isSiblingOf(SPObject const *object) const { + g_return_val_if_fail(object != NULL, false); + return this->parent && this->parent == object->parent; + } + bool isAncestorOf(SPObject const *object) const; + + SPObject const *nearestCommonAncestor(SPObject const *object) const; + /* A non-const version can be similarly constructed if you want one. + * (Don't just cast away the constness, which would be ill-formed.) */ + + bool hasChildren() const { return ( children != NULL ); } + + SPObject *firstChild() { return children; } + SPObject const *firstChild() const { return children; } + SPObject *lastChild() { return _last_child; } + SPObject const *lastChild() const { return _last_child; } + + SPObject *appendChildRepr(Inkscape::XML::Node *repr); + + /** @brief Gets the author-visible label for this object. */ + gchar const *label() const; + /** @brief Returns a default label for this object. */ + gchar const *defaultLabel() const; + /** @brief Sets the author-visible label for this object. + * + * Sets the author-visible label for the object. + * + * @param label the new label + */ + void setLabel(gchar const *label); + + /** Retrieves the title of this object */ + gchar const *title() const { return NULL; /* TODO */ } + /** Sets the title of this object */ + void setTitle(gchar const *title) { /* TODO */ } + + /** Retrieves the description of this object */ + gchar const *desc() const { return NULL; /* TODO */ } + /** Sets the description of this object */ + void setDesc(gchar const *desc) { /* TODO */ } + + /** @brief Set the policy under which this object will be + * orphan-collected. + * + * Orphan-collection is the process of deleting all objects which no longer have + * hyper-references pointing to them. The policy determines when this happens. Many objects + * should not be deleted simply because they are no longer referred to; other objects (like + * "intermediate" gradients) are more or less throw-away and should always be collected when no + * longer in use. + * + * Along these lines, there are currently two orphan-collection policies: + * + * COLLECT_WITH_PARENT - don't worry about the object's hrefcount; + * if its parent is collected, this object + * will be too + * + * COLLECT_ALWAYS - always collect the object as soon as its + * hrefcount reaches zero + * + * @returns the current collection policy in effect for this object + */ + CollectionPolicy collectionPolicy() const { return _collection_policy; } + + /** @brief Sets the orphan-collection policy in effect for this object. + * + * @see SPObject::collectionPolicy + * + * @param policy the new policy to adopt + */ + void setCollectionPolicy(CollectionPolicy policy) { + _collection_policy = policy; + } + + /** @brief Requests a later automatic call to collectOrphan(). + * + * This method requests that collectOrphan() be called during the document update cycle, + * deleting the object if it is no longer used. + * + * If the current collection policy is COLLECT_WITH_PARENT, this function has no effect. + * + * @see SPObject::collectOrphan + */ + void requestOrphanCollection(); + + /** @brief Unconditionally delete the object if it is not referenced. + * + * Unconditionally delete the object if there are no outstanding hyper-references to it. + * Observers are not notified of the object's deletion (at the SPObject level; XML tree + * notifications still fire). + * + * @see SPObject::deleteObject + */ + void collectOrphan() { + if ( _total_hrefcount == 0 ) { + deleteObject(false); + } + } + + /** @brief Deletes an object. + * + * Detaches the object's repr, and optionally sends notification that the object has been + * deleted. + * + * @param propagate notify observers that the object has been deleted? + * + * @param propagate_descendants notify observers of children that they have been deleted? + */ + void deleteObject(bool propagate, bool propagate_descendants); + + /** @brief Deletes on object. + * + * @param propagate Notify observers of this object and its children that they have been + * deleted? + */ + void deleteObject(bool propagate=true) { + deleteObject(propagate, propagate); + } + + /** @brief Connects a slot to be called when an object is deleted. + * + * This connects a slot to an object's internal delete signal, which is invoked when the object + * is deleted + * + * The signal is mainly useful for e.g. knowing when to break hrefs or dissociate clones. + * + * @param slot the slot to connect + * + * @see SPObject::deleteObject + */ + sigc::connection connectDelete(sigc::slot<void, SPObject *> slot) { + return _delete_signal.connect(slot); + } + + /** @brief Returns the object which supercedes this one (if any). + * + * This is mainly useful for ensuring we can correctly perform a series of moves or deletes, + * even if the objects in question have been replaced in the middle of the sequence. + */ + SPObject *successor() { return _successor; } + + /** @brief Indicates that another object supercedes this one. */ + void setSuccessor(SPObject *successor) { + g_assert(successor != NULL); + g_assert(_successor == NULL); + g_assert(successor->_successor == NULL); + sp_object_ref(successor, NULL); + _successor = successor; + } + + /* modifications; all three sets of methods should probably ultimately be protected, as they + * are not really part of its public interface. However, other parts of the code to + * occasionally use them at present. */ + + /* the no-argument version of updateRepr() is intended to be a bit more public, however -- it + * essentially just flushes any changes back to the backing store (the repr layer); maybe it + * should be called something else and made public at that point. */ + + /** @brief Updates the object's repr based on the object's state. + * + * This method updates the the repr attached to the object to reflect the object's current + * state; see the two-argument version for details. + * + * @param flags object write flags that apply to this update + * + * @return the updated repr + */ + Inkscape::XML::Node *updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT); + + /** @brief Updates the given repr based on the object's state. + * + * This method updates the given repr to reflect the object's current state. There are + * several flags that affect this: + * + * SP_OBJECT_WRITE_BUILD - create new reprs + * + * SP_OBJECT_WRITE_EXT - write elements and attributes + * which are not part of pure SVG + * (i.e. the Inkscape and Sodipodi + * namespaces) + * + * SP_OBJECT_WRITE_ALL - create all nodes and attributes, + * even those which might be redundant + * + * @param repr the repr to update + * @param flags object write flags that apply to this update + * + * @return the updated repr + */ + Inkscape::XML::Node *updateRepr(Inkscape::XML::Node *repr, unsigned int flags); + + /** @brief Queues an deferred update of this object's display. + * + * This method sets flags to indicate updates to be performed later, during the idle loop. + * + * There are several flags permitted here: + * + * SP_OBJECT_MODIFIED_FLAG - the object has been modified + * + * SP_OBJECT_CHILD_MODIFIED_FLAG - a child of the object has been + * modified + * + * SP_OBJECT_STYLE_MODIFIED_FLAG - the object's style has been + * modified + * + * There are also some subclass-specific modified flags which are hardly ever used. + * + * One of either MODIFIED or CHILD_MODIFIED is required. + * + * @param flags flags indicating what to update + */ + void requestDisplayUpdate(unsigned int flags); + + /** @brief Updates the object's display immediately + * + * This method is called during the idle loop by SPDocument in order to update the object's + * display. + * + * One additional flag is legal here: + * + * SP_OBJECT_PARENT_MODIFIED_FLAG - the parent has been + * modified + * + * @param ctx an SPCtx which accumulates various state + * during the recursive update -- beware! some + * subclasses try to cast this to an SPItemCtx * + * + * @param flags flags indicating what to update (in addition + * to any already set flags) + */ + void updateDisplay(SPCtx *ctx, unsigned int flags); + + /** @brief Requests that a modification notification signal + * be emitted later (e.g. during the idle loop) + * + * @param flags flags indicating what has been modified + */ + void requestModified(unsigned int flags); + + /** @brief Emits a modification notification signal + * + * @param flags indicating what has been modified + */ + void emitModified(unsigned int flags); + + void _sendDeleteSignalRecursive(); + void _updateTotalHRefCount(int increment); + + void _requireSVGVersion(unsigned major, unsigned minor) { + _requireSVGVersion(Inkscape::Version(major, minor)); + } + void _requireSVGVersion(Inkscape::Version version); + + sigc::signal<void, SPObject *> _delete_signal; + SPObject *_successor; + CollectionPolicy _collection_policy; + gchar *_label; + mutable gchar *_default_label; +}; + +/// The SPObject vtable. +struct SPObjectClass { + GObjectClass parent_class; + + void (* build) (SPObject *object, SPDocument *doc, Inkscape::XML::Node *repr); + void (* release) (SPObject *object); + + /* Virtual handlers of repr signals */ + void (* child_added) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref); + void (* remove_child) (SPObject *object, Inkscape::XML::Node *child); + + void (* order_changed) (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *new_repr); + + void (* set) (SPObject *object, unsigned int key, gchar const *value); + + void (* read_content) (SPObject *object); + + /* Update handler */ + void (* update) (SPObject *object, SPCtx *ctx, unsigned int flags); + /* Modification handler */ + void (* modified) (SPObject *object, unsigned int flags); + + Inkscape::XML::Node * (* write) (SPObject *object, Inkscape::XML::Node *repr, unsigned int flags); +}; + + +/* + * Attaching/detaching + */ + +void sp_object_attach(SPObject *parent, SPObject *object, SPObject *prev); +void sp_object_reorder(SPObject *object, SPObject *prev); +void sp_object_detach(SPObject *parent, SPObject *object); + +inline SPObject *sp_object_first_child(SPObject *parent) { + return parent->firstChild(); +} +SPObject *sp_object_get_child_by_repr(SPObject *object, Inkscape::XML::Node *repr); + +void sp_object_invoke_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned); +void sp_object_invoke_release(SPObject *object); + +void sp_object_set(SPObject *object, unsigned int key, gchar const *value); + +void sp_object_read_attr(SPObject *object, gchar const *key); + +/* + * Get and set descriptive parameters. + * + * These are inefficent, so they are not intended to be used interactively. + */ + +gchar const *sp_object_title_get(SPObject *object); +gchar const *sp_object_description_get(SPObject *object); +unsigned int sp_object_title_set(SPObject *object, gchar const *title); +unsigned int sp_object_description_set(SPObject *object, gchar const *desc); + +/* Public */ + +gchar const *sp_object_tagName_get(SPObject const *object, SPException *ex); +gchar const *sp_object_getAttribute(SPObject const *object, gchar const *key, SPException *ex); +void sp_object_setAttribute(SPObject *object, gchar const *key, gchar const *value, SPException *ex); +void sp_object_removeAttribute(SPObject *object, gchar const *key, SPException *ex); + +/* Style */ + +gchar const *sp_object_get_style_property(SPObject const *object, + gchar const *key, gchar const *def); + +Inkscape::Version sp_object_get_sodipodi_version(SPObject *object); + +int sp_object_compare_position(SPObject const *first, SPObject const *second); + +SPObject *sp_object_prev(SPObject *child); + + +#endif + + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : |
