Code

Inkscape::XML::Document -> Inkscape::XML::DocumentTree (more refactoring ...)
[inkscape.git] / src / xml / node.h
1 /** @file
2  * @brief Interface for XML nodes
3  */
4 /* Authors:
5  *   MenTaLguY <mental@rydia.net>
6  *   Krzysztof KosiƄski <tweenk.pl@gmail.com> (documentation)
7  *
8  * Copyright 2005-2008 Authors
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * See the file COPYING for details.
16  */
18 #ifndef SEEN_INKSCAPE_XML_NODE_H
19 #define SEEN_INKSCAPE_XML_NODE_H
21 #include <glib/gtypes.h>
22 #include "gc-anchored.h"
23 #include "util/list.h"
24 #include "xml/xml-forward.h"
26 namespace Inkscape {
27 namespace XML {
29 /**
30  * @brief Enumeration containing all supported node types.
31  */
32 enum NodeType {
33     DOCUMENT_NODE, ///< Top-level document node. Do not confuse with the root node.
34     ELEMENT_NODE, ///< Regular element node, e.g. &lt;group /&gt;.
35     TEXT_NODE, ///< Text node, e.g. "Some text" in &lt;group&gt;Some text&lt;/group&gt; is represented by a text node.
36     COMMENT_NODE, ///< Comment node, e.g. &lt;!-- some comment --&gt;
37     PI_NODE ///< Processing instruction node, e.g. &lt;?xml version="1.0" encoding="utf-8" standalone="no"?&gt;
38 };
40 // careful; GC::Anchored should only appear once in the inheritance
41 // hierarchy; otherwise there will be leaks
43 /**
44  * @brief Interface for refcounted XML nodes
45  *
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.
50  *
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
59  * in the XML output.
60  *
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
66  *
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.
69  *
70  * @see Inkscape::XML::Document
71  * @see Inkscape::XML::NodeObserver
72  */
73 class Node : public Inkscape::GC::Anchored {
74 public:
75     Node() {}
76     virtual ~Node() {}
78     /**
79      * @name Retrieve information about the node
80      * @{
81      */
85     /**
86      * @brief Get the type of the node
87      * @return NodeType enumeration member corresponding to the type of the node.
88      */
89     virtual NodeType type() const=0;
91     /**
92      * @brief Get the name of the element node
93      *
94      * This method only makes sense for element nodes. Names are stored as
95      * GQuarks to accelerate conversions.
96      *
97      * @return Name for element nodes, NULL for others
98      */
99     virtual gchar const *name() const=0;
100     /**
101      * @brief Get the integer code corresponding to the node's name
102      * @return GQuark code corresponding to the name
103      */
104     virtual int code() const=0;
105     
106     /**
107      * @brief Get the index of this node in parent's child order
108      *
109      * If this method is used on a node that doesn't have a parent, the method will return 0,
110      * and a warning will be printed on the console.
111      *
112      * @return The node's index, or 0 if the node does not have a parent
113      */
114     virtual unsigned position() const=0;
116     /**
117      * @brief Get the number of children of this node
118      * @return The number of children
119      */
120     virtual unsigned childCount() const=0;
121     
122     /**
123      * @brief Get the content of a text or comment node
124      *
125      * This method makes no sense for element nodes. To retrieve the element node's name,
126      * use the name() method.
127      *
128      * @return The node's content
129      */
130     virtual gchar const *content() const=0;
131     
132     /**
133      * @brief Get the string representation of a node's attribute
134      *
135      * If there is no attribute with the given name, the method will return NULL.
136      * All strings returned by this method are owned by the node and may not be freed.
137      * The returned pointer will become invalid when the attribute changes. If you need
138      * to store the return value, use g_strdup(). To parse the string, use methods
139      * in repr.h
140      *
141      * @param key The name of the node's attribute
142      */
143     virtual gchar const *attribute(gchar const *key) const=0;
144     
145     /**
146      * @brief Get a list of the node's attributes
147      *
148      * The returned list is a functional programming style list rather than a standard one.
149      *
150      * @return A list of AttributeRecord structures describing the attributes
151      * @todo This method should return std::map<Glib::Quark const, gchar const *>
152      *       or something similar with a custom allocator
153      */
154     virtual Inkscape::Util::List<AttributeRecord const> attributeList() const=0;
156     /**
157      * @brief Check whether this node has any attribute that matches a string
158      *
159      * This method checks whether this node has any attributes whose names
160      * have @c partial_name as their substrings. The check is done using
161      * the strstr() function of the C library. I don't know what would require that
162      * functionality, because matchAttributeName("id") matches both "identity" and "hidden".
163      *
164      * @param partial_name The string to match against all attributes
165      * @return true if there is such an attribute, false otherwise
166      */
167     virtual bool matchAttributeName(gchar const *partial_name) const=0;
169     /*@}*/
170     
171     /**
172      * @name Modify the node
173      * @{
174      */
175     
176     /**
177      * @brief Set the position of this node in parent's child order
178      *
179      * To move the node to the end of the parent's child order, pass a negative argument.
180      *
181      * @param pos The new position in parent's child order
182      */
183     virtual void setPosition(int pos)=0;
184     
185     /**
186      * @brief Set the content of a text or comment node
187      *
188      * This method doesn't make sense for element nodes.
189      *
190      * @param value The node's new content
191      */
192     virtual void setContent(gchar const *value)=0;
193     
194     /**
195      * @brief Change an attribute of this node
196      *
197      * The strings passed to this method are copied, so you can free them after use.
198      *
199      * @param key Name of the attribute to change
200      * @param value The new value of the attribute
201      * @param is_interactive Ignored
202      */
203     virtual void setAttribute(gchar const *key, gchar const *value, bool is_interactive=false)=0;
204     
205     /**
206      * @brief Directly set the integer GQuark code for the name of the node
207      *
208      * This function is a hack to easily move elements with no namespace to the SVG namespace.
209      * Do not use this function unless you really have a good reason.
210      *
211      * @param code The integer value corresponding to the string to be set as the name of this node
212      */
213     virtual void setCodeUnsafe(int code)=0;
214     
215     /*@}*/
217     
218     /**
219      * @name Traverse the XML tree
220      * @{
221      */
222      
223     //@{
224     /**
225      * @brief Get the node's associated document
226      * @return The document to which the node belongs. Never NULL.
227      */
228     virtual Document *document()=0;
229     virtual Document const *document() const=0;
230     //@}
232     //@{
233     /**
234      * @brief Get the root node of this node's document
235      *
236      * This method works on any node that is part of an XML document, and returns
237      * the root node of the document in which it resides. For detached node hierarchies
238      * (i.e. nodes that are not descendants of a document node) this method
239      * returns the highest-level element node. For detached non-element nodes this method
240      * returns NULL.
241      *
242      * @return A pointer to the root element node, or NULL if the node is detached
243      */
244     virtual Node *root()=0;
245     virtual Node const *root() const=0;
246     //@}
248     //@{
249     /**
250      * @brief Get the parent of this node
251      *
252      * This method will return NULL for detached nodes.
253      *
254      * @return Pointer to the parent, or NULL
255      */
256     virtual Node *parent()=0;
257     virtual Node const *parent() const=0;
258     //@}
260     //@{
261     /**
262      * @brief Get the next sibling of this node
263      *
264      * This method will return NULL if the node is the last sibling element of the parent.
265      * The nodes form a singly-linked list, so there is no "prev()" method. Use the provided
266      * external function for that.
267      *
268      * @return Pointer to the next sibling, or NULL
269      * @see Inkscape::XML::previous_node()
270      */
271     virtual Node *next()=0;
272     virtual Node const *next() const=0;
273     //@}
275     //@{
276     /**
277      * @brief Get the first child of this node
278      *
279      * For nodes without any children, this method returns NULL.
280      *
281      * @return Pointer to the first child, or NULL
282      */
283     virtual Node *firstChild()=0;
284     virtual Node const *firstChild() const=0;
285     //@}
286     
287     //@{
288     /**
289      * @brief Get the last child of this node
290      *
291      * For nodes without any children, this method returns NULL.
292      *
293      * @return Pointer to the last child, or NULL
294      */
295     virtual Node *lastChild()=0;
296     virtual Node const *lastChild() const=0;
297     //@}
298     
299     //@{
300     /**
301      * @brief Get the child of this node with a given index
302      *
303      * If there is no child with the specified index number, this method will return NULL.
304      *
305      * @param index The zero-based index of the child to retrieve
306      * @return Pointer to the appropriate child, or NULL
307      */
308     virtual Node *nthChild(unsigned index)=0;
309     virtual Node const *nthChild(unsigned index) const=0;
310     //@}
311     
312     /*@}*/
313     
314     /**
315      * @name Manipulate the XML tree
316      * @{
317      */
319     /**
320      * @brief Create a duplicate of this node
321      *
322      * The newly created node has no parent, and a refcount equal 1.
323      * You need to manually insert it into the document, using e.g. appendChild().
324      * Afterwards, call Inkscape::GC::release on it, so that it will be
325      * automatically collected when the parent is collected.
326      *
327      * @param doc The document in which the duplicate should be created
328      * @return A pointer to the duplicated node
329      */
330     virtual Node *duplicate(Document *doc) const=0;
332     /**
333      * @brief Insert another node as a child of this node
334      *
335      * When @c after is NULL, the inserted node will be placed as the first child
336      * of this node. @c after must be a child of this node.
337      *
338      * @param child The node to insert
339      * @param after The node after which the inserted node should be placed, or NULL
340      */
341     virtual void addChild(Node *child, Node *after)=0;
342     
343     /**
344      * @brief Append a node as the last child of this node
345      * @param child The node to append
346      */
347     virtual void appendChild(Node *child)=0;
348     
349     /**
350      * @brief Remove a child of this node
351      *
352      * Once the pointer to the removed node disappears from the stack, the removed node
353      * will be collected in the next GC pass, but only as long as its refcount is zero.
354      * You should keep a refcount of zero for all nodes in the document except for
355      * the document node itself, because they will be held in memory by the parent.
356      *
357      * @param child The child to remove
358      */
359     virtual void removeChild(Node *child)=0;
360     
361     /**
362      * @brief Move a given node in this node's child order
363      *
364      * Both @c child and @c after must be children of this node for the method to work.
365      *
366      * @param child The node to move in the order
367      * @param after The sibling node after which the moved node should be placed
368      */
369     virtual void changeOrder(Node *child, Node *after)=0;
371     /**
372      * @brief Merge all children of another node with the current
373      *
374      * This method merges two node hierarchies, where @c src takes precedence.
375      * @c key is the name of the attribute that determines whether two nodes are
376      * corresponding (it must be the same for both, and all of their ancestors). If there is
377      * a corresponding node in @c src hierarchy, their attributes and content override the ones
378      * already present in this node's hierarchy. If there is no corresponding node,
379      * it is copied from @c src to this node. This method is used when merging the user's
380      * preferences file with the defaults, and has little use beyond that.
381      *
382      * @param src The node to merge into this node
383      * @param key The attribute to use as the identity attribute
384      */
385     virtual void mergeFrom(Node const *src, gchar const *key)=0;
386     
387     /*@}*/
390     /**
391      * @name Notify observers about operations on the node
392      * @{
393      */
395     /**
396      * @brief Add an object that will be notified of the changes to this node
397      *
398      * @c observer must be an object deriving from the NodeObserver class.
399      * The virtual methods of this object will be called when a corresponding change
400      * happens to this node. You can also notify the observer of the node's current state
401      * using synthesizeEvents(NodeObserver &).
402      *
403      * @param observer The observer object
404      */
405     virtual void addObserver(NodeObserver &observer)=0;
406     /**
407      * @brief Remove an object from the list of observers
408      * @param observer The object to be removed
409      */
410     virtual void removeObserver(NodeObserver &observer)=0;
411     /**
412      * @brief Generate a sequence of events corresponding to the state of this node
413      *
414      * This function notifies the specified observer of all the events that would
415      * recreate the current state of this node; e.g. the observer is notified of
416      * all the attributes, children and content like they were just created.
417      * This function can greatly simplify observer logic.
418      *
419      * @param observer The node observer to notify of the events
420      */
421     virtual void synthesizeEvents(NodeObserver &observer)=0;
423     /**
424      * @brief Add an object that will be notified of the changes to this node and its descendants
425      *
426      * The difference between adding a regular observer and a subtree observer is that
427      * the subtree observer will also be notified if a change occurs to any of the node's
428      * descendants, while a regular observer will only be notified of changes to the node
429      * it was assigned to.
430      *
431      * @param observer The observer object
432      */
433     virtual void addSubtreeObserver(NodeObserver &observer)=0;
434     
435     /**
436      * @brief Remove an object from the subtree observers list
437      * @param observer The object to be removed
438      */
439     virtual void removeSubtreeObserver(NodeObserver &observer)=0;
441     /**
442      * @brief Add a set node change callbacks with an associated data
443      * @deprecated Use addObserver(NodeObserver &) instead
444      */
445     virtual void addListener(NodeEventVector const *vector, void *data)=0;
446     /**
447      * @brief Remove a set of node change callbacks by their associated data
448      * @deprecated Use removeObserver(NodeObserver &) instead
449      */
450     virtual void removeListenerByData(void *data)=0;
451     /**
452      * @brief Generate a sequence of events corresponding to the state of this node
453      * @deprecated Use synthesizeEvents(NodeObserver &) instead
454      */
455     virtual void synthesizeEvents(NodeEventVector const *vector, void *data)=0;
456     
457     /*@}*/
459 protected:
460     Node(Node const &) : Anchored() {}
461 };
466 #endif
467 /*
468   Local Variables:
469   mode:c++
470   c-file-style:"stroustrup"
471   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
472   indent-tabs-mode:nil
473   fill-column:99
474   End:
475 */
476 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :