1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package ui; 19 20 import java.awt.BorderLayout; 21 import java.awt.Color; 22 import java.awt.Component; 23 import java.awt.Dimension; 24 import java.awt.Font; 25 import java.awt.Image; 26 import java.awt.event.ActionEvent; 27 import java.awt.event.ActionListener; 28 import java.awt.event.TextEvent; 29 import java.awt.event.TextListener; 30 import java.io.BufferedReader; 31 import java.io.File; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.InputStreamReader; 35 import java.io.UnsupportedEncodingException; 36 import java.net.MalformedURLException; 37 import java.net.URL; 38 import java.util.EventObject; 39 import java.util.Hashtable; 40 import java.util.Iterator; 41 import java.util.Map; 42 import java.util.Vector; 43 44 import javax.swing.BorderFactory; 45 import javax.swing.ImageIcon; 46 import javax.swing.JButton; 47 import javax.swing.JComponent; 48 import javax.swing.JFrame; 49 import javax.swing.JLabel; 50 import javax.swing.JMenu; 51 import javax.swing.JMenuBar; 52 import javax.swing.JMenuItem; 53 import javax.swing.JPanel; 54 import javax.swing.JScrollPane; 55 import javax.swing.JSplitPane; 56 import javax.swing.JTextArea; 57 import javax.swing.JTextField; 58 import javax.swing.JTree; 59 import javax.swing.event.TreeSelectionEvent; 60 import javax.swing.event.TreeSelectionListener; 61 import javax.swing.tree.DefaultTreeCellRenderer; 62 import javax.swing.tree.TreeNode; 63 import javax.swing.tree.TreeSelectionModel; 64 65 import org.w3c.dom.Attr; 66 import org.w3c.dom.Document; 67 import org.w3c.dom.Element; 68 import org.w3c.dom.Node; 69 import org.xml.sax.ErrorHandler; 70 import org.xml.sax.SAXException; 71 import org.xml.sax.SAXParseException; 72 73 /** 74 * A sample DOM Tree Viewer. This sample program illustrates how to 75 * traverse a DOM tree and display it in a Swing JTree View. 76 * 77 * @version $Id: TreeView.java 778248 2009-05-24 22:39:36Z mrglavas $ 78 */ 79 public class TreeView extends JFrame implements ActionListener, TextListener { 80 81 private static final long serialVersionUID = 3688504394090098738L; 82 83 // 84 // Constants 85 // 86 87 static final boolean DEBUG = true; 88 89 /** Default parser name. */ 90 static final String 91 DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.DOMParser"; 92 static int WARNING = 0; 93 static int ERROR=1; 94 static int FATAL_ERROR=2; 95 96 97 static final String title = "TreeViewer"; 98 static final String openString = "Open"; 99 static final String quitString = "Quit"; 100 static final String reloadString = "Reload current XML file"; 101 static final String expandString = "Expand Tree"; 102 static final String collapseString = "Collapse Tree"; 103 104 // 105 // Data 106 // 107 108 ErrorStorer ef; 109 String fname; 110 DOMTree m_tree; 111 JTextArea sourceText, messageText; 112 Vector textLine; 113 FileNameInput fni; 114 DOMParserSaveEncoding parser; 115 Image openFolder; 116 Image closedFolder; 117 Image leafImage; 118 119 /** 120 * Constructor 121 */ TreeView()122 public TreeView() { 123 this(null); 124 } 125 126 /** 127 * Constructor 128 */ TreeView(String uri)129 public TreeView(String uri) { 130 super(uri); 131 openFolder = DefaultImages.createOpenFolderImage(); 132 closedFolder = DefaultImages.createClosedFolderImage(); 133 leafImage = DefaultImages.createLeafImage(); 134 parser = new DOMParserSaveEncoding(); 135 ef = new ErrorStorer(); 136 fname = uri; 137 JMenuBar jmb = new JMenuBar(); 138 JMenu fileMenu = new JMenu("File"); 139 JMenuItem item; 140 141 item = new JMenuItem(openString); 142 fileMenu.add(item); 143 item.addActionListener(this); 144 145 item = new JMenuItem(quitString); 146 fileMenu.add(item); 147 item.addActionListener(this); 148 149 JMenu shortcutMenu = new JMenu("Shortcuts"); 150 151 item = new JMenuItem(expandString); 152 shortcutMenu.add(item); 153 item.addActionListener(this); 154 155 item = new JMenuItem(collapseString); 156 shortcutMenu.add(item); 157 item.addActionListener(this); 158 159 item = new JMenuItem(reloadString); 160 shortcutMenu.add(item); 161 item.addActionListener(this); 162 163 jmb.add(fileMenu); 164 jmb.add(shortcutMenu); 165 setJMenuBar(jmb); 166 167 getContentPane().add(createUI(fname)); 168 169 } 170 171 /** create and return the entire UI from the root TreeNode 172 */ createUI(String filename)173 JComponent createUI(String filename) { 174 if (DEBUG) System.out.println("START createUI:"+filename); 175 176 // create the message panel first so we can send messages to it... 177 messageText = new JTextArea(3,40); 178 messageText.setFont(new Font("dialog", Font.PLAIN, 12)); 179 JPanel messagePanel = new JPanel(new BorderLayout()); 180 messagePanel.add(new JScrollPane(messageText) { 181 private static final long serialVersionUID = 3978426918603075632L; 182 public Dimension getPreferredSize(){ 183 Dimension size = TreeView.this.getSize(); 184 return new Dimension(size.width, size.height / 4); 185 } 186 public Dimension getMinimumSize(){ 187 return new Dimension(100, 100); 188 } 189 }, 190 BorderLayout.CENTER); 191 messagePanel.setBorder(BorderFactory.createCompoundBorder( 192 BorderFactory.createTitledBorder("Messages"), 193 BorderFactory.createEmptyBorder(4, 4, 4, 4) 194 )); 195 196 // create the TextArea for XML source 197 sourceText = new JTextArea(); 198 sourceText.setFont(new Font("monospaced", Font.PLAIN, 12)); 199 sourceText.setBackground(Color.white); 200 sourceText.setForeground(Color.black); 201 sourceText.setSelectedTextColor(Color.black); 202 sourceText.setSelectionColor(Color.red); 203 sourceText.setEditable(false); 204 JPanel sourcePanel = new JPanel(new BorderLayout()); 205 sourcePanel.add(new JScrollPane(sourceText){ 206 private static final long serialVersionUID = 4121135831458068789L; 207 public Dimension getPreferredSize(){ 208 Dimension size = TreeView.this.getSize(); 209 return new Dimension(size.width / 2, size.height * 3 / 5); 210 } 211 public Dimension getMinimumSize(){ 212 return new Dimension(100, 100); 213 } 214 }, 215 BorderLayout.CENTER); 216 sourcePanel.setBorder(BorderFactory.createCompoundBorder( 217 BorderFactory.createTitledBorder("Source View"), 218 BorderFactory.createEmptyBorder(4, 4, 4, 4) 219 )); 220 221 // create the JTree and scroll pane. 222 JPanel treePanel = new JPanel(new BorderLayout()); 223 m_tree = new DOMTree(); 224 m_tree.setCellRenderer(new XMLTreeCellRenderer()); 225 m_tree.getSelectionModel().setSelectionMode 226 (TreeSelectionModel.SINGLE_TREE_SELECTION); 227 228 // Listen for when the selection changes, call nodeSelected(node) 229 m_tree.addTreeSelectionListener( 230 new TreeSelectionListener() { 231 public void valueChanged(TreeSelectionEvent e) { 232 TreeNode node = (TreeNode) 233 (e.getPath().getLastPathComponent()); 234 235 nodeSelected(node); 236 } 237 } 238 ); 239 m_tree.setRowHeight(18); 240 m_tree.setFont(new Font("dialog", Font.PLAIN, 12)); 241 242 treePanel.add(new JScrollPane(m_tree) { 243 private static final long serialVersionUID = 3977860665971126320L; 244 public Dimension getPreferredSize(){ 245 Dimension size = TreeView.this.getSize(); 246 return new Dimension(size.width / 2, size.height * 3 / 5); 247 } 248 public Dimension getMinimumSize(){ 249 return new Dimension(100, 100); 250 } 251 }, 252 BorderLayout.CENTER); 253 254 treePanel.setBorder(BorderFactory.createCompoundBorder( 255 BorderFactory.createTitledBorder("Tree View"), 256 BorderFactory.createEmptyBorder(4, 4, 4, 4) 257 )); 258 259 // refreshUI loads everthything! 260 refreshUI(filename); 261 262 // use the new JSplitPane to dynamically resize... 263 JComponent split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 264 true, treePanel, sourcePanel); 265 266 JComponent mainSplitPane = 267 new JSplitPane(JSplitPane.VERTICAL_SPLIT, 268 true, split, messagePanel); 269 270 if (DEBUG) System.out.println("END createUI:"+filename); 271 return mainSplitPane; 272 } 273 274 /** refreshUI is called when we have a new filename to parse. 275 */ refreshUI(String filename)276 void refreshUI(String filename) { 277 if (DEBUG) System.out.println("START refreshUI:"+filename); 278 279 messageText.selectAll(); 280 messageText.cut(); 281 282 if (filename == null || filename.length() == 0) { 283 messageText.setForeground(Color.red); 284 messageText.append("No input XML filename specified:"+filename+"\n"); 285 return; 286 } 287 288 fname = filename; 289 Document newRoot = getRoot(filename); 290 if (newRoot == null) { 291 messageText.setForeground(Color.red); 292 messageText.append("Unable to get new DOM Tree for:"+filename+"\n"); 293 return; 294 } 295 m_tree.setDocument(newRoot); 296 297 // new Source 298 sourceText.selectAll(); 299 sourceText.cut(); 300 readXMLFile(fname, sourceText); 301 302 setTitle(title+": "+filename); 303 304 if (m_tree!= null) 305 expandTree(); 306 307 308 if (ef != null && ef.getErrorNodes()!=null 309 && ef.getErrorNodes().size() > 0 ) { 310 messageText.setForeground(Color.red); 311 messageText.append("XML source, "+fname+" has errors.\n"); 312 messageText.append("Please click on red Tree View items for details.\n"); 313 /***/ 314 Hashtable errors = ef.getErrorNodes(); 315 Iterator entries = errors.entrySet().iterator(); 316 while (entries.hasNext()) { 317 Map.Entry entry = (Map.Entry) entries.next(); 318 Node node = (Node) entry.getKey(); 319 ParseError parseError = (ParseError) entry.getValue(); 320 messageText.append("node="+node.getNodeName() 321 +", error="+parseError.getMsg()+"\n"); 322 } 323 } 324 if (DEBUG) System.out.println("END refreshUI:"+filename); 325 } 326 327 /** 328 * Invoke the Parser on fname and return the root TreeNode. 329 */ getRoot(String filename)330 public Document getRoot(String filename) { 331 if (DEBUG) System.out.println("START getRoot:"+filename); 332 333 if (filename == null || filename.length() == 0) 334 return null; 335 336 try { 337 // 338 // Reset the Error Storage and handling 339 // 340 341 ef.resetErrors(); 342 parser.setErrorHandler(ef); 343 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); // otherwise parser.getCurrentNode() == null 344 parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true); 345 parser.setFeature("http://apache.org/xml/features/allow-java-encodings", true); 346 parser.parse(filename); 347 Document document = parser.getDocument(); 348 /***/ 349 return document; 350 } catch (Exception e) { 351 System.err.println( "Error: Invalid XML document could not get ROOT" ); 352 System.exit( 1 ); 353 //e.printStackTrace(System.err); 354 } 355 return null; 356 } 357 358 /** read the xml file from filename and append it to the JTextArea 359 */ readXMLFile(String filename, JTextArea ta)360 synchronized void readXMLFile(String filename, JTextArea ta) { 361 362 if (DEBUG) System.out.println("START readXMLFile"+filename); 363 if (filename == null || filename.length() == 0) 364 return; 365 InputStream fis = null; 366 BufferedReader dis = null; 367 try { 368 java.net.URL file = createURL(filename); 369 fis = file.openStream(); 370 371 String javaEncoding = parser.getJavaEncoding(); // get saved java encoding 372 try 373 { 374 dis = new BufferedReader(new InputStreamReader(fis, javaEncoding )); 375 } 376 catch( UnsupportedEncodingException ex ) 377 { 378 dis = new BufferedReader(new InputStreamReader(fis )); 379 } 380 } catch (Exception ex) { 381 System.err.println("ERROR: Xerces.readXMLFile: "+ex); 382 return; 383 } 384 385 String line; 386 int len = 0; 387 textLine = new Vector(); 388 String nl = "\n"; 389 int nllen = nl.length(); 390 StringBuffer sb = new StringBuffer(); 391 392 try{ 393 readline: while ((line = dis.readLine()) != null) { 394 sb.append(line+nl); 395 textLine.addElement(new Integer(len)); 396 len += line.length()+nllen; 397 } 398 ta.append(sb.toString()); 399 } catch (IOException io) { 400 System.err.println(io); 401 return; 402 } 403 404 // relayout because contents have changed 405 //ta.revalidate(); 406 407 if (DEBUG) System.out.println("END readXMLFile"+filename); 408 return; 409 410 } 411 412 /** called when our JTree's nodes are selected. 413 */ nodeSelected(TreeNode treeNode)414 void nodeSelected(TreeNode treeNode) { 415 416 Node node = m_tree.getNode(treeNode); 417 418 if( node == null ) // It is possible to get a null node 419 return; 420 421 StringBuffer sb = new StringBuffer(); 422 messageText.selectAll(); 423 messageText.cut(); 424 425 426 //fix 427 428 //JTextArea sourceText = sourceText; 429 Object errorObject = ef == null ? null : ef.getError(node); 430 if (errorObject != null) { 431 // There *is* an error in this node. 432 messageText.setForeground(Color.red); 433 ParseError eip = (ParseError)errorObject; 434 sb.append("Error: "+eip.getMsg()+"\n"); 435 int lineNo = eip.getLineNo(); 436 int pos = 0; 437 int next = 0; 438 int sizeOfTextLine = textLine.size(); 439 440 if( lineNo < sizeOfTextLine ) 441 { 442 pos = ((Integer)textLine.elementAt(lineNo-1)).intValue(); 443 next = (lineNo == sizeOfTextLine ) ? 444 pos : 445 (((Integer)textLine.elementAt(lineNo)).intValue()); 446 } 447 else 448 { 449 pos = (( Integer) textLine.elementAt( sizeOfTextLine - 1 )).intValue(); 450 next = pos + 2; 451 } 452 453 sourceText.select(pos, next ); 454 //m_textScrollPane.repaint(); 455 } else { 456 messageText.setForeground(Color.black); 457 sourceText.select(0, 0 ); 458 } 459 460 //fix 461 462 463 if (node.getNodeType() == Node.ELEMENT_NODE 464 || node.getNodeType() == Node.TEXT_NODE 465 || node.getNodeType() == Node.CDATA_SECTION_NODE ) 466 { 467 sb.append(node.toString()); 468 } 469 470 messageText.append(sb.toString()); 471 } 472 473 /** called when a the text value has changed in the FileNameInput. 474 * read in new XML file. 475 */ textValueChanged(TextEvent e)476 public void textValueChanged(TextEvent e) { 477 try { 478 if (fni != null) 479 fni.setVisible(false); 480 fname = ((JTextField)e.getSource()).getText(); 481 if (DEBUG) System.out.println("textValueChanged:"+fname); 482 refreshUI(fname); 483 484 } catch (Exception ex) { 485 System.err.println( "Error: while trying to refresh gui" ); 486 System.exit( 1 ); 487 // ex.printStackTrace(); 488 } 489 } 490 491 /** called to handle menu actions. 492 */ actionPerformed(java.awt.event.ActionEvent e)493 public void actionPerformed(java.awt.event.ActionEvent e) { 494 if (DEBUG) System.err.println("ACTION: "+e.getActionCommand()+", "+e.paramString()); 495 496 if (e.getActionCommand().equals(quitString)) { 497 System.exit(0); 498 } 499 else if (e.getActionCommand().equals(openString)) { 500 501 fni = new FileNameInput("Open File"); 502 fni.addTextListener(this); 503 fni.setVisible(true); 504 } 505 else if (e.getActionCommand().equals(expandString)) { 506 expandTree(); 507 } 508 else if (e.getActionCommand().equals(collapseString)) { 509 int rows = m_tree.getRowCount(); 510 for (int i = 0; i < rows; i++) { 511 m_tree.collapseRow(i); 512 } 513 } 514 else 515 //if (e.getActionCommand().equals(reloadString)) { 516 refreshUI(fname); 517 //} 518 } 519 expandTree()520 void expandTree() { 521 int rows = 0; 522 for (int levels=0; levels <= 4; levels++) { 523 rows=m_tree.getRowCount(); 524 for (int i = 0; i < rows; i++) { 525 m_tree.expandRow(i); 526 } 527 } 528 } 529 530 /* 531 * The XMLTreeCellRenderer is an inner class which enables the 532 * highlighting of errors in the tree and shows the gender values 533 * as different icons. 534 */ 535 class XMLTreeCellRenderer extends DefaultTreeCellRenderer { 536 537 private static final long serialVersionUID = 3761130444229720113L; 538 getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus)539 public Component getTreeCellRendererComponent(JTree tree, Object value, 540 boolean selected, boolean expanded, 541 boolean leaf, int row, 542 boolean hasFocus) 543 { 544 Node node = ((DOMTree)tree).getNode(value); 545 Component comp = super.getTreeCellRendererComponent(tree, value, 546 selected, expanded, leaf, row, hasFocus); 547 if (selected) { 548 comp.setBackground(Color.blue); 549 } 550 if (ef != null 551 && ef.getErrorNodes() != null 552 && value != null 553 && node != null 554 && ef.getErrorNodes().containsKey( node )) { 555 comp.setForeground(Color.red); 556 } 557 558 if (node != null) { 559 if (leaf) { 560 setIcon(new ImageIcon(leafImage)); 561 } else if (expanded) { 562 setIcon(new ImageIcon(openFolder)); 563 } else { 564 setIcon(new ImageIcon(closedFolder)); 565 } 566 } 567 if (node != null && node instanceof Element) { 568 569 Element txNode = (Element)node; 570 Attr txAtt = (Attr)txNode.getAttributeNode("gender"); 571 if (txAtt != null) { 572 if (txAtt.getValue().equals("male")) { 573 setIcon(new ImageIcon("male.gif")); 574 } else 575 if (txAtt.getValue().equals("female")) { 576 setIcon(new ImageIcon("female.gif")); 577 } 578 } 579 } 580 581 return comp; 582 } 583 } 584 585 /* 586 * The FileNameInput is an inner class which allows the user 587 * to enter a filename. It exists due to a Swing bug which 588 * has problems with the real file input panel. 589 */ 590 class FileNameInput extends JFrame implements ActionListener { 591 592 private static final long serialVersionUID = 3257562893292615472L; 593 594 JLabel fileLabel; 595 JTextField textField; 596 JButton ok; 597 JButton cancel; 598 Vector textListeners; 599 FileNameInput()600 public FileNameInput() { 601 this(""); 602 } 603 FileNameInput(String title)604 public FileNameInput(String title) { 605 606 super(title); 607 608 fileLabel = new JLabel("Enter XML file name:"); 609 textField = new JTextField(); 610 textField.addActionListener(this); 611 ok = new JButton("ok"); 612 cancel = new JButton("cancel"); 613 JPanel buttonPanel = new JPanel(); 614 buttonPanel.add(ok); 615 buttonPanel.add(cancel); 616 ok.addActionListener(this); 617 cancel.addActionListener(this); 618 getContentPane().add(fileLabel, BorderLayout.NORTH); 619 getContentPane().add(textField, BorderLayout.CENTER); 620 getContentPane().add(buttonPanel, BorderLayout.SOUTH); 621 setSize(400,100); 622 } 623 actionPerformed(ActionEvent e)624 public void actionPerformed(ActionEvent e) { 625 626 if (e.getSource() == ok || e.getSource() == textField) { 627 System.out.println("FileNameInput: pressed OK"); 628 TextEvent event = new TextEvent(textField, TextEvent.TEXT_VALUE_CHANGED); 629 deliverEvent(event); 630 setVisible(false); 631 } else 632 if (e.getSource() == cancel) { 633 System.out.println("FileNameInput: pressed cancel"); 634 setVisible(false); 635 } 636 } 637 638 /** 639 * Adds a TextListener event listener. 640 * 641 * @param listener The listener to add. 642 * 643 * @see #removeTextListener 644 */ addTextListener(TextListener listener)645 public void addTextListener(TextListener listener) { 646 647 // is there anything to do? 648 if (listener == null) 649 return; 650 651 if (textListeners == null) 652 textListeners = new Vector(); 653 654 // add listener 655 textListeners.addElement(listener); 656 } 657 658 /** 659 * Removes a TextListener event listener. 660 * 661 * @param listener The listener to remove. 662 * 663 * @see #addTextListener 664 */ removeTextListener(TextListener listener)665 public void removeTextListener(TextListener listener) { 666 667 // is there anything to do? 668 if (listener == null || textListeners == null) 669 return; 670 671 // add listener 672 textListeners.removeElement(listener); 673 } 674 675 676 /** 677 * This function delivers TextListener events, when the ok 678 * button is clicked. 679 * 680 * @param evt The event to deliver. 681 */ deliverEvent(EventObject evt)682 protected void deliverEvent(EventObject evt) { 683 684 if (evt instanceof TextEvent) { 685 TextEvent event = (TextEvent)evt; 686 687 Vector l; 688 synchronized (textListeners) { l = (Vector)textListeners.clone(); } 689 690 int size = l.size(); 691 for (int i = 0; i < size; i++) 692 ((TextListener)l.elementAt(i)).textValueChanged(event); 693 } 694 } 695 } 696 697 // 698 // Create a URL object from either a URL string or a plain file name. 699 // createURL(String name)700 static URL createURL(String name) throws Exception { 701 try { 702 URL u = new URL(name); 703 return u; 704 } catch (MalformedURLException ex) { 705 } 706 URL u = new URL("file:" + new File(name).getAbsolutePath()); 707 return u; 708 } 709 710 /** 711 * The ErrorStorer maps Nodes to errors. It receives a reference 712 * to the ErrorTreeFactory in the Constructor. 713 * 714 * When error is called, it asks the 715 * ErrorTreeFactory for the current node, and uses this as the 716 * "key" of a Hashtable, with the error as a value. The error 717 * value is wrapped up nicely in an ParseError object. 718 * 719 * It is used in the XML Tutorial to illustrate how to implement 720 * the ErrorListener to provide error storage for later reference. 721 * 722 */ 723 class ErrorStorer 724 implements ErrorHandler 725 726 { 727 728 // 729 // Data 730 // 731 Hashtable errorNodes = null; 732 733 /** 734 * Constructor 735 */ ErrorStorer()736 public ErrorStorer() { 737 } 738 739 /** 740 * The client is is allowed to get a reference to the Hashtable, 741 * and so could corrupt it, or add to it... 742 */ getErrorNodes()743 public Hashtable getErrorNodes() { 744 return errorNodes; 745 } 746 747 /** 748 * The ParseError object for the node key is returned. 749 * If the node doesn't have errors, null is returned. 750 */ getError(Node node)751 public Object getError(Node node) { 752 if (errorNodes == null) 753 return null; 754 return errorNodes.get(node); 755 } 756 757 /** 758 * Reset the error storage. 759 */ resetErrors()760 public void resetErrors() { 761 if (errorNodes != null) 762 errorNodes.clear(); 763 } 764 765 /***/ warning(SAXParseException ex)766 public void warning(SAXParseException ex) { 767 handleError(ex, WARNING); 768 } 769 error(SAXParseException ex)770 public void error(SAXParseException ex) { 771 handleError(ex, ERROR); 772 } 773 fatalError(SAXParseException ex)774 public void fatalError(SAXParseException ex) throws SAXException { 775 handleError(ex, FATAL_ERROR); 776 } 777 handleError(SAXParseException ex, int type)778 private void handleError(SAXParseException ex, int type) { 779 System.out.println("!!! handleError: "+ex.getMessage()); 780 781 StringBuffer errorString = new StringBuffer(); 782 errorString.append("at line number, "); 783 errorString.append(ex.getLineNumber()); 784 errorString.append(": "); 785 errorString.append(ex.getMessage()); 786 787 // Node current = parser.getCurrentNode(); 788 789 Node current = null ; 790 791 try 792 { 793 current = ( Node ) parser.getProperty( "http://apache.org/xml/properties/dom/current-element-node" ); 794 795 } 796 catch( SAXException exception ) 797 { 798 ; 799 } 800 801 if (current == null) { 802 System.err.println("Error in handleError. getCurrentNode()==null!"); 803 return; 804 } 805 806 if (errorNodes == null) 807 errorNodes = new Hashtable(); 808 ParseError previous = (ParseError) errorNodes.get(current); 809 ParseError eip = null; 810 // if a Node already has an error, we accumulate the text here... 811 if (previous != null) { 812 eip = previous; 813 errorString = new StringBuffer(previous.getMsg()+"\n"+errorString.toString()); 814 eip.setMsg(errorString.toString()); 815 } else { 816 eip = new 817 ParseError( 818 ex.getSystemId(), 819 ex.getLineNumber(), 820 ex.getColumnNumber(), 821 "", 822 errorString.toString()); 823 } 824 825 // put it in the Hashtable. 826 errorNodes.put(current, eip); 827 } 828 829 } 830 831 /** 832 * The ParseError class wraps up all the error info from 833 * the ErrorStorer's error method. 834 * 835 * @see ErrorStorer 836 */ 837 class ParseError extends Object { 838 839 // 840 // Data 841 // 842 843 String fileName; 844 int lineNo; 845 int charOffset; 846 Object key; 847 String msg; 848 849 /** 850 * Constructor 851 */ ParseError(String fileName, int lineNo, int charOffset, Object key, String msg)852 public ParseError(String fileName, int lineNo, int charOffset, 853 Object key, 854 String msg) 855 { 856 this. fileName=fileName; 857 this. lineNo=lineNo; 858 this. charOffset=charOffset; 859 this. key=key; 860 this. msg=msg; 861 } 862 863 // 864 // Getters... 865 // getFileName()866 public String getFileName() { return fileName; } getLineNo()867 public int getLineNo() { return lineNo; } getCharOffset()868 public int getCharOffset() { return charOffset;} getKey()869 public Object getKey() { return key; } getMsg()870 public String getMsg() { return msg; } setMsg(String s)871 public void setMsg(String s) { msg = s; } 872 } 873 874 875 // 876 // Main 877 // 878 879 /** Main program entry point. */ main(String argv[])880 public static void main(String argv[]) { 881 882 // vars 883 int parserNameIndex = -1; 884 String parserName = DEFAULT_PARSER_NAME; 885 886 // check parameters 887 for (int i = 0; i < argv.length; i++) { 888 String arg = argv[i]; 889 890 // options 891 if (arg.startsWith("-")) { 892 if (arg.equals("-p")) { 893 if (i == argv.length - 1) { 894 System.err.println("error: missing parser class"); 895 System.exit(1); 896 } 897 parserName = argv[++i]; 898 parserNameIndex = i; 899 continue; 900 } 901 902 if (arg.equals("-h")) { 903 printUsage(); 904 System.exit(1); 905 } 906 } 907 908 // print uri 909 System.err.println(arg+':'); 910 911 JFrame frame = null; 912 if (parserNameIndex == argv.length-1) { 913 // null behaviour is blank screen - eg no JTree, or file dispalyed 914 frame = new TreeView(""); 915 } else { 916 frame = new TreeView(arg); 917 } 918 frame.addWindowListener(new java.awt.event.WindowAdapter() { 919 public void windowClosing(java.awt.event.WindowEvent e) { 920 System.exit(0); 921 } 922 }); 923 frame.setSize(790, 590); 924 frame.setVisible(true); 925 } 926 } // main(String[]) 927 928 /** Prints the usage. */ printUsage()929 private static void printUsage() { 930 931 System.err.println("usage: java ui.TreeViewer (options) uri ..."); 932 System.err.println(); 933 System.err.println("options:"); 934 System.err.println(" -p name Specify DOM parser class by name."); 935 System.err.println(" Default parser: "+DEFAULT_PARSER_NAME); 936 System.err.println(" -h This help screen."); 937 938 } // printUsage() 939 940 } // class TreeViewer 941