/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.Serializable;
import java.util.Hashtable;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import org.w3c.dom.Attr;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Notation;
/**
* DOMTree class to enter every DOM node into a Swing JTree tree. The forward
* and backward mappings between Nodes to TreeNodes are kept.
*
* @version $Id: DOMTreeFull.java 447689 2006-09-19 02:40:36Z mrglavas $
*/
public class DOMTreeFull extends JTree {
private static final long serialVersionUID = 3978144335541975344L;
//
// 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);
} // <init>()
//
// 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 {
private static final long serialVersionUID = 3258131375181018673L;
//
// 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
|