diff options
Diffstat (limited to 'src/object/sp-object.h')
-rw-r--r-- | src/object/sp-object.h | 895 |
1 files changed, 895 insertions, 0 deletions
diff --git a/src/object/sp-object.h b/src/object/sp-object.h new file mode 100644 index 0000000..64c67be --- /dev/null +++ b/src/object/sp-object.h @@ -0,0 +1,895 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SP_OBJECT_H_SEEN +#define SP_OBJECT_H_SEEN + + +/* + * Authors: + * Lauris Kaplinski <lauris@kaplinski.com> + * Jon A. Cruz <jon@joncruz.org> + * Abhishek Sharma + * Adrian Boguszewski + * + * Copyright (C) 1999-2016 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <set> +#include <glibmm/ustring.h> +#include "util/const_char_ptr.h" +/* SPObject flags */ + +class SPObject; + +#define MAKE_SP_OBJECT_DOWNCAST_FUNCTIONS(func, T) \ + inline T *func(SPObject *obj) { return dynamic_cast<T *>(obj); } \ + inline T const *func(SPObject const *obj) { return dynamic_cast<T const *>(obj); } \ + inline T *func(T *derived) = delete; \ + inline T const *func(T const *derived) = delete; + +#define MAKE_SP_OBJECT_TYPECHECK_FUNCTIONS(func, T) \ + inline bool func(SPObject const *obj) { return dynamic_cast<T const *>(obj); } + +#define SP_IS_OBJECT(obj) (dynamic_cast<const SPObject*>(obj) != nullptr) + +/* 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_STYLESHEET_MODIFIED_FLAG (1 << 7) + +/* Convenience */ +#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)) + +/* Write flags */ +#define SP_OBJECT_WRITE_BUILD (1 << 0) +#define SP_OBJECT_WRITE_EXT (1 << 1) +#define SP_OBJECT_WRITE_ALL (1 << 2) +#define SP_OBJECT_WRITE_NO_CHILDREN (1 << 3) + +#include <cassert> +#include <cstddef> +#include <sigc++/connection.h> +#include <sigc++/functors/slot.h> +#include <sigc++/signal.h> +#include <vector> +#include <boost/intrusive/list.hpp> +#include "2geom/point.h" // Used for dpi only +#include "version.h" +#include "util/forward-pointer-iterator.h" + +enum class SPAttr; + +class SPCSSAttr; +class SPStyle; + +namespace Inkscape { +namespace XML { +class Node; +struct Document; +} +} + +namespace Glib { + class ustring; +} + +/// Unused +struct SPCtx { + unsigned int flags; +}; + +enum { + SP_XML_SPACE_DEFAULT, + SP_XML_SPACE_PRESERVE +}; + +class SPDocument; + +/// Internal class consisting of two bits. +class SPIXmlSpace { +public: + SPIXmlSpace(): set(0), value(SP_XML_SPACE_DEFAULT) {}; + unsigned int set : 1; + unsigned int value : 1; +}; + +/* + * 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 + */ + +/** + * Increase reference count of object, with possible debugging. + * + * @param owner If non-NULL, make debug log entry. + * @return object, NULL is error. + * \pre object points to real object + * @todo need to move this to be a member of SPObject. + */ +SPObject *sp_object_ref(SPObject *object, SPObject *owner=nullptr); + +/** + * Decrease reference count of object, with possible debugging and + * finalization. + * + * @param owner If non-NULL, make debug log entry. + * @return always NULL + * \pre object points to real object + * @todo need to move this to be a member of SPObject. + */ +SPObject *sp_object_unref(SPObject *object, SPObject *owner=nullptr); + +/** + * SPObject is an abstract base class of all of the document nodes at the + * SVG document level. Each SPObject subclass implements a certain SVG + * element node type, or is an abstract base class for different node + * types. The SPObject layer is bound to the SPRepr layer, closely + * following the SPRepr mutations via callbacks. During creation, + * SPObject parses and interprets all textual attributes and CSS style + * strings of the SPRepr, and later updates the internal state whenever + * it receives a signal about a change. The opposite is not true - there + * are methods manipulating SPObjects directly and such changes do not + * propagate to the SPRepr layer. This is important for implementation of + * the undo stack, animations and other features. + * + * SPObjects are bound to the higher-level container SPDocument, which + * provides document level functionality such as the undo stack, + * dictionary and so on. Source: doc/architecture.txt + */ +class SPObject { +public: + enum CollectionPolicy { + COLLECT_WITH_PARENT, + ALWAYS_COLLECT + }; + + SPObject(); + virtual ~SPObject(); + + unsigned int cloned : 1; + SPObject *clone_original; + unsigned int uflags : 8; + unsigned int mflags : 8; + SPIXmlSpace xml_space; + Glib::ustring lang; + 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) */ + +private: + SPObject(const SPObject&); + SPObject& operator=(const SPObject&); + + char *id; /* Our very own unique id */ + Inkscape::XML::Node *repr; /* Our xml representation */ + +public: + int refCount; + std::list<SPObject*> hrefList; + + /** + * Returns the objects current ID string. + */ + char const* getId() const; + + void getIds(std::set<std::string> &ret) const; + + /** + * Get the id in a URL format. + */ + std::string getUrl() const; + + /** + * Returns the XML representation of tree + */ +//protected: + Inkscape::XML::Node * getRepr(); + + /** + * Returns the XML representation of tree + */ + Inkscape::XML::Node const* getRepr() const; + +public: + + /** + * Cleans up an SPObject, releasing its references and + * requesting that references to it be released + */ + void releaseReferences(); + + /** + * Connects to the release request signal + * + * @param slot the slot to connect + * + * @return the sigc::connection formed + */ + sigc::connection connectRelease(sigc::slot<void, SPObject *> slot) { + return _release_signal.connect(slot); + } + + /** + * Represents the style properties, whether from presentation attributes, the <tt>style</tt> + * attribute, or inherited. + * + * private_set() doesn't handle SPAttr::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; + + /** + * Represents the style that should be used to resolve 'context-fill' and 'context-stroke' + */ + SPStyle *context_style; + + /// Switch containing next() method. + struct ParentIteratorStrategy { + static SPObject const *next(SPObject const *object) { + return object->parent; + } + }; + + typedef Inkscape::Util::ForwardPointerIterator<SPObject, ParentIteratorStrategy> ParentIterator; + typedef Inkscape::Util::ForwardPointerIterator<SPObject const, ParentIteratorStrategy> ConstParentIterator; + + bool isSiblingOf(SPObject const *object) const { + if (object == nullptr) return false; + return this->parent && this->parent == object->parent; + } + + /** + * True if object is non-NULL and this is some in/direct parent of object. + */ + bool isAncestorOf(SPObject const *object) const; + + /** + * Returns youngest object being parent to this and object. + */ + SPObject const *nearestCommonAncestor(SPObject const *object) const; + + /* Returns next object in sibling list or NULL. */ + SPObject *getNext(); + + /** + * Returns previous object in sibling list or NULL. + */ + SPObject *getPrev(); + + bool hasChildren() const { return ( children.size() > 0 ); } + + SPObject *firstChild() { return children.empty() ? nullptr : &children.front(); } + SPObject const *firstChild() const { return children.empty() ? nullptr : &children.front(); } + + SPObject *lastChild() { return children.empty() ? nullptr : &children.back(); } + SPObject const *lastChild() const { return children.empty() ? nullptr : &children.back(); } + + SPObject *nthChild(unsigned index); + SPObject const *nthChild(unsigned index) const; + + enum Action { ActionGeneral, ActionBBox, ActionUpdate, ActionShow }; + + /** + * Retrieves the children as a std vector object, optionally ref'ing the children + * in the process, if add_ref is specified. + */ + std::vector<SPObject*> childList(bool add_ref, Action action = ActionGeneral); + + + /** + * Retrieves a list of ancestors of the object, as an easy to use vector + * @param root_to_tip - If set, orders the list from the svg root to the tip. + */ + std::vector<SPObject*> ancestorList(bool root_to_tip); + + /** + * Append repr as child of this object. + * \pre this is not a cloned object + */ + SPObject *appendChildRepr(Inkscape::XML::Node *repr); + + /** + * Gets the author-visible label property for the object or a default if + * no label is defined. + */ + char const *label() const; + + /** + * Returns a default label property for this object. + */ + char const *defaultLabel() const; + + /** + * Sets the author-visible label for this object. + * + * @param label the new label. + */ + void setLabel(char const *label); + + /** + * Returns the title of this object, or NULL if there is none. + * The caller must free the returned string using g_free() - see comment + * for getTitleOrDesc() below. + */ + char *title() const; + + /** + * Sets the title of this object. + * A NULL first argument is interpreted as meaning that the existing title + * (if any) should be deleted. + * The second argument is optional - @see setTitleOrDesc() below for details. + */ + bool setTitle(char const *title, bool verbatim = false); + + /** + * Returns the description of this object, or NULL if there is none. + * The caller must free the returned string using g_free() - see comment + * for getTitleOrDesc() below. + */ + char *desc() const; + + /** + * Sets the description of this object. + * A NULL first argument is interpreted as meaning that the existing + * description (if any) should be deleted. + * The second argument is optional - @see setTitleOrDesc() below for details. + */ + bool setDesc(char const *desc, bool verbatim=false); + + /** + * Get and set the exportable filename on this object. Usually sp-item or sp-page + */ + Glib::ustring getExportFilename() const; + void setExportFilename(Glib::ustring filename); + + /** + * Get and set the exported DPI for this objet, if available. + */ + Geom::Point getExportDpi() const; + void setExportDpi(Geom::Point dpi); + + /** + * 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 + * + * @return the current collection policy in effect for this object + */ + CollectionPolicy collectionPolicy() const { return _collection_policy; } + + /** + * Sets the orphan-collection policy in effect for this object. + * + * @param policy the new policy to adopt + * + * @see SPObject::collectionPolicy + */ + void setCollectionPolicy(CollectionPolicy policy) { + _collection_policy = policy; + } + + /** + * 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(); + + /** + * 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); + } + } + + /** + * Increase weak refcount. + * + * Hrefcount is used for weak references, for example, to + * determine whether any graphical element references a certain gradient + * node. + * It keeps a list of "owners". + * @param owner Used to track who uses this object. + */ + void hrefObject(SPObject* owner = nullptr); + + /** + * Decrease weak refcount. + * + * Hrefcount is used for weak references, for example, to determine whether + * any graphical element references a certain gradient node. + * @param owner Used to track who uses this object. + * \pre hrefcount>0 + */ + void unhrefObject(SPObject* owner = nullptr); + + /** + * Check if object is referenced by any other object. + */ + bool isReferenced() { return ( _total_hrefcount > 0 ); } + + /** + * Deletes an object, unparenting it from its parent. + * + * Detaches the object's repr, and optionally sends notification that the object has been + * deleted. + * + * @param propagate If it is set to true, it emits a delete signal. + * + * @param propagate_descendants If it is true, it recursively sends the delete signal to children. + */ + void deleteObject(bool propagate, bool propagate_descendants); + + /** + * 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); + } + + /** + * Removes all children except for the given object, it's children and it's ancesstors. + */ + void cropToObject(SPObject *except); + void cropToObjects(std::vector<SPObject *> except_objects); + + /** + * 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); + } + + sigc::connection connectPositionChanged(sigc::slot<void, SPObject *> slot) { + return _position_changed_signal.connect(slot); + } + + /** + * 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; } + + /** + * Indicates that another object supercedes this one. + */ + void setSuccessor(SPObject *successor) { + assert(successor != NULL); + assert(_successor == NULL); + assert(successor->_successor == NULL); + sp_object_ref(successor, nullptr); + _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. */ + + /** + * Updates the object's repr based on the object's state. + * + * This method updates the repr attached to the object to reflect the object's current + * state; see the three-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); + + /** + * Updates the given repr based on the object's state. + * + * Used both to create reprs in the original document, and to create reprs + * in another document (e.g. a temporary document used when saving as "Plain SVG". + * + * 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::Document *doc, Inkscape::XML::Node *repr, unsigned int flags); + + /** + * 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); + + /** + * 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); + + /** + * Requests that a modification notification signal + * be emitted later (e.g. during the idle loop) + * + * Request modified always bubbles *up* the tree, as opposed to + * request display update, which trickles down and relies on the + * flags set during this pass... + * + * @param flags flags indicating what has been modified + */ + void requestModified(unsigned int flags); + + /** + * Emits the MODIFIED signal with the object's flags. + * The object's mflags are the original set aside during the update pass for + * later delivery here. Once emitModified() is called, those flags don't + * need to be stored any longer. + * + * @param flags indicating what has been modified. + */ + void emitModified(unsigned int flags); + + /** + * Connects to the modification notification signal + * + * @param slot the slot to connect + * + * @return the connection formed thereby + */ + sigc::connection connectModified( + sigc::slot<void, SPObject *, unsigned int> slot + ) { + return _modified_signal.connect(slot); + } + + /** Sends the delete signal to all children of this object recursively */ + void _sendDeleteSignalRecursive(); + + /** + * Adds increment to _total_hrefcount of object and its parents. + */ + void _updateTotalHRefCount(int increment); + + void _requireSVGVersion(unsigned major, unsigned minor) { + _requireSVGVersion(Inkscape::Version(major, minor)); + } + + /** + * Lifts SVG version of all root objects to version. + */ + void _requireSVGVersion(Inkscape::Version version); + + sigc::signal<void, SPObject *> _release_signal; + sigc::signal<void, SPObject *> _delete_signal; + sigc::signal<void, SPObject *> _position_changed_signal; + sigc::signal<void, SPObject *, unsigned int> _modified_signal; + SPObject *_successor; + CollectionPolicy _collection_policy; + char *_label; + mutable char *_default_label; + + // WARNING: + // Methods below should not be used outside of the SP tree, + // as they operate directly on the XML representation. + // In future, they will be made protected. + + /** + * Put object into object tree, under parent, and behind prev; + * also update object's XML space. + */ + void attach(SPObject *object, SPObject *prev); + + /** + * In list of object's children, move object behind prev. + */ + void reorder(SPObject* obj, SPObject *prev); + + /** + * Remove object from parent's children, release and unref it. + */ + void detach(SPObject *object); + + /** + * Return object's child whose node pointer equals repr. + */ + SPObject *get_child_by_repr(Inkscape::XML::Node *repr); + + void invoke_build(SPDocument *document, Inkscape::XML::Node *repr, unsigned int cloned); + + int getIntAttribute(char const *key, int def); + + unsigned getPosition(); + + char const * getAttribute(char const *name) const; + + void appendChild(Inkscape::XML::Node *child); + + void addChild(Inkscape::XML::Node *child,Inkscape::XML::Node *prev=nullptr); + + /** + * Call virtual set() function of object. + */ + void setKeyValue(SPAttr key, char const *value); + + + void setAttribute(Inkscape::Util::const_char_ptr key, + Inkscape::Util::const_char_ptr value); + + void setAttributeDouble(Inkscape::Util::const_char_ptr key, double value); + + void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, + Inkscape::Util::const_char_ptr value) { + this->setAttribute(key.data(), + (value.data() == nullptr || value.data()[0]=='\0') ? nullptr : value.data()); + } + + /** + * Read value of key attribute from XML node into object. + */ + void readAttr(char const *key); + void readAttr(SPAttr keyid); + + char const *getTagName() const; + + void removeAttribute(char const *key); + + void setCSS(SPCSSAttr *css, char const *attr); + + void changeCSS(SPCSSAttr *css, char const *attr); + + bool storeAsDouble( char const *key, double *val ) const; + +private: + // Private member functions used in the definitions of setTitle(), + // setDesc(), title() and desc(). + + /** + * Sets or deletes the title or description of this object. + * A NULL 'value' argument causes the title or description to be deleted. + * + * 'verbatim' parameter: + * If verbatim==true, then the title or description is set to exactly the + * specified value. If verbatim==false then two exceptions are made: + * (1) If the specified value is just whitespace, then the title/description + * is deleted. + * (2) If the specified value is the same as the current value except for + * mark-up, then the current value is left unchanged. + * This is usually the desired behaviour, so 'verbatim' defaults to false for + * setTitle() and setDesc(). + * + * The return value is true if a change was made to the title/description, + * and usually false otherwise. + */ + bool setTitleOrDesc(char const *value, char const *svg_tagname, bool verbatim); + + /** + * Returns the title or description of this object, or NULL if there is none. + * + * The SVG spec allows 'title' and 'desc' elements to contain text marked up + * using elements from other namespaces. Therefore, this function cannot + * in general just return a pointer to an existing string - it must instead + * construct a string containing the title or description without the mark-up. + * Consequently, the return value is a newly allocated string (or NULL), and + * must be freed (using g_free()) by the caller. + */ + char * getTitleOrDesc(char const *svg_tagname) const; + + /** + * Find the first child of this object with a given tag name, + * and return it. Returns NULL if there is no matching child. + */ + SPObject * findFirstChild(char const *tagname) const; + + /** + * Return the full textual content of an element (typically all the + * content except the tags). + * Must not be used on anything except elements. + */ + Glib::ustring textualContent() const; + + /* Real handlers of repr signals */ + +public: + /** + * Callback for attr_changed node event. + */ + static void repr_attr_changed(Inkscape::XML::Node *repr, char const *key, char const *oldval, char const *newval, bool is_interactive, void* data); + + /** + * Callback for content_changed node event. + */ + static void repr_content_changed(Inkscape::XML::Node *repr, char const *oldcontent, char const *newcontent, void* data); + + /** + * Callback for child_added node event. + */ + static void repr_child_added(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void* data); + + /** + * Callback for remove_child node event. + */ + static void repr_child_removed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void *data); + + /** + * Callback for order_changed node event. + * + * \todo fixme: + */ + static void repr_order_changed(Inkscape::XML::Node *repr, Inkscape::XML::Node *child, Inkscape::XML::Node *old, Inkscape::XML::Node *newer, void* data); + + /** + * Callback for name_changed node event + */ + static void repr_name_changed(Inkscape::XML::Node* repr, gchar const* oldname, gchar const* newname, void * data); + + friend class SPObjectImpl; + +protected: + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); + + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); + + virtual void order_changed(Inkscape::XML::Node* child, Inkscape::XML::Node* old_repr, Inkscape::XML::Node* new_repr); + virtual void tag_name_changed(gchar const* oldname, gchar const* newname); + + virtual void set(SPAttr key, const char* value); + + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); + + virtual Inkscape::XML::Node* write(Inkscape::XML::Document* doc, Inkscape::XML::Node* repr, unsigned int flags); + + typedef boost::intrusive::list_member_hook<> ListHook; + ListHook _child_hook; +public: + typedef boost::intrusive::list< + SPObject, + boost::intrusive::member_hook< + SPObject, + ListHook, + &SPObject::_child_hook + >> ChildrenList; + ChildrenList children; + virtual void read_content(); + + void recursivePrintTree(unsigned level = 0); // For debugging + static unsigned indent_level; + void objectTrace( std::string const &, bool in=true, unsigned flags=0 ); +}; + +std::ostream &operator<<(std::ostream &out, const SPObject &o); + +/** + * Compares height of objects in tree. + * + * Works for different-parent objects, so long as they have a common ancestor. + * \return \verbatim + * 0 positions are equivalent + * 1 first object's position is greater than the second + * -1 first object's position is less than the second \endverbatim + */ +int sp_object_compare_position(SPObject const *first, SPObject const *second); +bool sp_object_compare_position_bool(SPObject const *first, SPObject const *second); +gchar * sp_object_get_unique_id(SPObject *object, gchar const *defid); + +#endif // SP_OBJECT_H_SEEN + + +/* + 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:fileencoding=utf-8:textwidth=99 : |