blob: 4694ba9bc78affec4daad6d04dfbe93181512e17 [file] [log] [blame]
/*
* 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
* <http://www.apache.org/>.
*/
package dom.traversal;
import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import org.apache.xerces.parsers.*;
import org.w3c.dom.*;
import org.w3c.dom.traversal.*;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import ui.DOMTreeFull;
/** This class shows a DOM Document in a JTree, and presents controls
* which allow the user to create and view the progress of a TreeWalker
* in the DOM tree.
*/
public class TreeWalkerView
extends JFrame
implements ActionListener {
Document document;
TreeNode lastSelected;
DOMParser parser;
JTextArea messageText;
JScrollPane messageScroll;
DOMTreeFull jtree;
TreeWalker treeWalker;
NameNodeFilter nameNodeFilter;
JButton nextButton;
JButton prevButton;
JButton removeButton;
JButton addButton;
JTextField addText;
JButton newIterator;
JList whatToShow;
JCheckBox match;
JTextField nameFilter;
// treeWalker specific buttons
JButton parentButton;
JButton nextSiblingButton;
JButton previousSiblingButton;
JButton firstChildButton;
JButton lastChildButton;
JButton currentButton;
String whatArray[] = new String [] {
"ALL",
"ELEMENT",
"ATTRIBUTE",
"TEXT",
"CDATA_SECTION",
"ENTITY_REFERENCE",
"ENTITY",
"PROCESSING_INSTRUCTION",
"COMMENT",
"DOCUMENT",
"DOCUMENT_TYPE",
"DOCUMENT_FRAGMENT",
"NOTATION"
};
JCheckBox expandERs;
/** main */
public static void main (String args[]) {
if (args.length > 0) {
String filename = args[0];
try {
TreeWalkerView frame = new TreeWalkerView(filename) ;
frame.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent e) {
System.exit(0);
}
});
frame.setSize(640, 700);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
Hashtable treeNodeMap = new Hashtable();
/** Constructor */
public TreeWalkerView (String filename) {
super("TreeWalkerView: "+filename);
try {
parser = new DOMParser();
parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true);
Errors errors = new Errors();
parser.setErrorHandler(errors);
parser.parse(filename);
document = parser.getDocument();
if (!document.supports("Traversal", "2.0")) {
// This cannot happen with the DOMParser...
throw new RuntimeException("This DOM Document does not support Traversal");
}
// jtree UI setup
jtree = new DOMTreeFull((Node)document);
jtree.getSelectionModel().setSelectionMode
(TreeSelectionModel.SINGLE_TREE_SELECTION);
// Listen for when the selection changes, call nodeSelected(node)
jtree.addTreeSelectionListener(
new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
TreePath path = (TreePath)e.getPath();
TreeNode treeNode = (TreeNode)path.getLastPathComponent();
if(jtree.getSelectionModel().isPathSelected(path))
nodeSelected(treeNode);
}
}
);
//
// controls
//
BorderLayout borderLayout = new BorderLayout();
//iterate panel
JPanel iteratePanel = new JPanel();
iteratePanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Document Order Traversal"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
prevButton = new JButton("Previous");
iteratePanel.add(prevButton);
prevButton.addActionListener(this);
nextButton = new JButton("Next");
iteratePanel.add(nextButton);
nextButton.addActionListener(this);
//walkerPanel
JPanel walkerPanel = new JPanel();
walkerPanel.setLayout(new BorderLayout());
walkerPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Walk"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
parentButton = new JButton("Parent");
walkerPanel.add(parentButton, BorderLayout.NORTH);
parentButton.addActionListener(this);
JPanel childPanel = new JPanel();
firstChildButton = new JButton("First Child");
childPanel.add(firstChildButton);
firstChildButton.addActionListener(this);
lastChildButton = new JButton("Last Child");
childPanel.add(lastChildButton);
lastChildButton.addActionListener(this);
walkerPanel.add(childPanel, BorderLayout.SOUTH);
nextSiblingButton = new JButton("Next Sibling");
walkerPanel.add(nextSiblingButton, BorderLayout.EAST);
nextSiblingButton.addActionListener(this);
previousSiblingButton = new JButton("Previous Sibling");
walkerPanel.add(previousSiblingButton, BorderLayout.WEST);
previousSiblingButton.addActionListener(this);
//DOM tree panel
JPanel domPanel = new JPanel();
domPanel.setLayout(new BorderLayout());
domPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Selected Node"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
JPanel buttonPanel = new JPanel();
currentButton = new JButton("Current");
buttonPanel.add(currentButton);
currentButton.addActionListener(this);
removeButton = new JButton("Remove");
buttonPanel.add(removeButton);
removeButton.addActionListener(this);
addButton = new JButton("Append Text");
addText = new JTextField(10);
buttonPanel.add(addButton);
domPanel.add(buttonPanel, BorderLayout.NORTH);
domPanel.add(addText, BorderLayout.CENTER);
addButton.addActionListener(this);
// treeWalker settings
JPanel settingsPanel = new JPanel();
settingsPanel.setLayout(new BorderLayout());
settingsPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Filter Settings"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
JPanel treeWalkerPanel = new JPanel();
treeWalkerPanel.setLayout(new BorderLayout());
newIterator = new JButton("createTreeWalker");
treeWalkerPanel.add(newIterator, BorderLayout.NORTH);
expandERs = new JCheckBox("expandEntityReferences");
expandERs.setSelected(true);
treeWalkerPanel.add(expandERs, BorderLayout.SOUTH);
settingsPanel.add(treeWalkerPanel, BorderLayout.NORTH);
newIterator.addActionListener(this);
JPanel whatPanel = new JPanel();
whatPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("whatToShow"),
BorderFactory.createEmptyBorder(0, 0, 0, 0)
));
whatToShow = new JList(whatArray);
JScrollPane whatScroll =
new JScrollPane(whatToShow) {
public Dimension getPreferredSize(){
return new Dimension(200, 65 );
}
};
whatPanel.add(whatScroll);
JPanel filterPanel = new JPanel();
filterPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("NodeNameFilter"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
filterPanel.setLayout(new BorderLayout());
match = new JCheckBox("match/ignore node name", true);
nameFilter = new JTextField(10);
filterPanel.add(match, BorderLayout.NORTH);
filterPanel.add(nameFilter, BorderLayout.SOUTH);
settingsPanel.add(treeWalkerPanel, BorderLayout.NORTH);
settingsPanel.add(whatPanel, BorderLayout.CENTER);
settingsPanel.add(filterPanel, BorderLayout.SOUTH);
// Listen for when the selection changes, call nodeSelected(node)
whatToShow.addListSelectionListener(
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
// do nothing on selection...
}
}
);
JPanel controlsPanel = new JPanel(new BorderLayout());
controlsPanel.setFont(new Font("Dialog", Font.PLAIN, 8));
JPanel buttonsPanel = new JPanel(new BorderLayout());
buttonsPanel.add(iteratePanel, BorderLayout.NORTH);
buttonsPanel.add(walkerPanel, BorderLayout.CENTER);
buttonsPanel.add(domPanel, BorderLayout.SOUTH);
controlsPanel.add(buttonsPanel, BorderLayout.NORTH);
controlsPanel.add(settingsPanel, BorderLayout.CENTER);
controlsPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Controls"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
// tree panel
JPanel treePanel = new JPanel(new BorderLayout());
JScrollPane treeScroll = new JScrollPane(jtree) ;
treeScroll.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Tree View"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
// message text UI setup
messageText = new JTextArea(3,5);
JPanel messagePanel = new JPanel(new BorderLayout());
messageScroll = new JScrollPane(messageText);
messagePanel.add(messageScroll);
messagePanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createTitledBorder("Messages"),
BorderFactory.createEmptyBorder(4, 4, 4, 4)
));
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
mainPanel.add(controlsPanel, BorderLayout.EAST);
mainPanel.add(treeScroll, BorderLayout.CENTER);
mainPanel.add(messagePanel, BorderLayout.SOUTH);
getContentPane().add(mainPanel);
Hashtable errorNodes = errors.getErrorNodes();
Enumeration elements = errorNodes.elements();
while (elements.hasMoreElements()) {
//*** append errors to messageText
messageText.append( (String)elements.nextElement());
}
boolean expand = expandERs.isSelected();
treeWalker = ((DocumentTraversal)document).
createTreeWalker(
document,
NodeFilter.SHOW_ALL,
new NameNodeFilter(),
expand);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == newIterator) {
TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
if (treeNode == null) {
messageText.append("Must select a tree component.");
return;
}
Node node = jtree.getNode(treeNode);
if (node == null) {
setMessage("No current Node in TreeNode: "+node);
}
// whatToShow section
int [] indices = whatToShow.getSelectedIndices();
int mask = 0x0;
for (int i = 0; i < indices.length; i++) {
if (indices[i] == 0) {
mask = 0xFFFF;
break;
} else {
mask = mask | 1<<indices[i]-1;
}
}
// filter section
String nameText = nameFilter.getText();
boolean matched = match.isSelected();
if (nameNodeFilter==null) {
nameNodeFilter = new NameNodeFilter();
}
if (nameText.equals("")) {
setMessage("NodeNameFilter name is \"\". Assuming null.");
nameText = null;
}
nameNodeFilter.setName(nameText);
nameNodeFilter.setMatch(matched);
// expand Entity References?
boolean expand = expandERs.isSelected();
treeWalker = ((DocumentTraversal)document).
createTreeWalker(
node,
mask,
nameNodeFilter,
expand);
setMessage("createTreeWalker:"+
" root="+node+
", whatToShow="+mask+
", match="+matched+
", name="+nameText
);
return;
}
if (e.getSource() == currentButton) {
TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
if (treeNode == null) {
messageText.append("Must select a tree component.");
return;
}
Node node = jtree.getNode(treeNode);
if (node == null) {
setMessage("No current Node in TreeNode: "+node);
}
treeWalker.setCurrentNode(node);
return;
}
if (e.getSource() == addButton) {
String text = addText.getText();
if (text==null) return;
TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
if (treeNode == null) {
messageText.append("Must select a tree component to add a child to it.");
return;
}
TreePath path = new TreePath(
((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
if (path == null) {
setMessage("Could not create a path.");
return;
}
if(!jtree.getSelectionModel().isPathSelected(path))
return;
Node node = jtree.getNode(treeNode);
Node textNode = document.createTextNode(text);
try {
node.appendChild(textNode);
} catch (DOMException dome) {
setMessage("DOMException:"+dome.code+", "+dome);
return;
}
((DOMTreeFull.Model)jtree.getModel()).insertNode(textNode, (MutableTreeNode)treeNode);
return;
}
if (e.getSource() == removeButton) {
/** If the node is not selected don't remove. */
TreeNode treeNode = (TreeNode)jtree.getLastSelectedPathComponent();
if (treeNode == null) {
messageText.append("Must select a tree component to remove it.");
return;
}
TreePath path = new TreePath(
((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
if (path == null) {
setMessage("Could not create a path.");
return;
}
if(!jtree.getSelectionModel().isPathSelected(path))
return;
Node node = jtree.getNode(treeNode);
if (node == null) return;
Node parent = node.getParentNode();
if (parent == null) return;
parent.removeChild(node);
((DefaultTreeModel)jtree.getModel()).removeNodeFromParent((MutableTreeNode)treeNode);
return;
}
if (e.getSource() == previousSiblingButton) {
Node node = treeWalker.previousSibling();
handleButton(node, "previousSibling()");
return;
}
if (e.getSource() == firstChildButton) {
Node node = treeWalker.firstChild();
handleButton(node, "firstChild()");
return;
}
if (e.getSource() == lastChildButton) {
Node node = treeWalker.lastChild();
handleButton(node, "lastChild()");
return;
}
if (e.getSource() == nextSiblingButton) {
Node node = treeWalker.nextSibling();
handleButton(node, "nextSibling()");
return;
}
if (e.getSource() == parentButton) {
Node node = treeWalker.parentNode();
handleButton(node, "parentNode()");
return;
}
if (e.getSource() == nextButton) {
Node node = treeWalker.nextNode();
handleButton(node, "nextNode()");
return;
}
if (e.getSource() == prevButton) {
Node node = treeWalker.previousNode();
handleButton(node, "previousNode()");
return;
}
}
/** handle a button press: output messages and select node. */
void handleButton( Node node, String function) {
setMessage("treeWalker."+function+" == "+node);
if (node==null) return;
TreeNode treeNode = jtree.getTreeNode(node);
if (treeNode == null) {
setMessage("No JTree TreeNode for Node name:" + node.getNodeName());
return;
}
TreePath path = new TreePath(
((DefaultTreeModel)jtree.getModel()).getPathToRoot(treeNode));
jtree.requestFocus();
jtree.setSelectionPath(path);
jtree.scrollPathToVisible(path);
}
/** Helper function to set messages */
void setMessage(String string) {
messageText.selectAll();
messageText.cut();
messageText.append(string);
messageText.setCaretPosition(0);
}
/** called when our JTree's nodes are selected.
*/
void nodeSelected(TreeNode treeNode) {
lastSelected = treeNode;
Node node = jtree.getNode(treeNode);
if (node == null) return;
setMessage(DOMTreeFull.toString(node));
}
/** Utility function to expand the jtree */
void expandTree() {
for (int i = 0; i < jtree.getRowCount(); i++) {
jtree.expandRow(i);
}
}
class Errors implements ErrorHandler {
Hashtable errorNodes = new Hashtable();
public void warning(SAXParseException ex) {
store(ex, "[Warning]");
}
public void error(SAXParseException ex) {
store(ex, "[Error]");
}
public void fatalError(SAXParseException ex) throws SAXException {
store(ex, "[Fatal Error]");
}
public Hashtable getErrorNodes() {
return errorNodes;
}
public Object getError(Node node) {
return errorNodes.get(node);
}
public void clearErrors() {
errorNodes.clear();
}
void store(SAXParseException ex, String type) {
// build error text
String errorString= type+" at line number, "+ex.getLineNumber()
+": "+ex.getMessage()+"\n";
Node currentNode = null;
try {
currentNode = (Node)parser.getProperty("http://apache.org/xml/properties/dom-node");
} catch (SAXException se) {
System.err.println(se.getMessage());
return;
}
if (currentNode == null) return;
// accumulate any multiple errors per node in the Hashtable.
String previous = (String) errorNodes.get(currentNode);
if (previous != null)
errorNodes.put(currentNode, previous +errorString);
else
errorNodes.put(currentNode, errorString);
}
}
}