1 package org.vectomatic.dev.svg.impl.gen;
2
3 import java.util.ArrayList;
4 import java.util.HashSet;
5 import java.util.List;
6 import java.util.Set;
7
8 import org.vectomatic.dom.svg.ui.SVGResource;
9 import org.vectomatic.dom.svg.ui.SVGButtonBase.SVGFace;
10 import org.vectomatic.dom.svg.ui.SVGButtonBase.SVGFaceName;
11 import org.vectomatic.dom.svg.ui.SVGButtonBase.SVGStyleChange;
12 import org.vectomatic.dom.svg.utils.OMSVGParser;
13 import org.vectomatic.dom.svg.utils.SVGConstants;
14 import org.w3c.dom.Element;
15 import org.w3c.dom.Node;
16 import org.w3c.dom.NodeList;
17
18 import com.google.gwt.core.ext.UnableToCompleteException;
19 import com.google.gwt.core.ext.typeinfo.JClassType;
20 import com.google.gwt.uibinder.elementparsers.ElementParser;
21 import com.google.gwt.uibinder.elementparsers.SvgInterpreter;
22 import com.google.gwt.uibinder.rebind.UiBinderWriter;
23 import com.google.gwt.uibinder.rebind.XMLElement;
24
25 public class SVGButtonBaseParser implements ElementParser {
26 protected static final String ATTR_RESOURCE = "resource";
27 protected static final String ATTR_CLASS_NAME_BASE_VAL = "classNameBaseVal";
28 protected static final String ATTR_CLASS_NAMES = "classNames";
29 protected static final String ATTR_VALIDATED = "validated";
30 protected static final String TAG_ELEMENT = "element";
31 protected static final String TAG_UP = "upFace";
32 protected static final String TAG_UP_HOVERING = "upHoveringFace";
33 protected static final String TAG_UP_DISABLED = "upDisabledFace";
34 protected static final String TAG_DOWN = "downFace";
35 protected static final String TAG_DOWN_HOVERING = "downHoveringFace";
36 protected static final String TAG_DOWN_DISABLED = "downDisabledFace";
37 protected static final String TAG_STYLE_CHANGE = "styleChange";
38 protected static final String URI_VECTOMATIC = "urn:import:org.vectomatic.dom.svg.ui";
39
40
41
42
43
44
45
46
47
48
49
50 protected boolean validate(UiBinderWriter writer, Element container) throws UnableToCompleteException {
51 boolean hasInlineSvg = false;
52 NodeList childNodes = container.getChildNodes();
53 Set<SVGFaceName> faces = new HashSet<SVGFaceName>();
54 for (int i = 0, size = childNodes.getLength(); i < size; i++) {
55 Node childNode = childNodes.item(i);
56 if (childNode.getNodeType() == Node.ELEMENT_NODE) {
57 Element childElem = (Element)childNode;
58 if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_ELEMENT.equals(childElem.getLocalName())) {
59 if (hasInlineSvg) {
60 writer.die("Only one nested SVG element is allowed for %s", container.getTagName());
61 } else {
62 hasInlineSvg = true;
63 }
64 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_UP.equals(childElem.getLocalName())) {
65 if (faces.contains(SVGFaceName.UP)) {
66 writer.die("Multiple definitions for face %s", childElem.getTagName());
67 } else {
68 faces.add(SVGFaceName.UP);
69 }
70 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_UP_HOVERING.equals(childElem.getLocalName())) {
71 if (faces.contains(SVGFaceName.UP_HOVERING)) {
72 writer.die("Multiple definitions for face %s", childElem.getTagName());
73 } else {
74 faces.add(SVGFaceName.UP_HOVERING);
75 }
76 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_UP_DISABLED.equals(childElem.getLocalName())) {
77 if (faces.contains(SVGFaceName.UP_DISABLED)) {
78 writer.die("Multiple definitions for face %s", childElem.getTagName());
79 } else {
80 faces.add(SVGFaceName.UP_DISABLED);
81 }
82 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_DOWN.equals(childElem.getLocalName())) {
83 if (faces.contains(SVGFaceName.DOWN)) {
84 writer.die("Multiple definitions for face %s", childElem.getTagName());
85 } else {
86 faces.add(SVGFaceName.DOWN);
87 }
88 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_DOWN_HOVERING.equals(childElem.getLocalName())) {
89 if (faces.contains(SVGFaceName.DOWN_HOVERING)) {
90 writer.die("Multiple definitions for face %s", childElem.getTagName());
91 } else {
92 faces.add(SVGFaceName.DOWN_HOVERING);
93 }
94 } else if (URI_VECTOMATIC.equals(childElem.getNamespaceURI()) && TAG_DOWN_DISABLED.equals(childElem.getLocalName())) {
95 if (faces.contains(SVGFaceName.DOWN_DISABLED)) {
96 writer.die("Multiple definitions for face %s", childElem.getTagName());
97 } else {
98 faces.add(SVGFaceName.DOWN_DISABLED);
99 }
100 } else {
101 writer.die("Element %s cannot be nested under %s", childElem.getTagName(), container.getTagName());
102 }
103 }
104 }
105 return hasInlineSvg;
106 }
107
108
109 protected void parseFace(XMLElement elem, UiBinderWriter writer, String fieldName,
110 XMLElement childElem, SVGFaceName faceName) throws UnableToCompleteException {
111 for (XMLElement child : childElem.consumeChildElements()) {
112 List<String[]> styleChanges = new ArrayList<String[]>();
113 if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_STYLE_CHANGE.equals(child.getLocalName())) {
114 styleChanges.add((child.hasAttribute(ATTR_CLASS_NAMES))
115 ? child.consumeStringArrayAttribute(ATTR_CLASS_NAMES)
116 : new String[0]);
117 } else {
118 writer.die("Unsupported element %s in face definition", child.getElement().getTagName());
119 }
120 StringBuilder builder = new StringBuilder();
121 builder.append("new ");
122 builder.append(SVGFace.class.getCanonicalName());
123 builder.append("(");
124 builder.append("new ");
125 builder.append(SVGStyleChange.class.getCanonicalName());
126 builder.append("[] {");
127 for (String[] styleChange : styleChanges) {
128 builder.append("new ");
129 builder.append(SVGStyleChange.class.getCanonicalName());
130 builder.append("(new ");
131 builder.append(String.class.getCanonicalName());
132 builder.append("[] {");
133 for (int i = 0; i< styleChange.length; i++) {
134 if (i > 0) {
135 builder.append(", ");
136 }
137 builder.append(styleChange[i]);
138 }
139 builder.append("})");
140 }
141 builder.append("}");
142 builder.append(")");
143 writer.addStatement("%s.addFace(%s.%s, %s);", fieldName, SVGFaceName.class.getCanonicalName(), faceName, builder.toString());
144 }
145 }
146
147 protected void parseSvg(XMLElement elem, UiBinderWriter writer, String fieldName,
148 XMLElement childElem) throws UnableToCompleteException {
149
150 boolean validated = true;
151 if (childElem.hasAttribute(ATTR_VALIDATED)) {
152 String value = childElem.consumeBooleanAttribute(ATTR_VALIDATED);
153 validated = Boolean.valueOf(value);
154 }
155
156 Element container = childElem.getElement();
157 NodeList childNodes = container.getChildNodes();
158 Element root = null;
159 for (int i = 0, length = childNodes.getLength(); i < length; i++) {
160 Node node = childNodes.item(i);
161 if (node.getNodeType() == Node.ELEMENT_NODE) {
162 if (root == null
163 && SVGConstants.SVG_NAMESPACE_URI.equals(node.getNamespaceURI())
164 && SVGConstants.SVG_SVG_TAG.equals(node.getLocalName())) {
165 root = (Element)node;
166 } else {
167 writer.die("%s must contain inline svg", elem);
168 }
169 }
170 }
171 if (root == null) {
172 writer.die("%s must contain inline svg", elem);
173 }
174 writer.beginAttachedSection(fieldName + ".getElement()");
175 SvgInterpreter interpreter = SvgInterpreter.newInterpreterForUiObject(writer, fieldName, root);
176 String rawSvg = childElem.consumeInnerHtml(interpreter);
177 if (validated) {
178 SVGValidator.validate(rawSvg, elem.getLocation().getSystemId(), null, writer);
179 }
180 String omSvgParser = OMSVGParser.class.getCanonicalName();
181 writer.addStatement("%s.setSvgElement(%s.parse(\"%s\"));", fieldName, omSvgParser, rawSvg);
182 writer.endAttachedSection();
183 }
184
185 @Override
186 public void parse(XMLElement elem, String fieldName, JClassType type,
187 UiBinderWriter writer) throws UnableToCompleteException {
188
189 Element container = elem.getElement();
190 boolean hasInlineSvg = validate(writer, container);
191 if (elem.hasAttribute(ATTR_RESOURCE) && hasInlineSvg) {
192 writer.die("In %s, attribute \"%s\" and inline svg are mutually exclusive", elem, ATTR_RESOURCE);
193 }
194 if (!(elem.hasAttribute(ATTR_RESOURCE) || hasInlineSvg)) {
195 writer.die("In %s, attribute \"%s\" or inline svg must be present", elem, ATTR_RESOURCE);
196 }
197 if (elem.hasAttribute(ATTR_RESOURCE)) {
198 JClassType svgResourceType = writer.getOracle().findType(SVGResource.class.getCanonicalName());
199 String resource = elem.consumeAttribute(ATTR_RESOURCE, svgResourceType);
200 writer.addStatement("%s.setResource(%s);", fieldName, resource);
201 }
202 if (elem.hasAttribute(ATTR_CLASS_NAME_BASE_VAL)) {
203 JClassType stringResourceType = writer.getOracle().findType(String.class.getCanonicalName());
204 String resource = elem.consumeAttribute(ATTR_CLASS_NAME_BASE_VAL, stringResourceType);
205 writer.addStatement("%s.setClassNameBaseVal(%s);", fieldName, resource);
206 }
207 for (XMLElement child : elem.consumeChildElements()) {
208 if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_ELEMENT.equals(child.getLocalName())) {
209 parseSvg(elem, writer, fieldName, child);
210 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_UP.equals(child.getLocalName())) {
211 parseFace(elem, writer, fieldName, child, SVGFaceName.UP);
212 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_UP_HOVERING.equals(child.getLocalName())) {
213 parseFace(elem, writer, fieldName, child, SVGFaceName.UP_HOVERING);
214 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_UP_DISABLED.equals(child.getLocalName())) {
215 parseFace(elem, writer, fieldName, child, SVGFaceName.UP_DISABLED);
216 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_DOWN.equals(child.getLocalName())) {
217 parseFace(elem, writer, fieldName, child, SVGFaceName.DOWN);
218 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_DOWN_HOVERING.equals(child.getLocalName())) {
219 parseFace(elem, writer, fieldName, child, SVGFaceName.DOWN_HOVERING);
220 } else if (URI_VECTOMATIC.equals(child.getNamespaceUri()) && TAG_DOWN_DISABLED.equals(child.getLocalName())) {
221 parseFace(elem, writer, fieldName, child, SVGFaceName.DOWN_DISABLED);
222 }
223 }
224 writer.addStatement("%s.showFace(%s.%s);", fieldName, SVGFaceName.class.getCanonicalName(), SVGFaceName.UP.name());
225 }
226
227 }