1 #ifndef __SP_REPR_H__
2 #define __SP_REPR_H__
4 /** \file
5 * C facade to Inkscape::XML::Node.
6 *
7 * Authors:
8 * Lauris Kaplinski <lauris@kaplinski.com>
9 *
10 * Copyright (C) 1999-2002 authors
11 * Copyright (C) 2000-2002 Ximian, Inc.
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
16 #include <stdio.h>
17 #include <glib/gtypes.h>
18 #include "gc-anchored.h"
20 #include "xml/node.h"
21 #include "xml/document.h"
22 #include "xml/sp-css-attr.h"
24 #define SP_SODIPODI_NS_URI "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
25 #define SP_INKSCAPE_NS_URI "http://www.inkscape.org/namespaces/inkscape"
26 #define SP_XLINK_NS_URI "http://www.w3.org/1999/xlink"
27 #define SP_SVG_NS_URI "http://www.w3.org/2000/svg"
28 #define SP_RDF_NS_URI "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
29 #define SP_CC_NS_URI "http://web.resource.org/cc/"
30 #define SP_DC_NS_URI "http://purl.org/dc/elements/1.1/"
32 /**
33 * \note NB! Unless explicitly stated all methods are noref/nostrcpy
34 */
36 /** \todo
37 * Though Inkscape::XML::Node provides "signals" for notification when
38 * individual nodes change, there is no mechanism to receive notification
39 * for overall document changes.
40 * However, with the addition of the transactions code, it would not be
41 * very hard to implement if you wanted it.
42 *
43 * \class Inkscape::XML::Node
44 * \note
45 * Inkscape::XML::Node itself doesn't use GObject signals at present --
46 * Inkscape::XML::Nodes maintain lists of Inkscape::XML::NodeEventVectors
47 * (added via sp_repr_add_listener), which are used to specify callbacks
48 * when something changes.
49 *
50 * Here are the current callbacks in an event vector (they may be NULL):
51 *
52 * void (* child_added)(Inkscape::XML::Node *repr, Inkscape::XML::Node *child,
53 * Inkscape::XML::Node *ref, void *data); Called once a child has been added.
54 *
55 * void (* child_removed)(Inkscape::XML::Node *repr,
56 * Inkscape::XML::Node *child, Inkscape::XML::Node *ref, void *data);
57 * Called after a child is removed; ref is the child that used to precede
58 * the removed child.
59 *
60 * void (* attr_changed)(Inkscape::XML::Node *repr, gchar const *key,
61 * gchar const *oldval, gchar const *newval, void *data);
62 * Called after an attribute has been changed.
63 *
64 * void (* content_changed)(Inkscape::XML::Node *repr, gchar const *oldcontent,
65 * gchar const *newcontent, void *data);
66 * Called after an element's content has been changed.
67 *
68 * void (* order_changed)(Inkscape::XML::Node *repr, Inkscape::XML::Node *child,
69 * Inkscape::XML::Node *oldref, Inkscape::XML::Node *newref, void *data);
70 * Called once the child has been moved to its new position in the child order.
71 *
72 * <b> Inkscape::XML::Node mini-FAQ </b>
73 *
74 * Since I'm not very familiar with this section of code but I need to use
75 * it heavily for the RDF work, I'm going to answer various questions I run
76 * into with my best-guess answers so others can follow along too.
77 *
78 * \arg
79 * Q: How do I find the root Inkscape::XML::Node? <br>
80 * A: If you have an SPDocument, use doc->rroot. For example:
81 *
82 * \code SP_ACTIVE_DOCUMENT->rroot \endcode <br>
83 *
84 * (but it's better to arrange for your caller to pass in the relevent
85 * document rather than assuming it's necessarily the active one and
86 * using SP_ACTIVE_DOCUMENT)
87 *
88 * \arg
89 * Q: How do I find an Inkscape::XML::Node by unique key/value? <br>
90 * A: Use sp_repr_lookup_child
91 *
92 * \arg
93 * Q: How do I find an Inkscape::XML::Node by unique namespace name? <br>
94 * A: Use sp_repr_lookup_name
95 *
96 * \arg
97 * Q: How do I make an Inkscape::XML::Node namespace prefix constant in
98 * the application? <br>
99 * A: Add the XML namespace URL as a #define to repr.h at the top with the
100 * other SP_<NAMESPACE>_NS_URI #define's, and then in repr-util.cpp,
101 * in sp_xml_ns_register_defaults, bump "defaults" up in size one, and
102 * add another section. Don't forget to increment the array offset and
103 * keep ".next" pointed to the next (if any) array entry.
104 *
105 * \arg
106 * Q: How do I create a new Inkscape::XML::Node? <br>
107 * A: Use "sp_repr_new*". Then attach it to a parent somewhere with
108 * parent->appendChild(child), and then use Inkscape::GC::release(child) to
109 * let go of it (the parent will hold it in memory).
110 *
111 * \arg
112 * Q: How do I destroy an Inkscape::XML::Node?
113 * A: Just call "sp_repr_unparent" on it and release any references
114 * you may be retaining to it. Any attached SPObjects will
115 * clean themselves up automatically, as will any children.
116 *
117 * \arg
118 * Q: What about listeners? <br>
119 * A: I have no idea yet...
120 *
121 * \arg
122 * Q: How do I add a namespace to a newly created document? <br>
123 * A: The current hack is in document.cpp:sp_document_create
124 *
125 * Kees Cook 2004-07-01, updated MenTaLguY 2005-01-25
126 */
128 /* SPXMLNs */
129 char const *sp_xml_ns_uri_prefix(gchar const *uri, gchar const *suggested);
130 char const *sp_xml_ns_prefix_uri(gchar const *prefix);
133 Inkscape::XML::Node *sp_repr_new(gchar const *name);
134 Inkscape::XML::Node *sp_repr_new_text(gchar const *content);
135 Inkscape::XML::Node *sp_repr_new_comment(gchar const *comment);
137 /*inline Inkscape::XML::Node *sp_repr_duplicate(Inkscape::XML::Node const *repr) {
138 return repr->duplicate();
139 }*/
141 Inkscape::XML::Document *sp_repr_document_new(gchar const *rootname);
143 /// Returns root node of document.
144 inline Inkscape::XML::Node *sp_repr_document_root(Inkscape::XML::Document const *doc) {
145 return const_cast<Inkscape::XML::Node *>(doc->root());
146 }
148 /// Returns the node's document.
149 inline Inkscape::XML::Document *sp_repr_document(Inkscape::XML::Node const *repr) {
150 return const_cast<Inkscape::XML::Document *>(repr->document());
151 }
153 /* Contents */
154 /// Sets the node's \a key attribute to \a value.
155 inline unsigned sp_repr_set_attr(Inkscape::XML::Node *repr, gchar const *key, gchar const *value,
156 bool is_interactive = false) {
157 repr->setAttribute(key, value, is_interactive);
158 return true;
159 }
161 /* Tree */
162 /// Returns the node's parent.
163 inline Inkscape::XML::Node *sp_repr_parent(Inkscape::XML::Node const *repr) {
164 return const_cast<Inkscape::XML::Node *>(repr->parent());
165 }
167 /// Returns first child of node, resets iterator.
168 inline Inkscape::XML::Node *sp_repr_children(Inkscape::XML::Node *repr) {
169 return ( repr ? repr->firstChild() : NULL );
170 }
172 /// Returns next child of node or NULL.
173 inline Inkscape::XML::Node *sp_repr_next(Inkscape::XML::Node *repr) {
174 return ( repr ? repr->next() : NULL );
175 }
177 /* IO */
179 Inkscape::XML::Document *sp_repr_read_file(gchar const *filename, gchar const *default_ns);
180 Inkscape::XML::Document *sp_repr_read_mem(gchar const *buffer, int length, gchar const *default_ns);
181 void sp_repr_save_stream(Inkscape::XML::Document *doc, FILE *to_file, gchar const *default_ns=NULL, bool compress = false);
182 gboolean sp_repr_save_file(Inkscape::XML::Document *doc, gchar const *filename, gchar const *default_ns=NULL);
184 void sp_repr_print(Inkscape::XML::Node *repr);
186 /* CSS stuff */
188 SPCSSAttr *sp_repr_css_attr_new(void);
189 void sp_repr_css_attr_unref(SPCSSAttr *css);
190 SPCSSAttr *sp_repr_css_attr(Inkscape::XML::Node *repr, gchar const *attr);
191 SPCSSAttr *sp_repr_css_attr_inherited(Inkscape::XML::Node *repr, gchar const *attr);
193 gchar const *sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval);
194 void sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value);
195 void sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name);
196 bool sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name);
197 double sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval);
199 gchar *sp_repr_css_write_string(SPCSSAttr *css);
200 void sp_repr_css_set(Inkscape::XML::Node *repr, SPCSSAttr *css, gchar const *key);
201 void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src);
202 void sp_repr_css_attr_add_from_string(SPCSSAttr *css, const gchar *data);
203 void sp_repr_css_change(Inkscape::XML::Node *repr, SPCSSAttr *css, gchar const *key);
204 void sp_repr_css_change_recursive(Inkscape::XML::Node *repr, SPCSSAttr *css, gchar const *key);
206 void sp_repr_css_print(SPCSSAttr *css);
208 /* Utility finctions */
209 /// Remove \a repr from children of its parent node.
210 inline void sp_repr_unparent(Inkscape::XML::Node *repr) {
211 Inkscape::XML::Node *parent=repr->parent();
212 if (parent) {
213 parent->removeChild(repr);
214 }
215 }
217 /* Convenience */
218 unsigned sp_repr_get_boolean(Inkscape::XML::Node *repr, gchar const *key, unsigned *val);
219 unsigned sp_repr_get_int(Inkscape::XML::Node *repr, gchar const *key, int *val);
220 unsigned sp_repr_get_double(Inkscape::XML::Node *repr, gchar const *key, double *val);
221 unsigned sp_repr_set_boolean(Inkscape::XML::Node *repr, gchar const *key, unsigned val);
222 unsigned sp_repr_set_int(Inkscape::XML::Node *repr, gchar const *key, int val);
223 unsigned sp_repr_set_css_double(Inkscape::XML::Node *repr, gchar const *key, double val);
224 unsigned sp_repr_set_svg_double(Inkscape::XML::Node *repr, gchar const *key, double val);
226 /// \deprecated !
227 double sp_repr_get_double_attribute(Inkscape::XML::Node *repr, gchar const *key, double def);
228 /// \deprecated !
229 int sp_repr_get_int_attribute(Inkscape::XML::Node *repr, gchar const *key, int def);
230 /* End Deprecated? */
232 int sp_repr_compare_position(Inkscape::XML::Node *first, Inkscape::XML::Node *second);
234 /* Searching */
235 Inkscape::XML::Node *sp_repr_lookup_name(Inkscape::XML::Node *repr,
236 gchar const *name,
237 gint maxdepth = -1);
238 Inkscape::XML::Node *sp_repr_lookup_child(Inkscape::XML::Node *repr,
239 gchar const *key,
240 gchar const *value);
243 Inkscape::XML::Document *sp_repr_document_new_list(GSList *reprs);
245 inline Inkscape::XML::Node *sp_repr_document_first_child(Inkscape::XML::Document const *doc) {
246 return const_cast<Inkscape::XML::Node *>(doc->firstChild());
247 }
249 #endif
252 /*
253 Local Variables:
254 mode:c++
255 c-file-style:"stroustrup"
256 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
257 indent-tabs-mode:nil
258 fill-column:99
259 End:
260 */
261 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :