1 57 58 package ui; 59 60 61 import java.awt.BorderLayout ; 62 import java.awt.Color ; 63 import java.awt.Component ; 64 import java.awt.Dimension ; 65 import java.awt.Font ; 66 import java.awt.Image ; 67 import java.awt.event.ActionEvent ; 68 import java.awt.event.ActionListener ; 69 import java.awt.event.TextEvent ; 70 import java.awt.event.TextListener ; 71 import java.io.BufferedReader ; 72 import java.io.File ; 73 import java.io.IOException ; 74 import java.io.InputStream ; 75 import java.io.InputStreamReader ; 76 import java.io.UnsupportedEncodingException ; 77 import java.net.MalformedURLException ; 78 import java.net.URL ; 79 import java.util.Enumeration ; 80 import java.util.EventObject ; 81 import java.util.Hashtable ; 82 import java.util.Vector ; 83 84 import javax.swing.BorderFactory ; 85 import javax.swing.ImageIcon ; 86 import javax.swing.JButton ; 87 import javax.swing.JComponent ; 88 import javax.swing.JFrame ; 89 import javax.swing.JLabel ; 90 import javax.swing.JMenu ; 91 import javax.swing.JMenuBar ; 92 import javax.swing.JMenuItem ; 93 import javax.swing.JPanel ; 94 import javax.swing.JScrollPane ; 95 import javax.swing.JSplitPane ; 96 import javax.swing.JTextArea ; 97 import javax.swing.JTextField ; 98 import javax.swing.JTree ; 99 import javax.swing.event.TreeSelectionEvent ; 100 import javax.swing.event.TreeSelectionListener ; 101 import javax.swing.tree.DefaultTreeCellRenderer ; 102 import javax.swing.tree.TreeNode ; 103 import javax.swing.tree.TreeSelectionModel ; 104 105 import org.w3c.dom.Attr ; 106 import org.w3c.dom.Document ; 107 import org.w3c.dom.Element ; 108 import org.w3c.dom.Node ; 109 import org.xml.sax.ErrorHandler ; 110 import org.xml.sax.SAXException ; 111 import org.xml.sax.SAXParseException ; 112 113 114 115 121 public class TreeView extends JFrame implements ActionListener , TextListener { 122 123 127 static final boolean DEBUG = true; 128 129 130 static final String 131 DEFAULT_PARSER_NAME = "org.enhydra.apache.xerces.parsers.DOMParser"; 132 static int WARNING = 0; 133 static int ERROR=1; 134 static int FATAL_ERROR=2; 135 136 137 static final String title = "TreeViewer"; 138 static final String openString = "Open"; 139 static final String quitString = "Quit"; 140 static final String reloadString = "Reload current XML file"; 141 static final String expandString = "Expand Tree"; 142 static final String collapseString = "Collapse Tree"; 143 144 148 ErrorStorer ef; 149 String fname; 150 DOMTree m_tree; 151 JTextArea sourceText, messageText; 152 Vector textLine; 153 FileNameInput fni; 154 DOMParserSaveEncoding parser; 155 Image openFolder; 156 Image closedFolder; 157 Image leafImage; 158 159 162 public TreeView() { 163 this(null); 164 } 165 166 169 public TreeView(String uri) { 170 super(uri); 171 openFolder = DefaultImages.createOpenFolderImage(); 172 closedFolder = DefaultImages.createClosedFolderImage(); 173 leafImage = DefaultImages.createLeafImage(); 174 parser = new DOMParserSaveEncoding(); 175 ef = new ErrorStorer(); 176 fname = uri; 177 JMenuBar jmb = new JMenuBar (); 178 JMenu fileMenu = new JMenu ("File"); 179 JMenuItem item; 180 181 item = new JMenuItem (openString); 182 fileMenu.add(item); 183 item.addActionListener(this); 184 185 item = new JMenuItem (quitString); 186 fileMenu.add(item); 187 item.addActionListener(this); 188 189 JMenu shortcutMenu = new JMenu ("Shortcuts"); 190 191 item = new JMenuItem (expandString); 192 shortcutMenu.add(item); 193 item.addActionListener(this); 194 195 item = new JMenuItem (collapseString); 196 shortcutMenu.add(item); 197 item.addActionListener(this); 198 199 item = new JMenuItem (reloadString); 200 shortcutMenu.add(item); 201 item.addActionListener(this); 202 203 jmb.add(fileMenu); 204 jmb.add(shortcutMenu); 205 setJMenuBar(jmb); 206 207 getContentPane().add(createUI(fname)); 208 209 } 210 211 213 JComponent createUI(String filename) { 214 if (DEBUG) System.out.println("START createUI:"+filename); 215 216 messageText = new JTextArea (3,40); 218 messageText.setFont(new Font ("dialog", Font.PLAIN, 12)); 219 JPanel messagePanel = new JPanel (new BorderLayout ()); 220 messagePanel.add(new JScrollPane (messageText) { 221 public Dimension getPreferredSize(){ 222 Dimension size = TreeView.this.getSize(); 223 return new Dimension (size.width, size.height / 4); 224 } 225 public Dimension getMinimumSize(){ 226 return new Dimension (100, 100); 227 } 228 }, 229 BorderLayout.CENTER); 230 messagePanel.setBorder(BorderFactory.createCompoundBorder( 231 BorderFactory.createTitledBorder("Messages"), 232 BorderFactory.createEmptyBorder(4, 4, 4, 4) 233 )); 234 235 sourceText = new JTextArea (); 237 sourceText.setFont(new Font ("monospaced", Font.PLAIN, 12)); 238 sourceText.setBackground(Color.white); 239 sourceText.setForeground(Color.black); 240 sourceText.setSelectedTextColor(Color.black); 241 sourceText.setSelectionColor(Color.red); 242 sourceText.setEditable(false); 243 JPanel sourcePanel = new JPanel (new BorderLayout ()); 244 sourcePanel.add(new JScrollPane (sourceText){ 245 public Dimension getPreferredSize(){ 246 Dimension size = TreeView.this.getSize(); 247 return new Dimension (size.width / 2, size.height * 3 / 5); 248 } 249 public Dimension getMinimumSize(){ 250 return new Dimension (100, 100); 251 } 252 }, 253 BorderLayout.CENTER); 254 sourcePanel.setBorder(BorderFactory.createCompoundBorder( 255 BorderFactory.createTitledBorder("Source View"), 256 BorderFactory.createEmptyBorder(4, 4, 4, 4) 257 )); 258 259 JPanel treePanel = new JPanel (new BorderLayout ()); 261 m_tree = new DOMTree(); 262 m_tree.setCellRenderer(new XMLTreeCellRenderer()); 263 m_tree.getSelectionModel().setSelectionMode 264 (TreeSelectionModel.SINGLE_TREE_SELECTION); 265 266 m_tree.addTreeSelectionListener( 268 new TreeSelectionListener () { 269 public void valueChanged(TreeSelectionEvent e) { 270 TreeNode node = (TreeNode ) 271 (e.getPath().getLastPathComponent()); 272 273 nodeSelected(node); 274 } 275 } 276 ); 277 m_tree.setRowHeight(18); 278 m_tree.setFont(new Font ("dialog", Font.PLAIN, 12)); 279 280 treePanel.add(new JScrollPane (m_tree) { 281 public Dimension getPreferredSize(){ 282 Dimension size = TreeView.this.getSize(); 283 return new Dimension (size.width / 2, size.height * 3 / 5); 284 } 285 public Dimension getMinimumSize(){ 286 return new Dimension (100, 100); 287 } 288 }, 289 BorderLayout.CENTER); 290 291 treePanel.setBorder(BorderFactory.createCompoundBorder( 292 BorderFactory.createTitledBorder("Tree View"), 293 BorderFactory.createEmptyBorder(4, 4, 4, 4) 294 )); 295 296 refreshUI(filename); 298 299 JComponent split = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, 301 true, treePanel, sourcePanel); 302 303 JComponent mainSplitPane = 304 new JSplitPane (JSplitPane.VERTICAL_SPLIT, 305 true, split, messagePanel); 306 307 if (DEBUG) System.out.println("END createUI:"+filename); 308 return mainSplitPane; 309 } 310 311 313 void refreshUI(String filename) { 314 if (DEBUG) System.out.println("START refreshUI:"+filename); 315 316 messageText.selectAll(); 317 messageText.cut(); 318 319 if (filename == null || filename.equals("")) { 320 messageText.setForeground(Color.red); 321 messageText.append("No input XML filename specified:"+filename+"\n"); 322 return; 323 } 324 325 fname = filename; 326 Document newRoot = getRoot(filename); 327 if (newRoot == null) { 328 messageText.setForeground(Color.red); 329 messageText.append("Unable to get new DOM Tree for:"+filename+"\n"); 330 return; 331 } 332 m_tree.setDocument(newRoot); 333 334 sourceText.selectAll(); 336 sourceText.cut(); 337 readXMLFile(fname, sourceText); 338 339 setTitle(title+": "+filename); 340 341 if (m_tree!= null) 342 expandTree(); 343 344 345 if (ef != null && ef.getErrorNodes()!=null 346 && ef.getErrorNodes().size() > 0 ) { 347 messageText.setForeground(Color.red); 348 messageText.append("XML source, "+fname+" has errors.\n"); 349 messageText.append("Please click on red Tree View items for details.\n"); 350 351 Hashtable errors = ef.getErrorNodes(); 352 Enumeration keys = errors.keys(); 353 while (keys.hasMoreElements()) { 354 Node node = (Node )keys.nextElement(); 355 messageText.append("node="+node.getNodeName() 356 +", error="+((ParseError)errors.get(node)).getMsg()+"\n"); 357 } 358 } 359 if (DEBUG) System.out.println("END refreshUI:"+filename); 360 } 361 362 365 public Document getRoot(String filename) { 366 if (DEBUG) System.out.println("START getRoot:"+filename); 367 368 if (filename == null || filename.equals("")) 369 return null; 370 371 try { 372 376 ef.resetErrors(); 377 parser.setErrorHandler(ef); 378 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", false); parser.setFeature("http://apache.org/xml/features/continue-after-fatal-error", true); 380 parser.setFeature("http://apache.org/xml/features/allow-java-encodings", true); 381 parser.parse(filename); 382 Document document = parser.getDocument(); 383 384 return document; 385 } catch (Exception e) { 386 System.err.println( "Error: Invalid XML document could not get ROOT" ); 387 System.exit( 1 ); 388 } 390 return null; 391 } 392 393 395 synchronized void readXMLFile(String filename, JTextArea ta) { 396 397 if (DEBUG) System.out.println("START readXMLFile"+filename); 398 if (filename == null || filename.equals("")) 399 return; 400 InputStream fis = null; 401 BufferedReader dis = null; 402 try { 403 java.net.URL file = createURL(filename); 404 fis = file.openStream(); 405 406 String javaEncoding = parser.getJavaEncoding(); try 408 { 409 dis = new BufferedReader (new InputStreamReader (fis, javaEncoding )); 410 } 411 catch( UnsupportedEncodingException ex ) 412 { 413 dis = new BufferedReader (new InputStreamReader (fis )); 414 } 415 } catch (Exception ex) { 416 System.err.println("ERROR: Xerces.readXMLFile: "+ex); 417 return; 418 } 419 420 String line; 421 int i = 0; 422 423 int len = 0; 424 textLine = new Vector (); 425 String nl = "\n"; 426 int nllen = nl.length(); 427 StringBuffer sb = new StringBuffer (); 428 429 try{ 430 readline: while ((line = dis.readLine()) != null) { 431 sb.append(line+nl); 432 textLine.addElement(new Integer (len)); 433 len += line.length()+nllen; 434 } 435 ta.append(sb.toString()); 436 } catch (IOException io) { 437 System.err.println(io); 438 return; 439 } 440 441 444 if (DEBUG) System.out.println("END readXMLFile"+filename); 445 return; 446 447 } 448 449 451 void nodeSelected(TreeNode treeNode) { 452 453 Node node = m_tree.getNode(treeNode); 454 455 if( node == null ) return; 457 458 StringBuffer sb = new StringBuffer (); 459 messageText.selectAll(); 460 messageText.cut(); 461 462 463 465 Object errorObject = ef == null ? null : ef.getError(node); 467 if (errorObject != null) { 468 messageText.setForeground(Color.red); 470 ParseError eip = (ParseError)errorObject; 471 sb.append("Error: "+eip.getMsg()+"\n"); 472 int lineNo = eip.getLineNo(); 473 int pos = 0; 474 int next = 0; 475 int sizeOfTextLine = textLine.size(); 476 477 if( lineNo < sizeOfTextLine ) 478 { 479 pos = ((Integer )textLine.elementAt(lineNo-1)).intValue(); 480 next = (lineNo == sizeOfTextLine ) ? 481 pos : 482 (((Integer )textLine.elementAt(lineNo)).intValue()); 483 } 484 else 485 { 486 pos = (( Integer ) textLine.elementAt( sizeOfTextLine - 1 )).intValue(); 487 next = pos + 2; 488 } 489 490 sourceText.select(pos, next ); 491 } else { 493 messageText.setForeground(Color.black); 494 sourceText.select(0, 0 ); 495 } 496 497 499 500 if (node.getNodeType() == Node.ELEMENT_NODE 501 || node.getNodeType() == Node.TEXT_NODE 502 || node.getNodeType() == Node.CDATA_SECTION_NODE ) 503 { 504 sb.append(node.toString()); 505 } 506 507 messageText.append(sb.toString()); 508 } 509 510 513 public void textValueChanged(TextEvent e) { 514 try { 515 if (fni != null) 516 fni.setVisible(false); 517 fname = ((JTextField )e.getSource()).getText(); 518 if (DEBUG) System.out.println("textValueChanged:"+fname); 519 refreshUI(fname); 520 521 } catch (Exception ex) { 522 System.err.println( "Error: while trying to refresh gui" ); 523 System.exit( 1 ); 524 } 526 } 527 528 530 public void actionPerformed(java.awt.event.ActionEvent e) { 531 if (DEBUG) System.err.println("ACTION: "+e.getActionCommand()+", "+e.paramString()); 532 533 if (e.getActionCommand().equals(quitString)) { 534 System.exit(0); 535 } 536 else if (e.getActionCommand().equals(openString)) { 537 538 fni = new FileNameInput("Open File"); 539 fni.addTextListener(this); 540 fni.setVisible(true); 541 } 542 else if (e.getActionCommand().equals(expandString)) { 543 expandTree(); 544 } 545 else if (e.getActionCommand().equals(collapseString)) { 546 int rows = m_tree.getRowCount(); 547 for (int i = 0; i < rows; i++) { 548 m_tree.collapseRow(i); 549 } 550 } 551 else 552 refreshUI(fname); 554 } 556 557 void expandTree() { 558 int rows = 0; 559 for (int levels=0; levels <= 4; levels++) { 560 rows=m_tree.getRowCount(); 561 for (int i = 0; i < rows; i++) { 562 m_tree.expandRow(i); 563 } 564 } 565 } 566 567 572 class XMLTreeCellRenderer extends DefaultTreeCellRenderer 573 { 574 575 public Component getTreeCellRendererComponent(JTree tree, Object value, 576 boolean selected, boolean expanded, 577 boolean leaf, int row, 578 boolean hasFocus) 579 { 580 Node node = ((DOMTree)tree).getNode(value); 581 Component comp = super.getTreeCellRendererComponent(tree, value, 582 selected, expanded, leaf, row, hasFocus); 583 if (selected) { 584 comp.setBackground(Color.blue); 585 } 586 if (ef != null 587 && ef.getErrorNodes() != null 588 && value != null 589 && node != null 590 && ef.getErrorNodes().containsKey( node )) { 591 comp.setForeground(Color.red); 592 } 593 594 if (node != null) { 595 if (leaf) { 596 setIcon(new ImageIcon (leafImage)); 597 } else if (expanded) { 598 setIcon(new ImageIcon (openFolder)); 599 } else { 600 setIcon(new ImageIcon (closedFolder)); 601 } 602 } 603 if (node != null && node instanceof Element ) { 604 605 Element txNode = (Element )node; 606 Attr txAtt = (Attr )txNode.getAttributeNode("gender"); 607 if (txAtt != null) { 608 if (txAtt.getValue().equals("male")) { 609 setIcon(new ImageIcon ("male.gif")); 610 } else 611 if (txAtt.getValue().equals("female")) { 612 setIcon(new ImageIcon ("female.gif")); 613 } 614 } 615 } 616 617 return comp; 618 } 619 } 620 621 626 class FileNameInput extends JFrame implements ActionListener { 627 628 629 JLabel fileLabel; 630 JTextField textField; 631 JButton ok; 632 JButton cancel; 633 Vector textListeners; 634 635 public FileNameInput() { 636 this(""); 637 } 638 639 public FileNameInput(String title) { 640 641 super(title); 642 643 fileLabel = new JLabel ("Enter XML file name:"); 644 textField = new JTextField (); 645 textField.addActionListener(this); 646 ok = new JButton ("ok"); 647 cancel = new JButton ("cancel"); 648 JPanel buttonPanel = new JPanel (); 649 buttonPanel.add(ok); 650 buttonPanel.add(cancel); 651 ok.addActionListener(this); 652 cancel.addActionListener(this); 653 getContentPane().add(fileLabel, BorderLayout.NORTH); 654 getContentPane().add(textField, BorderLayout.CENTER); 655 getContentPane().add(buttonPanel, BorderLayout.SOUTH); 656 setSize(400,100); 657 } 658 659 public void actionPerformed(ActionEvent e) { 660 661 if (e.getSource() == ok || e.getSource() == textField) { 662 System.out.println("FileNameInput: pressed OK"); 663 TextEvent event = new TextEvent (textField, TextEvent.TEXT_VALUE_CHANGED); 664 deliverEvent(event); 665 setVisible(false); 666 } else 667 if (e.getSource() == cancel) { 668 System.out.println("FileNameInput: pressed cancel"); 669 setVisible(false); 670 } 671 } 672 673 680 public void addTextListener(TextListener listener) { 681 682 if (listener == null) 684 return; 685 686 if (textListeners == null) 687 textListeners = new Vector (); 688 689 textListeners.addElement(listener); 691 } 692 693 700 public void removeTextListener(TextListener listener) { 701 702 if (listener == null || textListeners == null) 704 return; 705 706 textListeners.removeElement(listener); 708 } 709 710 711 717 protected void deliverEvent(EventObject evt) { 718 719 if (evt instanceof TextEvent ) { 720 TextEvent event = (TextEvent )evt; 721 722 Vector l; 723 synchronized (textListeners) { l = (Vector )textListeners.clone(); } 724 725 int size = l.size(); 726 for (int i = 0; i < size; i++) 727 ((TextListener )l.elementAt(i)).textValueChanged(event); 728 } 729 } 730 } 731 732 static URL createURL(String name) throws Exception { 736 try { 737 URL u = new URL (name); 738 return u; 739 } catch (MalformedURLException ex) { 740 } 741 URL u = new URL ("file:" + new File (name).getAbsolutePath()); 742 return u; 743 } 744 745 758 class ErrorStorer 759 implements ErrorHandler 760 761 { 762 763 Hashtable errorNodes = null; 767 768 771 public ErrorStorer() { 772 } 773 774 778 public Hashtable getErrorNodes() { 779 return errorNodes; 780 } 781 782 786 public Object getError(Node node) { 787 if (errorNodes == null) 788 return null; 789 return errorNodes.get(node); 790 } 791 792 795 public void resetErrors() { 796 if (errorNodes != null) 797 errorNodes.clear(); 798 } 799 800 801 public void warning(SAXParseException ex) { 802 handleError(ex, WARNING); 803 } 804 805 public void error(SAXParseException ex) { 806 handleError(ex, ERROR); 807 } 808 809 public void fatalError(SAXParseException ex) throws SAXException { 810 handleError(ex, FATAL_ERROR); 811 } 812 813 private void handleError(SAXParseException ex, int type) { 814 System.out.println("!!! handleError: "+ex.getMessage()); 815 816 StringBuffer errorString = new StringBuffer (); 817 errorString.append("at line number, "); 818 errorString.append(ex.getLineNumber()); 819 errorString.append(": "); 820 errorString.append(ex.getMessage()); 821 822 824 Node current = null ; 825 826 try 827 { 828 current = ( Node ) parser.getProperty( "http://apache.org/xml/properties/dom/current-element-node" ); 829 830 } 831 catch( SAXException exception ) 832 { 833 ; 834 } 835 836 if (current == null) { 837 System.err.println("Error in handleError. getCurrentNode()==null!"); 838 return; 839 } 840 841 if (errorNodes == null) 842 errorNodes = new Hashtable (); 843 ParseError previous = (ParseError) errorNodes.get(current); 844 ParseError eip = null; 845 if (previous != null) { 847 eip = previous; 848 errorString = new StringBuffer (previous.getMsg()+"\n"+errorString.toString()); 849 eip.setMsg(errorString.toString()); 850 } else { 851 eip = new 852 ParseError( 853 ex.getSystemId(), 854 ex.getLineNumber(), 855 ex.getColumnNumber(), 856 "", 857 errorString.toString()); 858 } 859 860 errorNodes.put(current, eip); 862 } 863 864 } 865 866 872 class ParseError extends Object { 873 874 878 String fileName; 879 int lineNo; 880 int charOffset; 881 Object key; 882 String msg; 883 884 887 public ParseError(String fileName, int lineNo, int charOffset, 888 Object key, 889 String msg) 890 { 891 this. fileName=fileName; 892 this. lineNo=lineNo; 893 this. charOffset=charOffset; 894 this. key=key; 895 this. msg=msg; 896 } 897 898 public String getFileName() { return fileName; } 902 public int getLineNo() { return lineNo; } 903 public int getCharOffset() { return charOffset;} 904 public Object getKey() { return key; } 905 public String getMsg() { return msg; } 906 public void setMsg(String s) { msg = s; } 907 } 908 909 910 914 915 public static void main(String argv[]) { 916 917 int parserNameIndex = -1; 919 String parserName = DEFAULT_PARSER_NAME; 920 921 for (int i = 0; i < argv.length; i++) { 923 String arg = argv[i]; 924 925 if (arg.startsWith("-")) { 927 if (arg.equals("-p")) { 928 if (i == argv.length - 1) { 929 System.err.println("error: missing parser class"); 930 System.exit(1); 931 } 932 parserName = argv[++i]; 933 parserNameIndex = i; 934 continue; 935 } 936 937 if (arg.equals("-h")) { 938 printUsage(); 939 System.exit(1); 940 } 941 } 942 943 System.err.println(arg+':'); 945 946 JFrame frame = null; 947 if (parserNameIndex == argv.length-1) { 948 frame = new TreeView(""); 950 } else { 951 frame = new TreeView(arg); 952 } 953 frame.addWindowListener(new java.awt.event.WindowAdapter () { 954 public void windowClosing(java.awt.event.WindowEvent e) { 955 System.exit(0); 956 } 957 }); 958 frame.setSize(790, 590); 959 frame.setVisible(true); 960 } 961 } 963 964 private static void printUsage() { 965 966 System.err.println("usage: java ui.TreeViewer (options) uri ..."); 967 System.err.println(); 968 System.err.println("options:"); 969 System.err.println(" -p name Specify DOM parser class by name."); 970 System.err.println(" Default parser: "+DEFAULT_PARSER_NAME); 971 System.err.println(" -h This help screen."); 972 973 } 975 } | Popular Tags |