001: package com.xoetrope.svgscanner.model;
002:
003: import java.io.BufferedReader;
004: import java.io.FileReader;
005: import java.util.ArrayList;
006: import java.util.Enumeration;
007: import java.util.HashMap;
008: import java.util.Hashtable;
009: import java.util.Vector;
010: import net.xoetrope.xml.XmlElement;
011: import net.xoetrope.xml.XmlSource;
012: import net.xoetrope.xml.nanoxml.NanoXmlElement;
013: import net.xoetrope.xui.XProject;
014:
015: /**
016: * <p>A Wrapper for the synth.xml file, allowing manipulation of the various
017: * nodes.</p>
018: *
019: * <p>The model builds up a set of references to all the 'bind' elements in the
020: * synth file. For regions (the only bind type suppoorted so far) the 'bind'
021: * elements associate a style with a 'style' and a 'key'.
022: * </p>
023: * <p>The model provides access to the 'bind' and the 'style' elements by id.
024: * Since an individual 'style' element may be used in multiple 'bind' elements a
025: * list of cross references is essatblished so that the SkinBuilder can track
026: * the effect of changing styles.
027: * </p>
028: * <p></p>
029: * <p>Copyright Xoetrope Ltd. (c) 2001-2006. This software is licensed under the
030: * GPL, see license.txt for the full text
031: * </p>
032: * @author luano
033: */
034: public class SynthModel {
035: private XProject currentProject;
036:
037: private String synthFile;
038: private XmlElement synthRoot;
039:
040: private ArrayList<XmlElement> bindings;
041: private ArrayList<CrossReferenceElement> styles;
042:
043: private static HashMap<String, SynthElementHandler> handlers;
044:
045: /**
046: * Creates a new instance of SynthModel
047: * @param file the name of the synth.xml file
048: */
049: public SynthModel(XProject project, String file) {
050: currentProject = project;
051: synthFile = file;
052:
053: init();
054:
055: project.getModel().set("SynthModel", this );
056: setupHandlers();
057: }
058:
059: private void init() {
060: try {
061: synthRoot = XmlSource.read(new BufferedReader(
062: new FileReader(synthFile)));
063:
064: bindings = new ArrayList<XmlElement>();
065: styles = new ArrayList<CrossReferenceElement>();
066:
067: Vector children = synthRoot.getChildren();
068: for (Object obj : children) {
069: XmlElement child = (XmlElement) obj;
070: String tag = child.getName();
071: if (tag.equals("bind"))
072: bindings.add(child);
073: else if (tag.equals("style"))
074: styles.add(new CrossReferenceElement(child));
075: }
076: } catch (Exception ex) {
077: ex.printStackTrace();
078: }
079:
080: crossReference();
081: }
082:
083: public void crossReference() {
084: for (CrossReferenceElement xref : styles)
085: xref.resetUsage();
086:
087: for (XmlElement binding : bindings) {
088: String styleID = binding.getAttribute("style");
089: CrossReferenceElement styleElement = getStyle(styleID);
090: if (styleElement != null)
091: styleElement.usages.add(binding.getAttribute("key"));
092: }
093: }
094:
095: /**
096: * Get the binding element for a particular region
097: * @param region the region key
098: * @return the bind element
099: */
100: public XmlElement getBinding(String region) {
101: for (XmlElement element : bindings) {
102: if (element.getAttribute("key").equals(region))
103: return element;
104: }
105:
106: return null;
107: }
108:
109: /**
110: * Add a new binding
111: * @param type the binding type
112: * @param key the key
113: * @param styleName the name of the style
114: * @return the new binding element
115: */
116: public XmlElement addBinding(String type, String key,
117: String styleName) {
118: NanoXmlElement bindingElement = new NanoXmlElement("bind");
119: bindingElement.setAttribute("type", type);
120: bindingElement.setAttribute("key", key);
121: bindingElement.setAttribute("style", styleName);
122: bindings.add(bindingElement);
123:
124: return bindingElement;
125: }
126:
127: /**
128: * Get the style element for a particular style id
129: * @param style the style id
130: * @return the style element
131: */
132: public CrossReferenceElement getStyle(String style) {
133: for (CrossReferenceElement xref : styles) {
134: if (xref.id.equals(style))
135: return xref;
136: }
137:
138: return null;
139: }
140:
141: /**
142: * Add a new style
143: * @param type the binding type
144: * @param key the key
145: * @param styleName the name of the style
146: * @return the new binding element
147: */
148: public XmlElement addStyle(String id) {
149: NanoXmlElement styleElement = new NanoXmlElement("style");
150: styleElement.setAttribute("id", id);
151:
152: styles.add(new CrossReferenceElement(styleElement));
153:
154: return styleElement;
155: }
156:
157: private void setupHandlers() {
158: if (handlers == null) {
159: handlers = new HashMap<String, SynthElementHandler>();
160: handlers.put("property", new PropertyElementHandler());
161: handlers.put("defaultsProperty",
162: new DefaultsPropertyElementHandler());
163: handlers.put("state", new StateElementHandler());
164: handlers.put("font", new FontElementHandler());
165: handlers.put("graphicsUtils",
166: new GraphicsUtilsElementHandler());
167: handlers.put("insets", new InsetsElementHandler());
168: handlers.put("painter", new PainterElementHandler());
169: handlers.put("imagePainter",
170: new ImagePainterElementHandler());
171: handlers.put("opaque", new OpaqueElementHandler());
172: handlers.put("inputMap", new InputMapElementHandler());
173: handlers.put("object", new ObjectElementHandler());
174: handlers.put("imageIcon", new ImageIconElementHandler());
175: handlers.put("color", new ColorElementHandler());
176: }
177: }
178:
179: /**
180: * Get the XML for the synth model.
181: * @return the XML
182: */
183: public XmlElement getXml() {
184: XmlElement rootElement = new NanoXmlElement("synth");
185: Hashtable<String, XmlElement> outputStyles = new Hashtable<String, XmlElement>();
186:
187: for (XmlElement bindingElement : bindings) {
188: String styleName = bindingElement.getAttribute("style");
189: if (outputStyles.get(styleName) == null) {
190: XmlElement styleElement = (XmlElement) getStyle(styleName).element
191: .clone();
192: outputStyles.put(styleName, styleElement);
193: rootElement.addChild(styleElement);
194: }
195: rootElement.addChild((XmlElement) bindingElement.clone());
196: }
197:
198: return rootElement;
199: }
200:
201: /**
202: * Deep copy the xml element
203: */
204: // private XmlElement cloneXmlElement( XmlElement xml )
205: // {
206: // NanoXmlElement nxml = new NanoXmlElement( xml.getName());
207: // // Setting the content seems to wipe the children LOC 04/03/2007
208: // String content = xml.getContent();
209: // if ( content != null ) {
210: // content.trim();
211: // if ( content.length() > 0 )
212: // nxml.setContent( content );
213: // }
214: //
215: // Enumeration keys = xml.getAttributes().keys();
216: // while ( keys.hasMoreElements()) {
217: // String attribName = keys.nextElement().toString();
218: // nxml.setAttribute( attribName, xml.getAttribute( attribName ));
219: // }
220: //
221: // Vector kids = xml.getChildren();
222: // for ( Object o : kids )
223: // nxml.addChild( cloneXmlElement( (XmlElement)o ));
224: //
225: // return nxml;
226: // }
227: /**
228: * Get the name of the available styles
229: * @return the style array
230: */
231: public ArrayList<String> getStyleNames() {
232: ArrayList<String> names = new ArrayList<String>();
233:
234: for (CrossReferenceElement xref : styles) {
235: names.add(xref.id);
236: }
237:
238: return names;
239: }
240:
241: /**
242: * A reference to a (style) element and its usage.
243: */
244: public class CrossReferenceElement {
245: public XmlElement element;
246: public ArrayList<String> usages;
247: public String id;
248:
249: public CrossReferenceElement(XmlElement e) {
250: element = e;
251: id = e.getAttribute("id");
252: usages = new ArrayList<String>();
253: }
254:
255: public void resetUsage() {
256: usages = new ArrayList<String>();
257: }
258:
259: }
260:
261: public static SynthElementHandler getElementHandler(String name) {
262: return handlers.get(name);
263: }
264: }
|