| /* |
| * 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. |
| */ |
| package dom.traversal; |
| |
| import java.awt.BorderLayout; |
| import java.awt.Dimension; |
| import java.awt.Font; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.util.Enumeration; |
| import java.util.Hashtable; |
| |
| import javax.swing.BorderFactory; |
| import javax.swing.JButton; |
| import javax.swing.JCheckBox; |
| import javax.swing.JFrame; |
| import javax.swing.JList; |
| import javax.swing.JPanel; |
| import javax.swing.JScrollPane; |
| import javax.swing.JTextArea; |
| import javax.swing.JTextField; |
| import javax.swing.event.ListSelectionEvent; |
| import javax.swing.event.ListSelectionListener; |
| import javax.swing.event.TreeSelectionEvent; |
| import javax.swing.event.TreeSelectionListener; |
| import javax.swing.tree.DefaultTreeModel; |
| import javax.swing.tree.MutableTreeNode; |
| import javax.swing.tree.TreeNode; |
| import javax.swing.tree.TreePath; |
| import javax.swing.tree.TreeSelectionModel; |
| |
| import org.apache.xerces.parsers.DOMParser; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.traversal.DocumentTraversal; |
| import org.w3c.dom.traversal.NodeFilter; |
| import org.w3c.dom.traversal.TreeWalker; |
| 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. |
| * |
| * @version $Id$ |
| */ |
| public class TreeWalkerView |
| extends JFrame |
| implements ActionListener { |
| |
| private static final long serialVersionUID = 3257566187583189559L; |
| |
| 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.isSupported("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) { |
| private static final long serialVersionUID = 3545240236637305138L; |
| 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.length() == 0) { |
| 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); |
| } |
| } |
| |
| } |