⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sourcebrowserplugin.java~1~

📁 具有不同语法高亮的编辑器实例
💻 JAVA~1~
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -