View Javadoc

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  	 * Validates the widget structure 
42  	 * @param writer
43  	 * The UiBinder writer
44  	 * @param container
45  	 * The SVG widget top-level tag
46  	 * @return
47  	 * true if the container has inline-svg, false otherwise
48  	 * @throws UnableToCompleteException 
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 }