package org.korsakow.ide.ui.laf; import java.awt.Color; import java.awt.Font; import java.awt.Insets; import java.awt.font.TextAttribute; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.plaf.ColorUIResource; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import org.korsakow.ide.DomHelper; import org.korsakow.ide.util.DomUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class LafProperties { private static final String ROOT = "/laf"; private static final String PATH_SEPARATOR = "/"; private static final Map<String, TextAttribute> FONT_ATTRIBUTES = new HashMap<String, TextAttribute>(); { FONT_ATTRIBUTES.put("family", TextAttribute.FAMILY); FONT_ATTRIBUTES.put("size", TextAttribute.SIZE); FONT_ATTRIBUTES.put("weight", TextAttribute.WEIGHT); // attributes.put("", TextAttribute.); // attributes.put("", TextAttribute.); // attributes.put("", TextAttribute.); } private Document document; private DomHelper helper; public LafProperties(InputStream input) throws LafException { try { document = DomUtil.parseXML(input); helper = new DomHelper(document); } catch (IOException e) { throw new LafException(e); } catch (SAXException e) { throw new LafException(e); } catch (ParserConfigurationException e) { throw new LafException(e); } } private Insets parseInsets(String key) throws XPathExpressionException { Element elm = helper.xpathAsElement(key); int left = helper.getInt(elm, "left"); int top = helper.getInt(elm, "top"); int right = helper.getInt(elm, "right"); int bottom = helper.getInt(elm, "bottom"); Insets insets = new Insets(top, left, bottom, right); return insets; } private Font parseFont(String key) throws XPathExpressionException { Map<TextAttribute, Object> atts = new HashMap<TextAttribute, Object>(); NodeList list = helper.xpathAsNodeList(key + "/child::*"); int length = list.getLength(); for (int i = 0; i < length; ++i) { Element element = (Element)list.item(i); String name = element.getTagName(); TextAttribute att = FONT_ATTRIBUTES.get(name); if (att == null) continue; Object value = element.getTextContent(); if (att == TextAttribute.SIZE) { value = Float.parseFloat(value.toString()); } else if (att == TextAttribute.WEIGHT) { value = Float.parseFloat(value.toString()); } atts.put(att, value); } return new Font(atts); } private Color parseColor(String key) throws XPathExpressionException, LafException { Element element = helper.xpathAsElement(key); if (element == null) return null; String value = element.getTextContent(); String format = element.getAttribute("format"); Color color = null; if ("hex".equals(format)) { Integer hex = Integer.valueOf(value, 16); color = new Color(hex, false); } else throw new LafException("unknown color format: " + format); return color; } private Integer parseInteger(String key) throws LafException, XPathExpressionException { Element element = helper.xpathAsElement(key); if (element == null) return null; String value = element.getTextContent(); try { return Integer.valueOf(value, 10); } catch (NumberFormatException e) { throw new LafException(e); } } private Boolean parseBoolean(String key) throws LafException, XPathExpressionException { Element element = helper.xpathAsElement(key); if (element == null) return null; String value = element.getTextContent(); try { return Boolean.valueOf(value); } catch (NumberFormatException e) { throw new LafException(e); } } private static String getLastPathComponent(String path) { String[] bits = path.split(PATH_SEPARATOR); if (bits.length == 0) return path; return bits[bits.length-1]; } private String getLastPathComponentType(String path) throws XPathExpressionException { Node node = helper.xpathAsNode(path + "/attribute::type"); if (node == null) return ""; return node.getNodeValue(); } public Object get(String key) throws LafException { try { return getImpl(ROOT + PATH_SEPARATOR + key); } catch (XPathExpressionException e) { throw new LafException(e); } } public Object getComponent(String key) throws LafException { try { return getImpl(ROOT + PATH_SEPARATOR + "component" + PATH_SEPARATOR + key); } catch (XPathExpressionException e) { throw new LafException(e); } } public Object getDefault(String key) throws LafException { try { return getImpl(ROOT + PATH_SEPARATOR + "default" + PATH_SEPARATOR + key); } catch (XPathExpressionException e) { throw new LafException(e); } } private Object getImpl(String key) throws LafException, XPathExpressionException { if (getLastPathComponentType(key).equals("Font")) { return parseFont(key); } if (getLastPathComponentType(key).equals("Color")) { return parseColor(key); } if (getLastPathComponentType(key).equals("Insets")) { return parseInsets(key); } if (getLastPathComponentType(key).equals("Integer")) { return parseInteger(key); } if (getLastPathComponentType(key).equals("Boolean")) { return parseBoolean(key); } throw new LafException("unknown type: " + key); // if (key.endsWith(FONT_SUFFIX)) { // // } } public Map<String, Object> getDefaultValues() throws XPathExpressionException, LafException { Map<String, Object> map = new HashMap<String, Object>(); NodeList list = helper.xpathAsNodeList(ROOT + "/default/child::*"); int length = list.getLength(); for (int i = 0; i < length; ++i) { Element element = (Element)list.item(i); String tagName = element.getTagName(); Object value = getImpl(ROOT + "/default/" + tagName); map.put(tagName, value); } return map; } public void install(UIDefaults defaults) throws LafException { try { Map<String, Object> defaultValues = getDefaultValues(); installColors(defaults); installComponents(defaults, defaultValues); } catch (XPathExpressionException e) { throw new LafException(e); } } public void installColors(UIDefaults defaults) throws LafException, XPathExpressionException { NodeList complist = helper.xpathAsNodeList(ROOT + "/color/child::*"); int complength = complist.getLength(); for (int i = 0; i < complength; ++i) { Element element = (Element)complist.item(i); String tagName = element.getTagName(); NodeList childlist = DomUtil.getChildElements(element); Color value = parseColor(ROOT + "/color/" + tagName); defaults.put(tagName, new ColorUIResource(value)); } } public void installComponents(UIDefaults defaults, Map<String, Object> defaultValues) throws LafException, XPathExpressionException { NodeList complist = helper.xpathAsNodeList(ROOT + "/component/child::*"); int complength = complist.getLength(); for (int i = 0; i < complength; ++i) { Element element = (Element)complist.item(i); String tagName = element.getTagName(); for (String defaultKey : defaultValues.keySet()) UIManager.put(tagName + "." + defaultKey, defaultValues.get(defaultKey)); NodeList childlist = DomUtil.getChildElements(element); int childlength = childlist.getLength(); for (int j = 0; j < childlength; ++j) { Element childElement = (Element)childlist.item(j); String childName = childElement.getTagName(); Object value = getImpl(ROOT + "/component/" + tagName + "/" + childName); defaults.put(tagName + "." + childName, value); } } } public static class LafException extends Exception { public LafException(String msg) { super(msg); } public LafException(Throwable cause) { super(cause); } } }