Code

#include "config.h" too
[inkscape.git] / src / xml / repr-css.cpp
1 /*
2  *   bulia byak <buliabyak@users.sf.net>
3 */ 
4  
5 #define SP_REPR_CSS_C
8 #include <glibmm/ustring.h>
10 #include "xml/repr.h"
11 #include "xml/simple-node.h"
13 using Inkscape::Util::List;
14 using Inkscape::XML::AttributeRecord;
15 using Inkscape::XML::SimpleNode;
16 using Inkscape::XML::Node;
17 using Inkscape::XML::NodeType;
19 struct SPCSSAttrImpl : public SimpleNode, public SPCSSAttr {
20 public:
21     SPCSSAttrImpl() : SimpleNode(g_quark_from_static_string("css")) {}
23     NodeType type() const { return Inkscape::XML::ELEMENT_NODE; }
25 protected:
26     SimpleNode *_duplicate() const { return new SPCSSAttrImpl(*this); }
27 };
29 static void sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr);
31 SPCSSAttr *
32 sp_repr_css_attr_new()
33 {
34     return new SPCSSAttrImpl();
35 }
37 void
38 sp_repr_css_attr_unref(SPCSSAttr *css)
39 {
40     g_assert(css != NULL);
41     Inkscape::GC::release((Node *) css);
42 }
44 SPCSSAttr *sp_repr_css_attr(Node *repr, gchar const *attr)
45 {
46     g_assert(repr != NULL);
47     g_assert(attr != NULL);
49     SPCSSAttr *css = sp_repr_css_attr_new();
50     sp_repr_css_add_components(css, repr, attr);
51     return css;
52 }
54 SPCSSAttr *sp_repr_css_attr_inherited(Node *repr, gchar const *attr)
55 {
56     g_assert(repr != NULL);
57     g_assert(attr != NULL);
59     SPCSSAttr *css = sp_repr_css_attr_new();
61     sp_repr_css_add_components(css, repr, attr);
62     Node *current = sp_repr_parent(repr);
64     while (current) {
65         sp_repr_css_add_components(css, current, attr);
66         current = sp_repr_parent(current);
67     }
69     return css;
70 }
72 static void
73 sp_repr_css_add_components(SPCSSAttr *css, Node *repr, gchar const *attr)
74 {
75     g_assert(css != NULL);
76     g_assert(repr != NULL);
77     g_assert(attr != NULL);
79     char const *data = repr->attribute(attr);
80     sp_repr_css_attr_add_from_string(css, data);
81 }
83 char const *
84 sp_repr_css_property(SPCSSAttr *css, gchar const *name, gchar const *defval)
85 {
86     g_assert(css != NULL);
87     g_assert(name != NULL);
89     char const *attr = ((Node *)css)->attribute(name);
90     return ( attr == NULL
91              ? defval
92              : attr );
93 }
95 bool
96 sp_repr_css_property_is_unset(SPCSSAttr *css, gchar const *name)
97 {
98     g_assert(css != NULL);
99     g_assert(name != NULL);
101     char const *attr = ((Node *)css)->attribute(name);
102     return (attr && !strcmp(attr, "inkscape:unset"));
106 void
107 sp_repr_css_set_property(SPCSSAttr *css, gchar const *name, gchar const *value)
109     g_assert(css != NULL);
110     g_assert(name != NULL);
112     sp_repr_set_attr((Node *) css, name, value);
115 void
116 sp_repr_css_unset_property(SPCSSAttr *css, gchar const *name)
118     g_assert(css != NULL);
119     g_assert(name != NULL);
121     sp_repr_set_attr((Node *) css, name, "inkscape:unset");
124 double
125 sp_repr_css_double_property(SPCSSAttr *css, gchar const *name, double defval)
127     g_assert(css != NULL);
128     g_assert(name != NULL);
130     return sp_repr_get_double_attribute((Node *) css, name, defval);
133 gchar *
134 sp_repr_css_write_string(SPCSSAttr *css)
136     Glib::ustring buffer;
138     for ( List<AttributeRecord const> iter = css->attributeList() ;
139           iter ; ++iter )
140     {
141         if (iter->value && !strcmp(iter->value, "inkscape:unset")) {
142             continue;
143         }
145         buffer.append(g_quark_to_string(iter->key));
146         buffer.push_back(':');
147         buffer.append(iter->value);
148         if (rest(iter)) {
149             buffer.push_back(';');
150         }
151     }
153     return (buffer.empty() ? NULL : g_strdup (buffer.c_str()));
156 void
157 sp_repr_css_set(Node *repr, SPCSSAttr *css, gchar const *attr)
159     g_assert(repr != NULL);
160     g_assert(css != NULL);
161     g_assert(attr != NULL);
163     gchar *value = sp_repr_css_write_string(css);
165     repr->setAttribute(attr, value);
167     if (value) g_free (value);
170 void
171 sp_repr_css_print(SPCSSAttr *css)
173     for ( List<AttributeRecord const> iter = css->attributeList() ;
174           iter ; ++iter )
175     {
176         g_print(g_quark_to_string(iter->key));
177         g_print(":\t");
178         g_print(iter->value);
179         g_print("\n");
180     }
183 void
184 sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src)
186     g_assert(dst != NULL);
187     g_assert(src != NULL);
189     dst->mergeFrom(src, "");
192 void
193 sp_repr_css_attr_add_from_string(SPCSSAttr *css, gchar const *data)
195     if (data != NULL) {
196         char *new_str = g_strdup(data);
197         char **token = g_strsplit(new_str, ";", 0);
198         for (char **ctoken = token; *ctoken != NULL; ctoken++) {
199             char *current = g_strstrip(*ctoken);
200             char *key = current;
201             char *val;
202             for (val = key; *val != '\0'; val++)
203                 if (*val == ':') break;
204             if (*val == '\0') break;
205             *val++ = '\0';
206             key = g_strstrip(key);
207             val = g_strstrip(val);
208             if (*val == '\0') break;
210             /* fixme: CSS specifies that later declarations override earlier ones with the same
211                key.  (Ref: http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order point 4.)
212                Either add a precondition that there are no key duplicates in the string, or get rid
213                of the below condition (documenting the change that data[] will override existing
214                values in *css), or process the list in reverse order. */
215             if (!css->attribute(key))
216                 sp_repr_set_attr((Node *) css, key, val);
217         }
218         g_strfreev(token);
219         g_free(new_str);
220     }
223 void
224 sp_repr_css_change(Node *repr, SPCSSAttr *css, gchar const *attr)
226     g_assert(repr != NULL);
227     g_assert(css != NULL);
228     g_assert(attr != NULL);
230     SPCSSAttr *current = sp_repr_css_attr(repr, attr);
231     sp_repr_css_merge(current, css);
232     sp_repr_css_set(repr, current, attr);
234     sp_repr_css_attr_unref(current);
237 void
238 sp_repr_css_change_recursive(Node *repr, SPCSSAttr *css, gchar const *attr)
240     g_assert(repr != NULL);
241     g_assert(css != NULL);
242     g_assert(attr != NULL);
244     sp_repr_css_change(repr, css, attr);
246     for (Node *child = repr->firstChild(); child != NULL; child = child->next()) {
247         sp_repr_css_change_recursive(child, css, attr);
248     }
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 :