org.fife.rsta.ac.java.tree.JavaOutlineTree Maven / Gradle / Ivy
/*
* 03/21/2010
*
* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
*
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
*/
package org.fife.rsta.ac.java.tree;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Iterator;
import javax.swing.BorderFactory;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.fife.rsta.ac.AbstractSourceTree;
import org.fife.rsta.ac.LanguageSupport;
import org.fife.rsta.ac.LanguageSupportFactory;
import org.fife.rsta.ac.java.IconFactory;
import org.fife.rsta.ac.java.JavaLanguageSupport;
import org.fife.rsta.ac.java.JavaParser;
import org.fife.rsta.ac.java.rjc.ast.ASTNode;
import org.fife.rsta.ac.java.rjc.ast.CodeBlock;
import org.fife.rsta.ac.java.rjc.ast.CompilationUnit;
import org.fife.rsta.ac.java.rjc.ast.Field;
import org.fife.rsta.ac.java.rjc.ast.ImportDeclaration;
import org.fife.rsta.ac.java.rjc.ast.LocalVariable;
import org.fife.rsta.ac.java.rjc.ast.Member;
import org.fife.rsta.ac.java.rjc.ast.Method;
import org.fife.rsta.ac.java.rjc.ast.Package;
import org.fife.rsta.ac.java.rjc.ast.NormalClassDeclaration;
import org.fife.rsta.ac.java.rjc.ast.NormalInterfaceDeclaration;
import org.fife.rsta.ac.java.rjc.ast.TypeDeclaration;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
/**
* A tree view showing the outline of Java source, similar to the "Outline"
* view in the Eclipse JDT. It also uses Eclipse's icons, just like the rest
* of this code completion library.
*
* You can get this tree automatically updating in response to edits in an
* RSyntaxTextArea
with {@link JavaLanguageSupport} installed by
* calling {@link #listenTo(RSyntaxTextArea)}. Note that, if you have an
* application with multiple RSTA editors, you would want to call this method
* each time a new editor is focused.
*
* @author Robert Futrell
* @version 1.0
*/
public class JavaOutlineTree extends AbstractSourceTree {
private DefaultTreeModel model;
private RSyntaxTextArea textArea;
private JavaParser parser;
private Listener listener;
/**
* Constructor. The tree created will not have its elements sorted
* alphabetically.
*/
public JavaOutlineTree() {
this(false);
}
/**
* Constructor.
*
* @param sorted Whether the tree should sort its elements alphabetically.
* Note that outline trees will likely group nodes by type before
* sorting (i.e. methods will be sorted in one group, fields in
* another group, etc.).
*/
public JavaOutlineTree(boolean sorted) {
setSorted(sorted);
setBorder(BorderFactory.createEmptyBorder(0,8,0,8));
setRootVisible(false);
setCellRenderer(new AstTreeCellRenderer());
model = new DefaultTreeModel(new DefaultMutableTreeNode("Nothing"));
setModel(model);
listener = new Listener();
addTreeSelectionListener(listener);
}
/**
* Refreshes this tree.
*
* @param cu The parsed compilation unit. If this is null
* then the tree is cleared.
*/
private void update(CompilationUnit cu) {
JavaTreeNode root = new JavaTreeNode("Remove me!",
IconFactory.SOURCE_FILE_ICON);
root.setSortable(false);
if (cu==null) {
model.setRoot(root);
return;
}
Package pkg = cu.getPackage();
if (pkg!=null) {
String iconName = IconFactory.PACKAGE_ICON;
root.add(new JavaTreeNode(pkg, iconName, false));
}
if (!getShowMajorElementsOnly()) {
JavaTreeNode importNode = new JavaTreeNode("Imports",
IconFactory.IMPORT_ROOT_ICON);
for (Iterator i=cu.getImportIterator(); i.hasNext(); ) {
ImportDeclaration idec = (ImportDeclaration)i.next();
JavaTreeNode iNode = new JavaTreeNode(idec,
IconFactory.IMPORT_ICON);
importNode.add(iNode);
}
root.add(importNode);
}
for (Iterator i=cu.getTypeDeclarationIterator(); i.hasNext(); ) {
TypeDeclaration td = (TypeDeclaration)i.next();
TypeDeclarationTreeNode dmtn = createTypeDeclarationNode(td);
root.add(dmtn);
}
model.setRoot(root);
root.setSorted(isSorted());
refresh();
expandInitialNodes();
}
/**
* Refreshes listeners on the text area when its syntax style changes.
*/
private void checkForJavaParsing() {
// Remove possible listener on old Java parser (in case they're just
// changing syntax style AWAY from Java)
if (parser!=null) {
parser.removePropertyChangeListener(
JavaParser.PROPERTY_COMPILATION_UNIT, listener);
parser = null;
}
// Get the Java language support (shared by all RSTA instances editing
// Java that were registered with the LanguageSupportFactory).
LanguageSupportFactory lsf = LanguageSupportFactory.get();
LanguageSupport support = lsf.getSupportFor(SyntaxConstants.
SYNTAX_STYLE_JAVA);
JavaLanguageSupport jls = (JavaLanguageSupport)support;
// Listen for re-parsing of the editor, and update the tree accordingly
parser = jls.getParser(textArea);
if (parser!=null) { // Should always be true
parser.addPropertyChangeListener(
JavaParser.PROPERTY_COMPILATION_UNIT, listener);
// Populate with any already-existing CompilationUnit
CompilationUnit cu = parser.getCompilationUnit();
update(cu);
}
else {
update((CompilationUnit)null); // Clear the tree
}
}
private MemberTreeNode createMemberNode(Member member) {
MemberTreeNode node = null;
if (member instanceof CodeBlock) {
node = new MemberTreeNode((CodeBlock)member);
}
else if (member instanceof Field) {
node = new MemberTreeNode((Field)member);
}
else {
node = new MemberTreeNode((Method)member);
}
CodeBlock body = null;
if (member instanceof CodeBlock) {
body = (CodeBlock)member;
}
else if (member instanceof Method) {
body = ((Method)member).getBody();
}
if (body!=null && !getShowMajorElementsOnly()) {
for (int i=0; i