001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2002 Oliver Burn
004: //
005: // This library is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU Lesser General Public
007: // License as published by the Free Software Foundation; either
008: // version 2.1 of the License, or (at your option) any later version.
009: //
010: // This library is distributed in the hope that it will be useful,
011: // but WITHOUT ANY WARRANTY; without even the implied warranty of
012: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: // Lesser General Public License for more details.
014: //
015: // You should have received a copy of the GNU Lesser General Public
016: // License along with this library; if not, write to the Free Software
017: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: ////////////////////////////////////////////////////////////////////////////////
019:
020: package com.puppycrawl.tools.checkstyle.gui;
021:
022: import java.awt.BorderLayout;
023: import java.awt.Component;
024: import java.awt.GridLayout;
025: import java.awt.event.ActionEvent;
026: import java.awt.event.KeyEvent;
027: import java.io.File;
028: import java.io.IOException;
029: import java.util.TooManyListenersException;
030:
031: import javax.swing.AbstractAction;
032: import javax.swing.Action;
033: import javax.swing.JButton;
034: import javax.swing.JFileChooser;
035: import javax.swing.JOptionPane;
036: import javax.swing.JPanel;
037: import javax.swing.JScrollPane;
038: import javax.swing.SwingUtilities;
039: import javax.swing.filechooser.FileFilter;
040: import javax.swing.JTextArea;
041:
042: import antlr.ANTLRException;
043:
044: import com.puppycrawl.tools.checkstyle.TreeWalker;
045: import com.puppycrawl.tools.checkstyle.api.DetailAST;
046: import com.puppycrawl.tools.checkstyle.api.FileContents;
047: import com.puppycrawl.tools.checkstyle.api.Utils;
048:
049: /**
050: * Displays information about a parse tree.
051: * The user can change the file that is parsed and displayed
052: * through a JFileChooser.
053: *
054: * @author Lars Kühne
055: */
056: public class ParseTreeInfoPanel extends JPanel {
057: private JTreeTable mTreeTable;
058: private ParseTreeModel mParseTreeModel;
059: private JTextArea mJTextArea;
060: private File mLastDirectory = null;
061: private File mCurrentFile = null;
062: private final Action reloadAction;
063:
064: private static class JavaFileFilter extends FileFilter {
065: public boolean accept(File f) {
066: if (f == null) {
067: return false;
068: }
069: return f.isDirectory() || f.getName().endsWith(".java");
070: }
071:
072: public String getDescription() {
073: return "Java Source Code";
074: }
075: }
076:
077: private class FileSelectionAction extends AbstractAction {
078: public FileSelectionAction() {
079: super ("Select Java File");
080: putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S));
081: }
082:
083: public void actionPerformed(ActionEvent e) {
084: final JFileChooser fc = new JFileChooser(mLastDirectory);
085: final FileFilter filter = new JavaFileFilter();
086: fc.setFileFilter(filter);
087: final Component parent = SwingUtilities
088: .getRoot(ParseTreeInfoPanel.this );
089: fc.showDialog(parent, "Open");
090: final File file = fc.getSelectedFile();
091: openFile(file, parent);
092:
093: }
094: }
095:
096: private class ReloadAction extends AbstractAction {
097: public ReloadAction() {
098: super ("Reload Java File");
099: putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
100: }
101:
102: public void actionPerformed(ActionEvent e) {
103: final Component parent = SwingUtilities
104: .getRoot(ParseTreeInfoPanel.this );
105: openFile(mCurrentFile, parent);
106: }
107: }
108:
109: private class FileDropListener implements FileDrop.Listener {
110: private final JScrollPane mSp;
111:
112: public void filesDropped(File[] files) {
113: if ((files != null) && (files.length > 0)) {
114: final File file = files[0];
115: openFile(file, mSp);
116: }
117: }
118:
119: public FileDropListener(JScrollPane aSp) {
120: mSp = aSp;
121: }
122: }
123:
124: public void openFile(File aFile, final Component aParent) {
125: if (aFile != null) {
126: try {
127: Main.frame.setTitle("Checkstyle : " + aFile.getName());
128: final DetailAST parseTree = parseFile(aFile
129: .getAbsolutePath());
130: mParseTreeModel.setParseTree(parseTree);
131: mCurrentFile = aFile;
132: mLastDirectory = aFile.getParentFile();
133: reloadAction.setEnabled(true);
134:
135: final String[] sourceLines = Utils.getLines(aFile
136: .getAbsolutePath());
137: //clean the text area before inserting the lines of the new file
138: if (mJTextArea.getText().length() != 0) {
139: mJTextArea.replaceRange("", 0, mJTextArea.getText()
140: .length());
141: }
142:
143: // insert the contents of the file to the text area
144: for (int i = 0; i < sourceLines.length; i++) {
145: mJTextArea.append(sourceLines[i] + "\n");
146: }
147:
148: // move back to the top of the file
149: mJTextArea.moveCaretPosition(0);
150: } catch (final IOException ex) {
151: showErrorDialog(aParent, "Could not open " + aFile
152: + ": " + ex.getMessage());
153: } catch (final ANTLRException ex) {
154: showErrorDialog(aParent, "Could not parse " + aFile
155: + ": " + ex.getMessage());
156: }
157: }
158: }
159:
160: /**
161: * Parses a file and returns the parse tree.
162: * @param aFileName the file to parse
163: * @return the root node of the parse tree
164: * @throws IOException if the file cannot be opened
165: * @throws ANTLRException if the file is not a Java source
166: */
167: public static DetailAST parseFile(String aFileName)
168: throws IOException, ANTLRException {
169: final String[] lines = Utils.getLines(aFileName);
170: final FileContents contents = new FileContents(aFileName, lines);
171: return TreeWalker.parse(contents);
172: }
173:
174: /**
175: * Create a new ParseTreeInfoPanel instance.
176: */
177: public ParseTreeInfoPanel() {
178: setLayout(new BorderLayout());
179:
180: final DetailAST treeRoot = null;
181: mParseTreeModel = new ParseTreeModel(treeRoot);
182: mTreeTable = new JTreeTable(mParseTreeModel);
183: final JScrollPane sp = new JScrollPane(mTreeTable);
184: this .add(sp, BorderLayout.NORTH);
185:
186: final JButton fileSelectionButton = new JButton(
187: new FileSelectionAction());
188:
189: reloadAction = new ReloadAction();
190: reloadAction.setEnabled(false);
191: final JButton reloadButton = new JButton(reloadAction);
192:
193: mJTextArea = new JTextArea(20, 15);
194: mJTextArea.setEditable(false);
195:
196: final JScrollPane sp2 = new JScrollPane(mJTextArea);
197: this .add(sp2, BorderLayout.CENTER);
198:
199: final JPanel p = new JPanel(new GridLayout(1, 2));
200: this .add(p, BorderLayout.SOUTH);
201: p.add(fileSelectionButton);
202: p.add(reloadButton);
203:
204: try {
205: // TODO: creating an object for the side effect of the constructor
206: // and then ignoring the object looks strange.
207: new FileDrop(sp, new FileDropListener(sp));
208: } catch (final TooManyListenersException ex) {
209: showErrorDialog(null,
210: "Cannot initialize Drag and Drop support");
211: }
212:
213: }
214:
215: private void showErrorDialog(final Component parent,
216: final String msg) {
217: final Runnable showError = new Runnable() {
218: public void run() {
219: JOptionPane.showMessageDialog(parent, msg);
220: }
221: };
222: SwingUtilities.invokeLater(showError);
223: }
224:
225: }
|