📄 sourcebrowserplugin.java~1~
字号:
/*
* 07/08/2004
*
* SourceBrowserPlugin.java - A panel that uses Exhuberant CTags to keep a list
* of variables, functions, etc. in the currently open source file in RText.
* Copyright (C) 2004 Robert Futrell
* email@address.com
* www.website.com
*
* This file is a part of RText.
*
* RText is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* RText is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.fife.rtext.plugins.sourcebrowser;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ResourceBundle;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.TreeUI;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.text.Element;
import javax.swing.tree.*;
import org.fife.RTreeSelectionModel;
import org.fife.ctags.TagEntry;
import org.fife.rtext.*;
import org.fife.ui.OptionsDialogPanel;
import org.fife.ui.RScrollPane;
import org.fife.ui.app.*;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.search.FindDialog;
/**
* A panel that uses Exhuberant CTags (installed separately from RText) to keep
* a list of all variables, functions, classes, methods, etc. defined in the
* currently-opened source file. Clicking on an item in the Source Browser
* moves the cursor to that item's position in the source file; also, right-
* clicking on an item displays a popup menu.
*
* @author Robert Futrell
* @version 1.1
*/
public class SourceBrowserPlugin extends GUIPlugin
implements CurrentTextAreaListener, MouseListener,
MouseMotionListener, TreeSelectionListener, ActionListener {
private static final int MAX_NUM_HASH_MAPS = 12; // Longest string length in knownTagTypes.
private static final String[] knownTagTypes = {
"", // NO_SYNTAX_STYLE
"", // ASM_X86_SYNTAX_STYLE
"cdfgmnstv", // C_SYNTAX_STYLE
"cdfgmnstv", // CPLUSPLUS_SYNTAX_STYLE
"cdEfgimnpqst", // CSHARP_SYNTAX_STYLE
"", // CSS_SYNTAX_STYLE
"bcefklmnpstv", // FORTRAN_SYNTAX_STYLE
"af", // HTML_SYNTAX_STYLE
"cfimp", // JAVA_SYNTAX_STYLE
"f", // JAVASCRIPT_SYNTAX_STYLE
"cls", // PERL_SYNTAX_STYLE
"", // PROPERTIES_FILE_SYNTAX_STYLE
"cfm", // PYTHON_SYNTAX_STYLE
"", // SAS_SYNTAX_STYLE
"cfFLPprstTv", // SQL_SYNTAX_STYLE
"f", // UNIX_SHELL_SYNTAX_STYLE
"", // WINDOWS_BATCH_SYNTAX_STYLE
"", // XML_SYNTAX_STYLE
};
private RText owner;
private String name;
private JTree sourceTree;
private SourceTreeCellRenderer treeRenderer;
private DefaultTreeModel treeModel;
private RScrollPane scrollPane;
private ResourceBundle msg;
private String lineFoundText;
private String cantFindLineText;
private Icon fileIcon;
private Icon pluginIcon;
private boolean useHTMLToolTips;
private String ctagsExecutableLocation;
private File ctagsFile; // Just for speed.
private HashMap map; // Hash map of array lists (tag type=>array list).
private ArrayList[] arrayListBuffer; // Cached array lists for performance.
private JPopupMenu rightClickMenu; // For the user right-clicking a node.
private int mouseX;
private int mouseY; // Where mouse was right-clicked.
private SourceBrowserOptionPanel optionPanel;
static final String BUNDLE_NAME =
"org.fife.rtext.plugins.sourcebrowser.SourceBrowser";
private static final String YELLOW_BULLET =
"org/fife/rtext/plugins/sourcebrowser/bullet_blue.gif";
private static final String GREEN_BULLET =
"org/fife/rtext/plugins/sourcebrowser/bullet_green.gif";
private static final String VERSION_STRING = "0.9.4.0";
/*****************************************************************************/
/**
* Creates a new <code>SourceBrowserPlugin</code>.
*
* @param app The RText instance.
*/
public SourceBrowserPlugin(AbstractPluggableGUIApplication app) {
this.owner = (RText)app;
ClassLoader cl = this.getClass().getClassLoader();
URL url = cl.getResource("org/fife/rtext/plugins/sourcebrowser/sourcebrowser.gif");
if (url!=null)
pluginIcon = new ImageIcon(url);
msg = ResourceBundle.getBundle(BUNDLE_NAME, getLocale(), cl);
this.name = msg.getString("Name");
this.lineFoundText = msg.getString("StatusBarMsg.FoundLine");
this.cantFindLineText = msg.getString("StatusBarMsg.CantFindLine");
setLayout(new BorderLayout());
// Create our tree of methods, etc.
sourceTree = new JTree() {
public void setUI(TreeUI ui) {
// Force us to always have this UI.
super.setUI(new SourceBrowserTreeUI());
}
};
sourceTree.setToggleClickCount(1);
treeRenderer = new SourceTreeCellRenderer();
sourceTree.setCellRenderer(treeRenderer);
sourceTree.setSelectionModel(new RTreeSelectionModel());
sourceTree.addTreeSelectionListener(this);
treeModel = new DefaultTreeModel(null);
sourceTree.setModel(treeModel);
ToolTipManager.sharedInstance().registerComponent(sourceTree);
sourceTree.addMouseMotionListener(this);
sourceTree.addMouseListener(this);
scrollPane = new RScrollPane(sourceTree);
//scrollPane.setViewportBorder(
// BorderFactory.createEmptyBorder(3,3,3,3));
add(scrollPane);
map = new HashMap();
arrayListBuffer = new ArrayList[MAX_NUM_HASH_MAPS];
for (int i=0; i<MAX_NUM_HASH_MAPS; i++) {
arrayListBuffer[i] = new ArrayList();
}
// Set any preferences saved from the last time this plugin was used.
SourceBrowserPreferences sbp = (SourceBrowserPreferences)
SourceBrowserPreferences.load();
setActive(sbp.active);
setPosition(sbp.position);
setCTagsExecutableLocation(sbp.ctagsExecutable);
setUseHTMLToolTips(sbp.useHTMLToolTips);
}
/*****************************************************************************/
/**
* Listens for actions in this component.
*/
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
int row = sourceTree.getClosestRowForLocation(mouseX, mouseY);
// Go to the tag's location in the current file.
if (actionCommand.equals("JumpToTag")) {
sourceTree.setSelectionRow(row);
}
// Insert the tag at the current caret position.
else if (actionCommand.equals("InsertAtCaret")) {
owner.getMainView().currentTextArea.replaceSelection(
getTagTextForRow(row));
owner.getMainView().currentTextArea.requestFocusInWindow();
}
}
/*****************************************************************************/
/**
* Adds a node to the ctags tree containing one child for each tag entry
* passed in.
*
* @param root The root of the ctags tree.
* @param title The title for this node.
* @param contents An array of <code>org.fife.ctags.TagEntry</code>s and
* <code>String</code>s to add as children of this node.
*/
private void addTagTypeNode(DefaultMutableTreeNode root, String title,
Object contents) {
List contentsList = (List)contents;
DefaultMutableTreeNode node = new DefaultMutableTreeNode();
int size = contentsList==null ? 0 : contentsList.size();
for (int i=0; i<size; i++) {
node.add(new DefaultMutableTreeNode(contentsList.get(i)));
}
node.setUserObject(title + " (" + size + ")");
root.add(node);
}
/*****************************************************************************/
/**
* Creates a preferences instance for this GUI plugin based on its
* current properties. Your GUI plugin should create a subclass of
* <code>GUIPluginPreferences</code> that loads and saves properties
* specific to your plugin, and return it from this method.
*
* @return A preferences instance.
* @see org.fife.ui.app.GUIPluginPreferences
*/
protected GUIPluginPreferences createPreferences() {
return (GUIPluginPreferences)SourceBrowserPreferences.
generatePreferences(this);
}
/*****************************************************************************/
/**
* Creates the right-click menu. This menu contains options for things
* such as going to the specified tag, inserting the tag at the current
* caret position, etc.
*/
private void createRightClickMenu() {
rightClickMenu = new JPopupMenu();
// Create a menu item for inserting the tag at the current caret
// location.
JMenuItem menuItem = new JMenuItem("foo");
menuItem.setActionCommand("InsertAtCaret");
menuItem.addActionListener(this);
rightClickMenu.add(menuItem);
// Create a menu item for jumping to a tag's location.
menuItem = new JMenuItem("bar");
menuItem.setActionCommand("JumpToTag");
menuItem.addActionListener(this);
rightClickMenu.add(menuItem);
}
/*****************************************************************************/
/**
* Called whenever the currently-active document in RText changes, or
* one of its properties changes. We are looking for cues to update
* our source browser tree.
*/
public void currentTextAreaPropertyChanged(CurrentTextAreaEvent e) {
// Don't worry about it if we're not visible.
if (!isActive()/* || !isShowing()*/)
return;
int type = e.getType();
boolean doChange =
(type==CurrentTextAreaEvent.TEXT_AREA_CHANGED) ||
(type==CurrentTextAreaEvent.IS_MODIFIED_CHANGED &&
((Boolean)e.getNewValue())==Boolean.FALSE) ||
(type==CurrentTextAreaEvent.FILE_NAME_CHANGED);
if (doChange) {
// If we cannot find the ctags executable, quit now.
if (ctagsFile==null || !ctagsFile.isFile()) {
setErrorMessage(msg.getString("Error.ExeNotFound"));
return;
}
// Otherwise, parse the file.
try {
// First, determine what language the user is programming in
// (via the text editor's syntax highlighting style). We do
// it this way because the user may have some odd extension
// (like .abc) mapped to say C source files.
RTextEditorPane textArea = owner.getMainView().
getCurrentTextArea();
int style = textArea.getSyntaxEditingStyle();
String language = getLanguageForStyle(style);
if (language==null) {
// Language not supported by ctags.
treeModel.setRoot(null);//root);
return;
}
// Create data structures in which we can store the tags.
map.clear();
int count = knownTagTypes[style].length();
for (int i=0; i<count; i++) {
arrayListBuffer[i].clear();
String tagType = knownTagTypes[style].substring(i,i+1);
map.put(tagType, arrayListBuffer[i]);
}
// Create a command line to run ctags.
String sourceFile = textArea.getFileFullPath();
fileIcon = FileTypeIconManager.getInstance().
getIconFor(textArea);
String toExecute = ctagsExecutableLocation +
" -f - --language-force=" + language +
" \"" + sourceFile +"\"";
// Run the process and collect its output in a separate
// thread, but wait on the thread to complete. We do it
// this way so that we can put a "time limit" on the process
// to complete, so that if something bad happens to it
// (e.g. ctags 5.5.4 has a bug that sometimes makes it run
// forever), we can give up and kill it.
ReaderThread t = new ReaderThread();
t.start(toExecute);
t.join(10000); // 10 seconds max, in milliseconds.
if (t.isAlive()) {
// If the process is still alive, we assume it's
// a runaway process.
System.err.println("... interrupting runaway ctags!");
t.interrupt();
t.destroyProcessIfNecessary();
t = null;
setErrorMessage(msg.getString("Error.RunawayProcess"));
return;
}
// Better safe than sorry...
t.destroyProcessIfNecessary();
t = null;
// Sets the tree stuff.
DefaultMutableTreeNode root = new DefaultMutableTreeNode(
textArea.getFileName());
switch (style) {
case SyntaxConstants.C_SYNTAX_STYLE:
case SyntaxConstants.CPLUSPLUS_SYNTAX_STYLE:
addTagTypeNode(root, "Classes", map.get("c"));
addTagTypeNode(root, "Macros", map.get("d"));
addTagTypeNode(root, "Functions", map.get("f"));
addTagTypeNode(root, "Enumerations", map.get("g"));
addTagTypeNode(root, "Class/Struct/Union members", map.get("m"));
addTagTypeNode(root, "Namespaces", map.get("n"));
addTagTypeNode(root, "Structs", map.get("s"));
addTagTypeNode(root, "Typedefs", map.get("t"));
addTagTypeNode(root, "Variables", map.get("v"));
break;
case SyntaxConstants.CSHARP_SYNTAX_STYLE:
addTagTypeNode(root, "Classes", map.get("c"));
addTagTypeNode(root, "Macros", map.get("d"));
addTagTypeNode(root, "Events", map.get("E"));
addTagTypeNode(root, "Fields", map.get("f"));
addTagTypeNode(root, "Enumerations", map.get("g"));
addTagTypeNode(root, "Interfaces", map.get("i"));
addTagTypeNode(root, "Methods", map.get("m"));
addTagTypeNode(root, "Namespaces", map.get("n"));
addTagTypeNode(root, "Properties", map.get("p"));
addTagTypeNode(root, "Structs", map.get("s"));
addTagTypeNode(root, "Typedefs", map.get("t"));
break;
case SyntaxConstants.FORTRAN_SYNTAX_STYLE:
addTagTypeNode(root, "Block Data", map.get("b"));
addTagTypeNode(root, "Common Blocks", map.get("c"));
addTagTypeNode(root, "Entry Points", map.get("e"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -