Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 644   Methods: 60
NCLOC: 514   Classes: 9
 
 Source file Conditionals Statements Methods TOTAL
Designer.java 0% 0% 0% 0%
coverage
 1    /**
 2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 3    */
 4    package net.sourceforge.pmd.util.designer;
 5   
 6    import net.sourceforge.pmd.PMD;
 7    import net.sourceforge.pmd.RuleContext;
 8    import net.sourceforge.pmd.RuleSet;
 9    import net.sourceforge.pmd.SourceType;
 10    import net.sourceforge.pmd.TargetJDK1_3;
 11    import net.sourceforge.pmd.TargetJDK1_4;
 12    import net.sourceforge.pmd.TargetJDK1_5;
 13    import net.sourceforge.pmd.TargetJDK1_6;
 14    import net.sourceforge.pmd.ast.Node;
 15    import net.sourceforge.pmd.ast.ParseException;
 16    import net.sourceforge.pmd.ast.SimpleNode;
 17    import net.sourceforge.pmd.jaxen.DocumentNavigator;
 18    import net.sourceforge.pmd.jaxen.MatchesFunction;
 19    import net.sourceforge.pmd.jsp.ast.JspCharStream;
 20    import net.sourceforge.pmd.jsp.ast.JspParser;
 21    import net.sourceforge.pmd.util.NumericConstants;
 22    import net.sourceforge.pmd.util.StringUtil;
 23    import org.jaxen.BaseXPath;
 24    import org.jaxen.JaxenException;
 25    import org.jaxen.XPath;
 26   
 27    import javax.swing.*;
 28    import javax.swing.event.*;
 29    import javax.swing.text.JTextComponent;
 30    import javax.swing.tree.DefaultTreeCellRenderer;
 31    import javax.swing.tree.DefaultTreeModel;
 32    import javax.swing.tree.TreeNode;
 33    import javax.swing.tree.TreePath;
 34    import javax.swing.undo.*;
 35    import java.awt.BorderLayout;
 36    import java.awt.Color;
 37    import java.awt.Component;
 38    import java.awt.Dimension;
 39    import java.awt.Font;
 40    import java.awt.FontMetrics;
 41    import java.awt.Graphics;
 42    import java.awt.Toolkit;
 43    import java.awt.datatransfer.Clipboard;
 44    import java.awt.datatransfer.ClipboardOwner;
 45    import java.awt.datatransfer.StringSelection;
 46    import java.awt.datatransfer.Transferable;
 47    import java.awt.event.ActionEvent;
 48    import java.awt.event.ActionListener;
 49    import java.awt.event.ComponentEvent;
 50    import java.awt.event.KeyEvent;
 51    import java.io.IOException;
 52    import java.io.StringReader;
 53    import java.io.StringWriter;
 54    import java.lang.reflect.InvocationTargetException;
 55    import java.lang.reflect.Method;
 56    import java.util.Enumeration;
 57    import java.util.Iterator;
 58    import java.util.List;
 59    import java.util.Vector;
 60   
 61    public class Designer implements ClipboardOwner {
 62   
 63    private static final char LABEL_IMAGE_SEPARATOR = ':';
 64    private static final Color IMAGE_TEXT_COLOR = Color.BLUE;
 65   
 66    private interface Parser { public SimpleNode parse(StringReader sr); };
 67   
 68    private static final Parser jdkParser1_3 = new Parser() {
 69  0 public SimpleNode parse(StringReader sr) { return new TargetJDK1_3().createParser(sr).CompilationUnit(); };
 70    };
 71   
 72    private static final Parser jdkParser1_4 = new Parser() {
 73  0 public SimpleNode parse(StringReader sr) { return new TargetJDK1_4().createParser(sr).CompilationUnit(); };
 74    };
 75   
 76    private static final Parser jdkParser1_5 = new Parser() {
 77  0 public SimpleNode parse(StringReader sr) { return new TargetJDK1_5().createParser(sr).CompilationUnit(); };
 78    };
 79   
 80    private static final Parser jdkParser1_6 = new Parser() {
 81  0 public SimpleNode parse(StringReader sr) { return new TargetJDK1_6().createParser(sr).CompilationUnit(); };
 82    };
 83   
 84    private static final Parser jspParser = new Parser() {
 85  0 public SimpleNode parse(StringReader sr) { return new JspParser(new JspCharStream(sr)).CompilationUnit(); };
 86    };
 87   
 88    private static final Object[][] sourceTypeSets = new Object[][] {
 89    { "JDK 1.3", SourceType.JAVA_13, jdkParser1_3 },
 90    { "JDK 1.4", SourceType.JAVA_14, jdkParser1_4 },
 91    { "JDK 1.5", SourceType.JAVA_15, jdkParser1_5 },
 92    { "JDK 1.6", SourceType.JAVA_16, jdkParser1_6 },
 93    { "JSP", SourceType.JSP, jspParser }
 94    };
 95   
 96    private static final int defaultSourceTypeSelectionIndex = 1; // JDK 1.4
 97   
 98   
 99  0 private SimpleNode getCompilationUnit() {
 100   
 101  0 Parser parser = (Parser)sourceTypeSets[selectedSourceTypeIndex()][2];
 102  0 return parser.parse(new StringReader(codeEditorPane.getText()));
 103    }
 104   
 105  0 private SourceType getSourceType() {
 106   
 107  0 return (SourceType)sourceTypeSets[selectedSourceTypeIndex()][1];
 108    }
 109   
 110  0 private int selectedSourceTypeIndex() {
 111  0 for (int i=0; i<sourceTypeMenuItems.length; i++) {
 112  0 if (sourceTypeMenuItems[i].isSelected()) return i;
 113    }
 114  0 throw new RuntimeException("Initial default source type not specified");
 115    }
 116   
 117    private class ExceptionNode implements TreeNode {
 118   
 119    private Object item;
 120    private ExceptionNode[] kids;
 121   
 122  0 public ExceptionNode(Object theItem) {
 123  0 item = theItem;
 124   
 125  0 if (item instanceof ParseException) createKids();
 126    }
 127   
 128    // each line in the error message becomes a separate tree node
 129  0 private void createKids() {
 130   
 131  0 String message = ((ParseException)item).getMessage();
 132  0 String[] lines = StringUtil.substringsOf(message, PMD.EOL);
 133   
 134  0 kids = new ExceptionNode[lines.length];
 135  0 for (int i=0; i<lines.length; i++) {
 136  0 kids[i] = new ExceptionNode(lines[i]);
 137    }
 138    }
 139   
 140  0 public int getChildCount() { return kids == null ? 0 : kids.length; }
 141  0 public boolean getAllowsChildren() {return false; }
 142  0 public boolean isLeaf() { return kids == null; }
 143  0 public TreeNode getParent() { return null; }
 144  0 public TreeNode getChildAt(int childIndex) { return kids[childIndex]; }
 145  0 public String label() { return item.toString(); }
 146   
 147  0 public Enumeration children() {
 148  0 Enumeration e = new Enumeration() {
 149    int i = 0;
 150  0 public boolean hasMoreElements() {
 151  0 return kids != null && i < kids.length;
 152    }
 153   
 154  0 public Object nextElement() { return kids[i++]; }
 155    };
 156  0 return e;
 157    }
 158   
 159  0 public int getIndex(TreeNode node) {
 160  0 for (int i=0; i<kids.length; i++) {
 161  0 if (kids[i] == node) return i;
 162    }
 163  0 return -1;
 164    }
 165    }
 166   
 167    // Tree node that wraps the AST node for the tree widget and
 168    // any possible children they may have.
 169    private class ASTTreeNode implements TreeNode {
 170   
 171    private Node node;
 172    private ASTTreeNode parent;
 173    private ASTTreeNode[] kids;
 174   
 175  0 public ASTTreeNode(Node theNode) {
 176  0 node = theNode;
 177   
 178  0 Node prnt = node.jjtGetParent();
 179  0 if (prnt != null) parent = new ASTTreeNode(prnt);
 180    }
 181   
 182  0 public int getChildCount() { return node.jjtGetNumChildren(); }
 183  0 public boolean getAllowsChildren() { return false; }
 184  0 public boolean isLeaf() { return node.jjtGetNumChildren() == 0; }
 185  0 public TreeNode getParent() { return parent; }
 186   
 187  0 public Enumeration children() {
 188   
 189  0 if (getChildCount() > 0) getChildAt(0); // force it to build kids
 190   
 191  0 Enumeration e = new Enumeration() {
 192    int i = 0;
 193  0 public boolean hasMoreElements() {
 194  0 return kids != null && i < kids.length;
 195    }
 196  0 public Object nextElement() { return kids[i++]; }
 197    };
 198  0 return e;
 199    }
 200   
 201  0 public TreeNode getChildAt(int childIndex) {
 202   
 203  0 if (kids == null) {
 204  0 kids = new ASTTreeNode[node.jjtGetNumChildren()];
 205  0 for (int i=0; i<kids.length; i++) {
 206  0 kids[i] = new ASTTreeNode(node.jjtGetChild(i));
 207    }
 208    }
 209  0 return kids[childIndex];
 210    }
 211   
 212  0 public int getIndex(TreeNode node) {
 213   
 214  0 for (int i=0; i<kids.length; i++) {
 215  0 if (kids[i] == node) return i;
 216    }
 217  0 return -1;
 218    }
 219   
 220  0 public String label() {
 221  0 if (node instanceof SimpleNode) {
 222  0 SimpleNode sn = (SimpleNode)node;
 223  0 if (sn.getLabel() != null) {
 224  0 return node.toString() + LABEL_IMAGE_SEPARATOR + sn.getLabel();
 225    }
 226  0 if (sn.getImage() == null) {
 227  0 return node.toString();
 228    }
 229  0 return node.toString() + LABEL_IMAGE_SEPARATOR + sn.getImage();
 230    }
 231  0 return node.toString();
 232    }
 233    }
 234   
 235    // Create our own renderer to ensure we don't show the default icon
 236    // and render any node image data in a different colour to hightlight
 237    // it.
 238   
 239    private class ASTCellRenderer extends DefaultTreeCellRenderer {
 240   
 241    private ASTTreeNode node;
 242   
 243  0 public Icon getIcon() { return null; };
 244   
 245  0 public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,boolean expanded,boolean leaf, int row, boolean hasFocus) {
 246   
 247  0 if (value instanceof ASTTreeNode) {
 248  0 node = (ASTTreeNode)value;
 249    }
 250  0 return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
 251    }
 252   
 253    // overwrite the image data (if present) in a different colour
 254  0 public void paint(Graphics g) {
 255   
 256  0 super.paint(g);
 257   
 258  0 if (node == null) return;
 259   
 260  0 String text = node.label();
 261  0 int separatorPos = text.indexOf(LABEL_IMAGE_SEPARATOR);
 262  0 if (separatorPos < 0) return;
 263   
 264  0 String label = text.substring(0, separatorPos+1);
 265  0 String image = text.substring(separatorPos+1);
 266   
 267  0 FontMetrics fm = g.getFontMetrics();
 268  0 int width = SwingUtilities.computeStringWidth(fm, label);
 269   
 270  0 g.setColor(IMAGE_TEXT_COLOR);
 271  0 g.drawString(image, width, fm.getMaxAscent());
 272    }
 273    }
 274   
 275    // Special tree variant that knows how to retrieve node labels and
 276    // provides the ability to expand all nodes at once.
 277   
 278    private class ASTTreeWidget extends JTree {
 279   
 280  0 public ASTTreeWidget(Vector items) {
 281  0 super(items);
 282    }
 283   
 284  0 public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
 285  0 if (value == null) return "";
 286  0 if (value instanceof ASTTreeNode) {
 287  0 return ((ASTTreeNode)value).label();
 288    }
 289  0 if (value instanceof ExceptionNode) {
 290  0 return ((ExceptionNode)value).label();
 291    }
 292  0 return value.toString();
 293    }
 294   
 295  0 public void expandAll(boolean expand) {
 296  0 TreeNode root = (TreeNode)getModel().getRoot();
 297  0 expandAll(new TreePath(root), expand);
 298    }
 299   
 300  0 private void expandAll(TreePath parent, boolean expand) {
 301    // Traverse children
 302  0 TreeNode node = (TreeNode)parent.getLastPathComponent();
 303  0 if (node.getChildCount() >= 0) {
 304  0 for (Enumeration e=node.children(); e.hasMoreElements(); ) {
 305  0 TreeNode n = (TreeNode)e.nextElement();
 306  0 TreePath path = parent.pathByAddingChild(n);
 307  0 expandAll(path, expand);
 308    }
 309    }
 310   
 311  0 if (expand) {
 312  0 expandPath(parent);
 313    } else {
 314  0 collapsePath(parent);
 315    }
 316    }
 317    }
 318   
 319  0 private void loadTreeData(TreeNode rootNode) {
 320  0 astWidget.setModel(new DefaultTreeModel(rootNode));
 321  0 astWidget.expandAll(true);
 322    }
 323   
 324    private class ShowListener implements ActionListener {
 325  0 public void actionPerformed(ActionEvent ae) {
 326  0 MyPrintStream ps = new MyPrintStream();
 327  0 System.setOut(ps);
 328  0 TreeNode tn;
 329  0 try {
 330  0 SimpleNode lastCompilationUnit = getCompilationUnit();
 331  0 tn = new ASTTreeNode(lastCompilationUnit);
 332    } catch (ParseException pe) {
 333  0 tn = new ExceptionNode(pe);
 334    }
 335   
 336  0 loadTreeData(tn);
 337    }
 338    }
 339   
 340    private class DFAListener implements ActionListener {
 341  0 public void actionPerformed(ActionEvent ae) {
 342   
 343  0 DFAGraphRule dfaGraphRule = new DFAGraphRule();
 344  0 RuleSet rs = new RuleSet();
 345  0 SourceType sourceType = getSourceType();
 346  0 if (!sourceType.equals(SourceType.JSP)){
 347  0 rs.addRule(dfaGraphRule);
 348    }
 349  0 RuleContext ctx = new RuleContext();
 350  0 ctx.setSourceCodeFilename("[no filename]");
 351  0 StringReader reader = new StringReader(codeEditorPane.getText());
 352  0 PMD pmd = new PMD();
 353  0 pmd.setJavaVersion(sourceType);
 354   
 355  0 try {
 356  0 pmd.processFile(reader, rs, ctx);
 357    // } catch (PMDException pmde) {
 358    // loadTreeData(new ExceptionNode(pmde));
 359    } catch (Exception e) {
 360  0 e.printStackTrace();
 361    }
 362   
 363  0 List methods = dfaGraphRule.getMethods();
 364  0 if (methods != null && !methods.isEmpty()) {
 365  0 dfaPanel.resetTo(methods, codeEditorPane);
 366  0 dfaPanel.repaint();
 367    }
 368    }
 369    }
 370   
 371    private class XPathListener implements ActionListener {
 372  0 public void actionPerformed(ActionEvent ae) {
 373  0 xpathResults.clear();
 374  0 if (xpathQueryArea.getText().length() == 0) {
 375  0 xpathResults.addElement("XPath query field is empty");
 376  0 xpathResultList.repaint();
 377  0 codeEditorPane.requestFocus();
 378  0 return;
 379    }
 380  0 SimpleNode c = getCompilationUnit();
 381  0 try {
 382  0 XPath xpath = new BaseXPath(xpathQueryArea.getText(), new DocumentNavigator());
 383  0 for (Iterator iter = xpath.selectNodes(c).iterator(); iter.hasNext();) {
 384  0 StringBuffer sb = new StringBuffer();
 385  0 Object obj = iter.next();
 386  0 if (obj instanceof String) {
 387  0 System.out.println("Result was a string: " + ((String) obj));
 388  0 } else if (!(obj instanceof Boolean)) {
 389    // if it's a Boolean and it's 'false', what does that mean?
 390  0 SimpleNode node = (SimpleNode) obj;
 391  0 String name = node.getClass().getName().substring(node.getClass().getName().lastIndexOf('.') + 1);
 392  0 String line = " at line " + node.getBeginLine();
 393  0 sb.append(name).append(line).append(PMD.EOL);
 394  0 xpathResults.addElement(sb.toString().trim());
 395    }
 396    }
 397  0 if (xpathResults.isEmpty()) {
 398  0 xpathResults.addElement("No matching nodes " + System.currentTimeMillis());
 399    }
 400    } catch (ParseException pe) {
 401  0 xpathResults.addElement(pe.fillInStackTrace().getMessage());
 402    } catch (JaxenException je) {
 403  0 xpathResults.addElement(je.fillInStackTrace().getMessage());
 404    }
 405  0 xpathResultList.repaint();
 406  0 xpathQueryArea.requestFocus();
 407    }
 408    }
 409   
 410    private final CodeEditorTextPane codeEditorPane = new CodeEditorTextPane();
 411    private final ASTTreeWidget astWidget = new ASTTreeWidget(new Vector());
 412    private DefaultListModel xpathResults = new DefaultListModel();
 413    private final JList xpathResultList = new JList(xpathResults);
 414    private final JTextArea xpathQueryArea = new JTextArea(15, 30);
 415    private final JFrame frame = new JFrame("PMD Rule Designer");
 416    private final DFAPanel dfaPanel = new DFAPanel();
 417    private final JRadioButtonMenuItem[] sourceTypeMenuItems = new JRadioButtonMenuItem[sourceTypeSets.length];
 418   
 419  0 public Designer() {
 420  0 MatchesFunction.registerSelfInSimpleContext();
 421   
 422  0 xpathQueryArea.setFont(new Font("Verdana", Font.PLAIN, 16));
 423  0 makeTextComponentUndoable(codeEditorPane);
 424  0 JSplitPane controlSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(codeEditorPane), createXPathQueryPanel());
 425  0 JSplitPane resultsSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, createASTPanel(), createXPathResultPanel());
 426   
 427  0 JTabbedPane tabbed = new JTabbedPane();
 428  0 tabbed.addTab("Abstract Syntax Tree / XPath", resultsSplitPane);
 429  0 tabbed.addTab("Data Flow Analysis", dfaPanel);
 430  0 try {
 431    // Remove when minimal runtime support is >= JDK 1.4
 432  0 Method setMnemonicAt = JTabbedPane.class.getMethod("setMnemonicAt", new Class[]{Integer.TYPE, Integer.TYPE});
 433  0 if (setMnemonicAt != null) {
 434    // // Compatible with >= JDK 1.4
 435    // tabbed.setMnemonicAt(0, KeyEvent.VK_A);
 436    // tabbed.setMnemonicAt(1, KeyEvent.VK_D);
 437  0 setMnemonicAt.invoke(tabbed, new Object[]{NumericConstants.ZERO, new Integer(KeyEvent.VK_A)});
 438  0 setMnemonicAt.invoke(tabbed, new Object[]{NumericConstants.ONE, new Integer(KeyEvent.VK_D)});
 439    }
 440    } catch (NoSuchMethodException nsme) { // Runtime is < JDK 1.4
 441    } catch (IllegalAccessException e) { // Runtime is >= JDK 1.4 but there was an error accessing the function
 442  0 e.printStackTrace();
 443  0 throw new InternalError("Runtime reports to be >= JDK 1.4 yet String.split(java.lang.String) is broken.");
 444    } catch (IllegalArgumentException e) {
 445  0 e.printStackTrace();
 446  0 throw new InternalError("Runtime reports to be >= JDK 1.4 yet String.split(java.lang.String) is broken.");
 447    } catch (InvocationTargetException e) { // Runtime is >= JDK 1.4 but there was an error accessing the function
 448  0 e.printStackTrace();
 449  0 throw new InternalError("Runtime reports to be >= JDK 1.4 yet String.split(java.lang.String) is broken.");
 450    }
 451   
 452  0 JSplitPane containerSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, controlSplitPane, tabbed);
 453  0 containerSplitPane.setContinuousLayout(true);
 454   
 455  0 JMenuBar menuBar = createMenuBar();
 456  0 frame.setJMenuBar(menuBar);
 457  0 frame.getContentPane().add(containerSplitPane);
 458  0 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 459   
 460  0 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 461  0 int screenHeight = screenSize.height;
 462  0 int screenWidth = screenSize.width;
 463   
 464  0 frame.pack();
 465  0 frame.setSize((screenWidth*3/4),(screenHeight*3/4));
 466  0 frame.setLocation((screenWidth -frame.getWidth()) / 2, (screenHeight - frame.getHeight()) / 2);
 467  0 frame.setVisible(true);
 468  0 resultsSplitPane.setDividerLocation(resultsSplitPane.getMaximumDividerLocation() - (resultsSplitPane.getMaximumDividerLocation() / 2));
 469  0 containerSplitPane.setDividerLocation(containerSplitPane.getMaximumDividerLocation() / 2);
 470    }
 471   
 472  0 private JMenuBar createMenuBar() {
 473  0 JMenuBar menuBar = new JMenuBar();
 474  0 JMenu menu = new JMenu("JDK");
 475  0 ButtonGroup group = new ButtonGroup();
 476   
 477  0 for (int i=0; i<sourceTypeSets.length; i++) {
 478  0 JRadioButtonMenuItem button = new JRadioButtonMenuItem(sourceTypeSets[i][0].toString());
 479  0 sourceTypeMenuItems[i] = button;
 480  0 group.add(button);
 481  0 menu.add(button);
 482    }
 483  0 sourceTypeMenuItems[defaultSourceTypeSelectionIndex].setSelected(true);
 484  0 menuBar.add(menu);
 485   
 486  0 JMenu actionsMenu = new JMenu("Actions");
 487  0 JMenuItem copyXMLItem = new JMenuItem("Copy xml to clipboard");
 488  0 copyXMLItem.addActionListener(new ActionListener() {
 489  0 public void actionPerformed(ActionEvent e) {
 490  0 copyXmlToClipboard();
 491    }
 492    });
 493  0 actionsMenu.add(copyXMLItem);
 494  0 JMenuItem createRuleXMLItem = new JMenuItem("Create rule XML");
 495  0 createRuleXMLItem.addActionListener(new ActionListener() {
 496  0 public void actionPerformed(ActionEvent e) {
 497  0 createRuleXML();
 498    }
 499    });
 500  0 actionsMenu.add(createRuleXMLItem);
 501  0 menuBar.add(actionsMenu);
 502   
 503  0 return menuBar;
 504    }
 505   
 506  0 private void createRuleXML() {
 507  0 CreateXMLRulePanel rulePanel = new CreateXMLRulePanel(xpathQueryArea, codeEditorPane);
 508  0 JFrame xmlframe = new JFrame("Create XML Rule");
 509  0 xmlframe.setContentPane(rulePanel);
 510  0 xmlframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
 511  0 xmlframe.setSize(new Dimension(600, 700));
 512  0 xmlframe.addComponentListener(new java.awt.event.ComponentAdapter() {
 513  0 public void componentResized(ComponentEvent e) {
 514  0 JFrame tmp = (JFrame)e.getSource();
 515  0 if (tmp.getWidth()<600 || tmp.getHeight()<700) {
 516  0 tmp.setSize(600, 700);
 517    }
 518    }
 519    });
 520  0 int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
 521  0 int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
 522  0 xmlframe.pack();
 523  0 xmlframe.setLocation((screenWidth - xmlframe.getWidth()) / 2, (screenHeight - xmlframe.getHeight()) / 2);
 524  0 xmlframe.setVisible(true);
 525    }
 526   
 527  0 private JComponent createASTPanel() {
 528  0 astWidget.setCellRenderer(new ASTCellRenderer());
 529  0 return new JScrollPane(astWidget);
 530    }
 531   
 532  0 private JComponent createXPathResultPanel() {
 533  0 xpathResults.addElement("No results yet");
 534  0 xpathResultList.setBorder(BorderFactory.createLineBorder(Color.black));
 535  0 xpathResultList.setFixedCellWidth(300);
 536  0 JScrollPane scrollPane = new JScrollPane();
 537  0 scrollPane.getViewport().setView(xpathResultList);
 538  0 return scrollPane;
 539    }
 540   
 541  0 private JPanel createXPathQueryPanel() {
 542  0 JPanel p = new JPanel();
 543  0 p.setLayout(new BorderLayout());
 544  0 xpathQueryArea.setBorder(BorderFactory.createLineBorder(Color.black));
 545  0 makeTextComponentUndoable(xpathQueryArea);
 546  0 JScrollPane scrollPane = new JScrollPane(xpathQueryArea);
 547  0 scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
 548  0 scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
 549  0 final JButton b = createGoButton();
 550   
 551  0 p.add(new JLabel("XPath Query (if any)"), BorderLayout.NORTH);
 552  0 p.add(scrollPane, BorderLayout.CENTER);
 553  0 p.add(b, BorderLayout.SOUTH);
 554   
 555  0 return p;
 556    }
 557   
 558  0 private JButton createGoButton() {
 559  0 JButton b = new JButton("Go");
 560  0 b.setMnemonic('g');
 561  0 b.addActionListener(new ShowListener());
 562  0 b.addActionListener(codeEditorPane);
 563  0 b.addActionListener(new XPathListener());
 564  0 b.addActionListener(new DFAListener());
 565  0 return b;
 566    }
 567   
 568  0 private static void makeTextComponentUndoable(JTextComponent textConponent) {
 569  0 final UndoManager undoManager = new UndoManager();
 570  0 textConponent.getDocument().addUndoableEditListener(new UndoableEditListener() {
 571  0 public void undoableEditHappened(
 572    UndoableEditEvent evt) {
 573  0 undoManager.addEdit(evt.getEdit());
 574    }
 575    });
 576  0 ActionMap actionMap = textConponent.getActionMap();
 577  0 InputMap inputMap = textConponent.getInputMap();
 578  0 actionMap.put("Undo", new AbstractAction("Undo") {
 579  0 public void actionPerformed(ActionEvent evt) {
 580  0 try {
 581  0 if (undoManager.canUndo()) {
 582  0 undoManager.undo();
 583    }
 584    } catch (CannotUndoException e) {
 585    }
 586    }
 587    });
 588  0 inputMap.put(KeyStroke.getKeyStroke("control Z"), "Undo");
 589   
 590  0 actionMap.put("Redo", new AbstractAction("Redo") {
 591  0 public void actionPerformed(ActionEvent evt) {
 592  0 try {
 593  0 if (undoManager.canRedo()) {
 594  0 undoManager.redo();
 595    }
 596    } catch (CannotRedoException e) {
 597    }
 598    }
 599    });
 600  0 inputMap.put(KeyStroke.getKeyStroke("control Y"), "Redo");
 601    }
 602   
 603  0 public static void main(String[] args) {
 604  0 new Designer();
 605    }
 606   
 607  0 private final void copyXmlToClipboard() {
 608  0 if (codeEditorPane.getText() != null && codeEditorPane.getText().trim().length() > 0) {
 609  0 String xml = "";
 610  0 SimpleNode cu = getCompilationUnit();
 611  0 if (cu != null) {
 612  0 try {
 613  0 xml = getXmlString(cu);
 614    } catch (IOException e) {
 615  0 e.printStackTrace();
 616  0 xml = "Error trying to construct XML representation";
 617    }
 618    }
 619  0 Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(xml), this);
 620    }
 621    }
 622   
 623    /**
 624    * Returns an unformatted xml string (without the declaration)
 625    *
 626    * @param node
 627    * @return String
 628    * @throws java.io.IOException
 629    */
 630  0 private String getXmlString(SimpleNode node) throws IOException {
 631    /*
 632    StringWriter writer = new StringWriter();
 633    XMLSerializer xmlSerializer = new XMLSerializer(writer, new OutputFormat("XML", "UTF-8", true));
 634    xmlSerializer.asDOMSerializer();
 635    xmlSerializer.serialize(node.asXml());
 636    return writer.toString();
 637    */
 638  0 return "FIXME"; // FIXME
 639    }
 640   
 641  0 public void lostOwnership(Clipboard clipboard, Transferable contents) {
 642    }
 643    }
 644