001/* 002 * Copyright (c) 2004-2007 by Michael Connor. All Rights Reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * o Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * o Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * o Neither the name of FormLayoutBuilder or Michael Connor nor the names of 015 * its contributors may be used to endorse or promote products derived 016 * from this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 027 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030/* 031 * ComponentDef.java 032 * 033 * Created on September 30, 2004, 5:44 PM 034 */ 035 036package org.mlc.swing.layout; 037 038import java.io.IOException; 039import java.io.InputStream; 040import java.util.ArrayList; 041import java.util.Collections; 042import java.util.Enumeration; 043import java.util.HashMap; 044import java.util.List; 045import java.util.Map; 046import java.util.jar.JarEntry; 047import java.util.jar.JarFile; 048 049import javax.swing.Icon; 050import javax.xml.parsers.DocumentBuilder; 051import javax.xml.parsers.DocumentBuilderFactory; 052 053import org.w3c.dom.Document; 054import org.w3c.dom.NamedNodeMap; 055import org.w3c.dom.Node; 056import org.w3c.dom.NodeList; 057 058/** 059 * A container class for all the definition data about a Component. 060 * Instances of this class make up the component palette and are 061 * used when creating and editing component data. 062 * @author Michael Connor 063@version $Id$ 064@since Ptolemy II 8.0 065 */ 066public class ComponentDef implements Comparable<Object> { 067 //private static final long serialVersionUID = 1L; 068 069 public String name = ""; 070 071 public String iconClass = ""; 072 073 public Icon icon = null; 074 075 public String declarations = ""; 076 077 public String configure = ""; 078 079 public String add = ""; 080 081 public String remove = ""; 082 083 public String imports = ""; 084 085 public String preview = ""; 086 087 public boolean isContainer = false; 088 089 private String description = ""; 090 091 public String getDescription() { 092 return description; 093 } 094 095 public ComponentDef() { 096 } 097 098 // Stolen from Xerces 2.5.0 code - need to replace java 1.5 getTextContent method 099 final boolean hasTextContent(Node child) { 100 return child.getNodeType() != Node.COMMENT_NODE 101 && child.getNodeType() != Node.PROCESSING_INSTRUCTION_NODE; 102 // && 103 // (child.getNodeType() != Node.TEXT_NODE ); 104 // || 105 // ((TextImpl) child).isIgnorableWhitespace() == false); 106 } 107 108 // Stolen from Xerces 2.5.0 code - need to replace java 1.5 getTextContent method 109 void getTextContent(Node anode, StringBuffer buf) { 110 Node child = anode.getFirstChild(); 111 while (child != null) { 112 if (hasTextContent(child)) { 113 buf.append(child.getNodeValue()); 114 } 115 child = child.getNextSibling(); 116 } 117 } 118 119 // Stolen from Xerces 2.5.0 code - need to replace java 1.5 getTextContent method 120 private String getTextContent(Node anode) //throws DOMException 121 { 122 Node child = anode.getFirstChild(); 123 if (child != null) { 124 Node next = child.getNextSibling(); 125 if (next == null) { 126 return hasTextContent(child) ? child.getNodeValue() : ""; 127 } 128 StringBuffer buf = new StringBuffer(); 129 getTextContent(anode, buf); 130 return buf.toString(); 131 } 132 return ""; 133 } 134 135 private String doNode(Node parent, String nodeName) { 136 String temp = ""; 137 Node[] nodes = getNodesNamed(parent, nodeName); 138 for (Node node : nodes) { 139 // Java 1.5 library function 140 // temp += nodes[i].getTextContent(); 141 temp += getTextContent(node); 142 } 143 return temp; 144 } 145 146 public ComponentDef(Node componentNode) { 147 Map<String, String> attributes = getAttributeMap(componentNode); 148 name = attributes.get("name"); 149 iconClass = attributes.get("iconClass"); 150 description = attributes.get("desc"); 151 // Java 1.5 library function. 152 // isContainer = Boolean.parseBoolean(attributes.get("container")); 153 String str = attributes.get("container"); 154 if (str != null) { 155 isContainer = str.compareToIgnoreCase("true") == 0; 156 } 157 158 imports = doNode(componentNode, "imports"); 159 declarations = doNode(componentNode, "declarations"); 160 configure = doNode(componentNode, "configure"); 161 remove = doNode(componentNode, "remove"); 162 add = doNode(componentNode, "add"); 163 preview = doNode(componentNode, "preview"); 164 } 165 166 // KBR 12/31/05 Add a ctor for use by the "old-style" new button 167 public ComponentDef(String name, String imp, String decl, String add) { 168 this.name = name; 169 this.imports = imp; 170 this.declarations = decl; 171 this.add = add; 172 } 173 174 private static InputStream getCompFile() { 175 // pull the components.xml file out of the root of the jar file 176 String jarFileName = "formLayoutMakerx.jar"; 177 JarFile jf = null; 178 try { 179 jf = new JarFile(jarFileName); 180 JarEntry je = null; 181 Enumeration entries = jf.entries(); 182 while (entries.hasMoreElements()) { 183 je = (JarEntry) entries.nextElement(); 184 if (je.getName().equals("components.xml")) { 185 return jf.getInputStream(je); 186 } 187 } 188 } catch (IOException e) { 189 return null; 190 } finally { 191 if (jf != null) { 192 try { 193 jf.close(); 194 } catch (IOException ex) { 195 System.out.println( 196 "Failed to close \"" + jarFileName + "\": " + ex); 197 } 198 } 199 } 200 return null; 201 } 202 203 /** Creates a new instance of Component Palette. All component configurations 204 are pulled out of components.xml 205 */ 206 @SuppressWarnings("unchecked") 207 public static List<ComponentDef> createComponentDefs() { 208 List<ComponentDef> components = new ArrayList<ComponentDef>(); 209 InputStream paletteStream = null; 210 try { 211 paletteStream = ComponentDef.class 212 .getResourceAsStream("components.xml"); 213 if (paletteStream == null) { 214 paletteStream = getCompFile(); 215 } 216 if (paletteStream == null) { 217 return components; 218 } 219 220 Document dataDocument = null; 221 222 try { 223 DocumentBuilder documentBuilder = DocumentBuilderFactory 224 .newInstance().newDocumentBuilder(); 225 dataDocument = documentBuilder.parse(paletteStream); 226 Node paletteNode = dataDocument.getDocumentElement(); 227 Node[] componentNodes = getNodesNamed(paletteNode, "component"); 228 229 for (Node componentNode : componentNodes) { 230 components.add(new ComponentDef(componentNode)); 231 } 232 } catch (Exception e) { 233 throw new RuntimeException("Unable to create DocumentBuilder", 234 e); 235 } 236 237 Collections.sort(components); 238 } finally { 239 if (paletteStream != null) { 240 try { 241 paletteStream.close(); 242 } catch (Exception ex) { 243 throw new RuntimeException( 244 "Failed to close paletteStream " + paletteStream, 245 ex); 246 } 247 } 248 } 249 return components; 250 } 251 252 private static Map<String, String> getAttributeMap(Node node) { 253 254 Map<String, String> attributeMap = new HashMap<String, String>(); 255 256 NamedNodeMap attributes = node.getAttributes(); 257 if (attributes != null) { 258 for (int index = 0; index < attributes.getLength(); index++) { 259 Node attribute = attributes.item(index); 260 attributeMap.put(attribute.getNodeName(), 261 attribute.getNodeValue()); 262 } 263 } 264 265 return attributeMap; 266 } 267 268 private static Node[] getNodesNamed(Node parent, String nodeName) { 269 NodeList children = parent.getChildNodes(); 270 List<Node> childList = new ArrayList<Node>(); 271 for (int i = 0; i < children.getLength(); i++) { 272 String childname = children.item(i).getNodeName(); 273 if (childname != null) { 274 if (nodeName.equals(childname)) { 275 childList.add(children.item(i)); 276 } 277 } 278 } 279 Node[] result = new Node[childList.size()]; 280 return childList.toArray(result); 281 } 282 283 public String getConfigure(String name) { 284 return configure.replaceAll("\\$\\{name\\}", name); 285 } 286 287 public String getImports(String name) { 288 return imports.replaceAll("\\$\\{name\\}", name); 289 } 290 291 public String getDeclarations(String name) { 292 return declarations.replaceAll("\\$\\{name\\}", name); 293 } 294 295 public String getAdd(String name) { 296 return add.replaceAll("\\$\\{name\\}", name); 297 } 298 299 /** When dragging from the palette we need a clone rather than modify 300 the original. 301 */ 302 @Override 303 public ComponentDef clone() { 304 ComponentDef newone = new ComponentDef(); 305 newone.name = name; 306 newone.iconClass = iconClass; 307 newone.declarations = declarations; 308 newone.configure = configure; 309 newone.add = add; 310 newone.imports = imports; 311 newone.preview = preview; 312 newone.isContainer = isContainer; 313 return newone; 314 } 315 316 /** Make it sortable on name so the palette is ordered. 317 */ 318 @Override 319 public int compareTo(Object o) { 320 return name.compareTo(((ComponentDef) o).name); 321 } 322 323 public static void main(String[] args) { 324 List<ComponentDef> components = ComponentDef.createComponentDefs(); 325 System.out.println(components); 326 } 327}