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

📄 sourcebrowserplugin.java

📁 具有不同语法高亮的编辑器实例
💻 JAVA
📖 第 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"));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -