18
21
#include <glib/gtypes.h>
19
22
#include "gc-anchored.h"
20
23
#include "util/list.h"
24
#include "xml/xml-forward.h"
22
26
namespace Inkscape {
25
class AttributeRecord;
27
class NodeEventVector;
30
* @brief Enumeration containing all supported node types.
33
DOCUMENT_NODE, ///< Top-level document node. Do not confuse with the root node.
34
ELEMENT_NODE, ///< Regular element node, e.g. <group />.
35
TEXT_NODE, ///< Text node, e.g. "Some text" in <group>Some text</group> is represented by a text node.
36
COMMENT_NODE, ///< Comment node, e.g. <!-- some comment -->
37
PI_NODE ///< Processing instruction node, e.g. <?xml version="1.0" encoding="utf-8" standalone="no"?>
37
40
// careful; GC::Anchored should only appear once in the inheritance
38
// hierarcy; else there will be leaks
41
// hierarchy; otherwise there will be leaks
44
* @brief Interface for refcounted XML nodes
46
* This class is an abstract base type for all nodes in an XML document - this includes
47
* everything except attributes. An XML document is also a node itself. This is the main
48
* class used for interfacing with Inkscape's documents. Everything that has to be stored
49
* in the SVG has to go through this class at some point.
51
* Each node unconditionally has to belong to a document. There no "documentless" nodes,
52
* and it's not possible to move nodes between documents - they have to be duplicated.
53
* Each node can only refer to the nodes in the same document. Name of the node is immutable,
54
* it cannot be changed after its creation. Same goes for the type of the node. To simplify
55
* the use of this class, you can perform all operations on all nodes, but only some of them
56
* make any sense. For example, only element nodes can have attributes, only element and
57
* document nodes can have children, and all nodes except element and document nodes can
58
* have content. Although you can set content for element nodes, it won't make any difference
61
* To create new nodes, use the methods of the Inkscape::XML::Document class. You can obtain
62
* the nodes' document using the document() method. To destroy a node, just unparent it
63
* by calling sp_repr_unparent() or node->parent->removeChild() and release any references
64
* to it. The garbage collector will reclaim the memory in the next pass. There are additional
65
* convenience functions defined in @ref xml/repr.h
67
* In addition to regular DOM manipulations, you can register observer objects that will
68
* receive notifications about changes made to the node. See the NodeObserver class.
70
* @see Inkscape::XML::Document
71
* @see Inkscape::XML::NodeObserver
39
73
class Node : public Inkscape::GC::Anchored {
79
* @name Retrieve information about the node
84
* @brief Get the type of the node
85
* @return NodeType enumeration member corresponding to the type of the node.
45
87
virtual NodeType type() const=0;
90
* @brief Get the name of the element node
92
* This method only makes sense for element nodes. Names are stored as
93
* GQuarks to accelerate conversions.
95
* @return Name for element nodes, NULL for others
47
97
virtual gchar const *name() const=0;
99
* @brief Get the integer code corresponding to the node's name
100
* @return GQuark code corresponding to the name
48
102
virtual int code() const=0;
105
* @brief Get the index of this node in parent's child order
107
* If this method is used on a node that doesn't have a parent, the method will return 0,
108
* and a warning will be printed on the console.
110
* @return The node's index, or 0 if the node does not have a parent
112
virtual unsigned position() const=0;
115
* @brief Get the number of children of this node
116
* @return The number of children
118
virtual unsigned childCount() const=0;
121
* @brief Get the content of a text or comment node
123
* This method makes no sense for element nodes. To retrieve the element node's name,
124
* use the name() method.
126
* @return The node's content
128
virtual gchar const *content() const=0;
131
* @brief Get the string representation of a node's attribute
133
* If there is no attribute with the given name, the method will return NULL.
134
* All strings returned by this method are owned by the node and may not be freed.
135
* The returned pointer will become invalid when the attribute changes. If you need
136
* to store the return value, use g_strdup(). To parse the string, use methods
139
* @param key The name of the node's attribute
141
virtual gchar const *attribute(gchar const *key) const=0;
144
* @brief Get a list of the node's attributes
146
* The returned list is a functional programming style list rather than a standard one.
148
* @return A list of AttributeRecord structures describing the attributes
149
* @todo This method should return std::map<Glib::Quark const, gchar const *>
150
* or something similar with a custom allocator
152
virtual Inkscape::Util::List<AttributeRecord const> attributeList() const=0;
155
* @brief Check whether this node has any attribute that matches a string
157
* This method checks whether this node has any attributes whose names
158
* have @c partial_name as their substrings. The check is done using
159
* the strstr() function of the C library. I don't know what would require that
160
* functionality, because matchAttributeName("id") matches both "identity" and "hidden".
162
* @param partial_name The string to match against all attributes
163
* @return true if there is such an attribute, false otherwise
165
virtual bool matchAttributeName(gchar const *partial_name) const=0;
170
* @name Modify the node
175
* @brief Set the position of this node in parent's child order
177
* To move the node to the end of the parent's child order, pass a negative argument.
179
* @param pos The new position in parent's child order
181
virtual void setPosition(int pos)=0;
184
* @brief Set the content of a text or comment node
186
* This method doesn't make sense for element nodes.
188
* @param value The node's new content
190
virtual void setContent(gchar const *value)=0;
193
* @brief Change an attribute of this node
195
* The strings passed to this method are copied, so you can free them after use.
197
* @param key Name of the attribute to change
198
* @param value The new value of the attribute
199
* @param is_interactive Ignored
201
virtual void setAttribute(gchar const *key, gchar const *value, bool is_interactive=false)=0;
204
* @brief Directly set the integer GQuark code for the name of the node
206
* This function is a hack to easily move elements with no namespace to the SVG namespace.
207
* Do not use this function unless you really have a good reason.
209
* @param code The integer value corresponding to the string to be set as the name of this node
49
211
virtual void setCodeUnsafe(int code)=0;
217
* @name Traverse the XML tree
223
* @brief Get the node's associated document
224
* @return The document to which the node belongs. Never NULL.
51
226
virtual Document *document()=0;
52
227
virtual Document const *document() const=0;
54
virtual Node *duplicate(Document *doc) const=0;
232
* @brief Get the root node of this node's document
234
* This method works on any node that is part of an XML document, and returns
235
* the root node of the document in which it resides. For detached node hierarchies
236
* (i.e. nodes that are not descendants of a document node) this method
237
* returns the highest-level element node. For detached non-element nodes this method
240
* @return A pointer to the root element node, or NULL if the node is detached
56
242
virtual Node *root()=0;
57
243
virtual Node const *root() const=0;
248
* @brief Get the parent of this node
250
* This method will return NULL for detached nodes.
252
* @return Pointer to the parent, or NULL
59
254
virtual Node *parent()=0;
60
255
virtual Node const *parent() const=0;
260
* @brief Get the next sibling of this node
262
* This method will return NULL if the node is the last sibling element of the parent.
263
* The nodes form a singly-linked list, so there is no "prev()" method. Use the provided
264
* external function for that.
266
* @return Pointer to the next sibling, or NULL
267
* @see Inkscape::XML::previous_node()
62
269
virtual Node *next()=0;
63
270
virtual Node const *next() const=0;
275
* @brief Get the first child of this node
277
* For nodes without any children, this method returns NULL.
279
* @return Pointer to the first child, or NULL
65
281
virtual Node *firstChild()=0;
66
282
virtual Node const *firstChild() const=0;
287
* @brief Get the last child of this node
289
* For nodes without any children, this method returns NULL.
291
* @return Pointer to the last child, or NULL
67
293
virtual Node *lastChild()=0;
68
294
virtual Node const *lastChild() const=0;
70
virtual unsigned childCount() const=0;
299
* @brief Get the child of this node with a given index
301
* If there is no child with the specified index number, this method will return NULL.
303
* @param index The zero-based index of the child to retrieve
304
* @return Pointer to the appropriate child, or NULL
71
306
virtual Node *nthChild(unsigned index)=0;
72
307
virtual Node const *nthChild(unsigned index) const=0;
74
virtual void addChild(Node *child, Node *ref)=0;
313
* @name Manipulate the XML tree
318
* @brief Create a duplicate of this node
320
* The newly created node has no parent, and a refcount equal 1.
321
* You need to manually insert it into the document, using e.g. appendChild().
322
* Afterwards, call Inkscape::GC::release on it, so that it will be
323
* automatically collected when the parent is collected.
325
* @param doc The document in which the duplicate should be created
326
* @return A pointer to the duplicated node
328
virtual Node *duplicate(Document *doc) const=0;
331
* @brief Insert another node as a child of this node
333
* When @c after is NULL, the inserted node will be placed as the first child
334
* of this node. @c after must be a child of this node.
336
* @param child The node to insert
337
* @param after The node after which the inserted node should be placed, or NULL
339
virtual void addChild(Node *child, Node *after)=0;
342
* @brief Append a node as the last child of this node
343
* @param child The node to append
75
345
virtual void appendChild(Node *child)=0;
348
* @brief Remove a child of this node
350
* Once the pointer to the removed node disappears from the stack, the removed node
351
* will be collected in the next GC pass, but only as long as its refcount is zero.
352
* You should keep a refcount of zero for all nodes in the document except for
353
* the document node itself, because they will be held in memory by the parent.
355
* @param child The child to remove
76
357
virtual void removeChild(Node *child)=0;
77
virtual void changeOrder(Node *child, Node *ref)=0;
79
virtual unsigned position() const=0;
80
virtual void setPosition(int pos)=0;
82
virtual gchar const *attribute(gchar const *key) const=0;
83
virtual void setAttribute(gchar const *key, gchar const *value, bool is_interactive=false)=0;
84
virtual bool matchAttributeName(gchar const *partial_name) const=0;
86
virtual gchar const *content() const=0;
87
virtual void setContent(gchar const *value)=0;
360
* @brief Move a given node in this node's child order
362
* Both @c child and @c after must be children of this node for the method to work.
364
* @param child The node to move in the order
365
* @param after The sibling node after which the moved node should be placed
367
virtual void changeOrder(Node *child, Node *after)=0;
370
* @brief Merge all children of another node with the current
372
* This method merges two node hierarchies, where @c src takes precedence.
373
* @c key is the name of the attribute that determines whether two nodes are
374
* corresponding (it must be the same for both, and all of their ancestors). If there is
375
* a corresponding node in @c src hierarchy, their attributes and content override the ones
376
* already present in this node's hierarchy. If there is no corresponding node,
377
* it is copied from @c src to this node. This method is used when merging the user's
378
* preferences file with the defaults, and has little use beyond that.
380
* @param src The node to merge into this node
381
* @param key The attribute to use as the identity attribute
89
383
virtual void mergeFrom(Node const *src, gchar const *key)=0;
91
virtual Inkscape::Util::List<AttributeRecord const> attributeList() const=0;
93
virtual void synthesizeEvents(NodeEventVector const *vector, void *data)=0;
94
virtual void synthesizeEvents(NodeObserver &observer)=0;
389
* @name Notify observers about operations on the node
394
* @brief Add an object that will be notified of the changes to this node
396
* @c observer must be an object deriving from the NodeObserver class.
397
* The virtual methods of this object will be called when a corresponding change
398
* happens to this node. You can also notify the observer of the node's current state
399
* using synthesizeEvents(NodeObserver &).
401
* @param observer The observer object
95
403
virtual void addObserver(NodeObserver &observer)=0;
96
virtual void addListener(NodeEventVector const *vector, void *data)=0;
405
* @brief Remove an object from the list of observers
406
* @param observer The object to be removed
97
408
virtual void removeObserver(NodeObserver &observer)=0;
98
virtual void removeListenerByData(void *data)=0;
410
* @brief Generate a sequence of events corresponding to the state of this node
412
* This function notifies the specified observer of all the events that would
413
* recreate the current state of this node; e.g. the observer is notified of
414
* all the attributes, children and content like they were just created.
415
* This function can greatly simplify observer logic.
417
* @param observer The node observer to notify of the events
419
virtual void synthesizeEvents(NodeObserver &observer)=0;
422
* @brief Add an object that will be notified of the changes to this node and its descendants
424
* The difference between adding a regular observer and a subtree observer is that
425
* the subtree observer will also be notified if a change occurs to any of the node's
426
* descendants, while a regular observer will only be notified of changes to the node
427
* it was assigned to.
429
* @param observer The observer object
100
431
virtual void addSubtreeObserver(NodeObserver &observer)=0;
434
* @brief Remove an object from the subtree observers list
435
* @param observer The object to be removed
101
437
virtual void removeSubtreeObserver(NodeObserver &observer)=0;
440
* @brief Add a set node change callbacks with an associated data
441
* @deprecated Use addObserver(NodeObserver &) instead
443
virtual void addListener(NodeEventVector const *vector, void *data)=0;
445
* @brief Remove a set of node change callbacks by their associated data
446
* @deprecated Use removeObserver(NodeObserver &) instead
448
virtual void removeListenerByData(void *data)=0;
450
* @brief Generate a sequence of events corresponding to the state of this node
451
* @deprecated Use synthesizeEvents(NodeObserver &) instead
453
virtual void synthesizeEvents(NodeEventVector const *vector, void *data)=0;
104
458
Node(Node const &) : Anchored() {}
106
public: // ideally these should be protected too somehow...
107
virtual NodeObserver &_subtreeObservers()=0;
108
virtual void _setParent(Node *parent)=0;
109
virtual void _setNext(Node *next)=0;
110
virtual void _bindDocument(Document &document)=0;
112
virtual unsigned _childPosition(Node const &child) const=0;
113
virtual unsigned _cachedPosition() const=0;
114
virtual void _setCachedPosition(unsigned position) const=0;