/* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xerces" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, International * Business Machines, Inc., http://www.apache.org. For more * information on the Apache Software Foundation, please see * . */ package ui; import java.io.Serializable; import java.io.UnsupportedEncodingException; import javax.swing.JTree; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; import org.w3c.dom.*; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Hashtable; import java.util.Enumeration; /** * DOMTree class to enter every DOM node into a Swing JTree tree. * The forward and backward mappings between Nodes to TreeNodes are kept. * */ public class DOMTreeFull extends JTree { // // Constructors // /** Default constructor. */ public DOMTreeFull() { this(null); } /** Constructs a tree with the specified document. */ public DOMTreeFull(Node root) { super(new Model()); // set tree properties setRootVisible(false); // set properties setRootNode(root); } // () // // Public methods // /** Sets the root. */ public void setRootNode(Node root) { ((Model)getModel()).setRootNode(root); expandRow(0); } /** Returns the root. */ public Node getRootNode() { return ((Model)getModel()).getRootNode(); } /** get the org.w3c.Node for a MutableTreeNode. */ public Node getNode(Object treeNode) { return ((Model)getModel()).getNode(treeNode); } /** get the TreeNode for the org.w3c.Node */ public TreeNode getTreeNode(Object node) { return ((Model)getModel()).getTreeNode(node); } // // Classes // /** * DOM tree model. * */ public static class Model extends DefaultTreeModel implements Serializable { // // Data // /** Root. */ private Node root; /** Node Map. */ private Hashtable nodeMap = new Hashtable(); /** Tree Node Map. */ private Hashtable treeNodeMap = new Hashtable(); // // Constructors // /** Default constructor. */ public Model() { this(null); } /** Constructs a model from the specified root. */ public Model(Node node) { super(new DefaultMutableTreeNode()); if (node!=null) setRootNode(node); } // // Public methods // /** Sets the root. */ public synchronized void setRootNode(Node root) { // save root this.root = root; // clear tree and re-populate DefaultMutableTreeNode where = (DefaultMutableTreeNode)getRoot(); where.removeAllChildren(); nodeMap.clear(); treeNodeMap.clear(); buildTree(root, where); fireTreeStructureChanged(this, new Object[] { getRoot() }, new int[0], new Object[0]); } // setRootNode(Node) /** Returns the root. */ public Node getRootNode() { return root; } /** get the org.w3c.Node for a MutableTreeNode. */ public Node getNode(Object treeNode) { return (Node)nodeMap.get(treeNode); } public Hashtable getAllNodes() { return nodeMap; } /** get the org.w3c.Node for a MutableTreeNode. */ public TreeNode getTreeNode(Object node) { Object object = treeNodeMap.get(node); return (TreeNode)object; } // // Private methods // /** Builds the tree. */ private void buildTree(Node node, MutableTreeNode where) { // is there anything to do? if (node == null) { return; } MutableTreeNode treeNode = insertNode(node, where); // iterate over children of this node NodeList nodes = node.getChildNodes(); int len = (nodes != null) ? nodes.getLength() : 0; for (int i = 0; i < len; i++) { Node child = nodes.item(i); buildTree(child, treeNode); } } // buildTree() /** Inserts a node and returns a reference to the new node. */ private MutableTreeNode insertNode(String what, MutableTreeNode where) { MutableTreeNode node = new DefaultMutableTreeNode(what); insertNodeInto(node, where, where.getChildCount()); return node; } // insertNode(Node,MutableTreeNode):MutableTreeNode /** Inserts a text node. */ public MutableTreeNode insertNode(Node what, MutableTreeNode where) { MutableTreeNode treeNode = insertNode(DOMTreeFull.toString(what), where); nodeMap.put(treeNode, what); treeNodeMap.put(what, treeNode); return treeNode; } } // class Model public static String whatArray[] = new String [] { "ALL", "ELEMENT", "ATTRIBUTE", "TEXT", "CDATA_SECTION", "ENTITY_REFERENCE", "ENTITY", "PROCESSING_INSTRUCTION", "COMMENT", "DOCUMENT", "DOCUMENT_TYPE", "DOCUMENT_FRAGMENT", "NOTATION" }; // // Public methods // public static String toString(Node node) { StringBuffer sb = new StringBuffer(); // is there anything to do? if (node == null) { return ""; } int type = node.getNodeType(); sb.append(whatArray[type]); sb.append(" : "); sb.append(node.getNodeName()); String value = node.getNodeValue(); if (value != null) { sb.append(" Value: \""); sb.append(value); sb.append("\""); } switch (type) { // document case Node.DOCUMENT_NODE: { break; } // element with attributes case Node.ELEMENT_NODE: { Attr attrs[] = sortAttributes(node.getAttributes()); if (attrs.length > 0) sb.append(" ATTRS:"); for (int i = 0; i < attrs.length; i++) { Attr attr = attrs[i]; sb.append(' '); sb.append(attr.getNodeName()); sb.append("=\""); sb.append(normalize(attr.getNodeValue())); sb.append('"'); } sb.append('>'); break; } // handle entity reference nodes case Node.ENTITY_REFERENCE_NODE: { break; } // cdata sections case Node.CDATA_SECTION_NODE: { break; } // text case Node.TEXT_NODE: { break; } // processing instruction case Node.PROCESSING_INSTRUCTION_NODE: { break; } // comment node case Node.COMMENT_NODE: { break; } // DOCTYPE node case Node.DOCUMENT_TYPE_NODE: { break; } // Notation node case Node.NOTATION_NODE: { sb.append("public:"); String id = ((Notation)node).getPublicId(); if (id == null) { sb.append("PUBLIC "); sb.append(id); sb.append(" "); } id = ((Notation)node).getSystemId(); if (id == null) { sb.append("system: "); sb.append(id); sb.append(" "); } break; } } return sb.toString(); } /** Normalizes the given string. */ static protected String normalize(String s) { StringBuffer str = new StringBuffer(); int len = (s != null) ? s.length() : 0; for (int i = 0; i < len; i++) { char ch = s.charAt(i); switch (ch) { case '<': { str.append("<"); break; } case '>': { str.append(">"); break; } case '&': { str.append("&"); break; } case '"': { str.append("""); break; } case '\r': case '\n': default: { str.append(ch); } } } return str.toString(); } // normalize(String):String /** Returns a sorted list of attributes. */ static protected Attr[] sortAttributes(NamedNodeMap attrs) { int len = (attrs != null) ? attrs.getLength() : 0; Attr array[] = new Attr[len]; for (int i = 0; i < len; i++) { array[i] = (Attr)attrs.item(i); } for (int i = 0; i < len - 1; i++) { String name = array[i].getNodeName(); int index = i; for (int j = i + 1; j < len; j++) { String curName = array[j].getNodeName(); if (curName.compareTo(name) < 0) { name = curName; index = j; } } if (index != i) { Attr temp = array[i]; array[i] = array[index]; array[index] = temp; } } return array; } // sortAttributes(NamedNodeMap):Attr[] } // class DOMTreeFull