📄 sourcebrowserplugin.java~1~
字号:
// that this should always be a TagEntry, but we're just being
// safe by checking here.
else if (object instanceof TagEntry) {
ExtendedTagEntry entry = (ExtendedTagEntry)object;
// If we've already generated the (probably HTML) tooltip text,
// use it.
if (entry.cachedToolTipText!=null) {
text = entry.cachedToolTipText;
}
// Create the tooltip text (HTML, or just text if only a line
// number was found (such as #defines for C/C++).
else {
text = entry.pattern;
// If we have a pattern, try to create an HTML tooltip.
if (text!=null) {
// To trim off the "regular expression" parts.
text = text.substring(2, text.length()-2);
if (getUseHTMLToolTips()) {
// FIXME: Fix me to look line by line (as it's
// guaranteed to be just a a line!).
RTextEditorPane textArea = owner.getMainView().
currentTextArea;
String pattern = RTextUtilities.
getRegularExpressionForLine(text, true);
if (pattern!=null) { // i.e., the regex is okay.
Point pos = FindDialog.getNextMatchPosRegEx(pattern,
textArea.getText(), 0, true, true, false);
if (pos!=null) {
try {
int line = textArea.getLineOfOffset(pos.x);
text = getHTMLForLine(line);
entry.cachedToolTipText = text;
} catch (javax.swing.text.BadLocationException ble) {
owner.displayException(ble);
}
}
}
}
}
// If all we have is a line number, use the tag's element's
// name as the tooltip.
else {
text = entry.name.replaceAll("\t", " ");
}
} // End of else.
} // End of else if (object instanceof TagEntry).
// Set the tooltip text.
treeRenderer.setToolTipText(text);
}
/*****************************************************************************/
/**
* Called when the user downclicks in the ctags tree.
*/
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
/*****************************************************************************/
/**
* Called when the user up-clicks in the ctags tree.
*/
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
/*****************************************************************************/
/**
* Refreshes the tag list for the current document.
*/
public void refresh() {
// Tricks this browser into refreshing its tree using the new
// ctags location.
currentTextAreaPropertyChanged(new CurrentTextAreaEvent(
owner.getMainView(),
CurrentTextAreaEvent.TEXT_AREA_CHANGED,
null, owner.getMainView().currentTextArea));
}
/*****************************************************************************/
/**
* Sets the path used to run the ctags executable.
*
* @return The path to use.
* @see #getCTagsExecutableLocation
*/
public void setCTagsExecutableLocation(String location) {
if (ctagsExecutableLocation==null ||
!ctagsExecutableLocation.equals(location)) {
ctagsExecutableLocation = location;
ctagsFile = location==null ? null : new File(location);
refresh(); // Redo ctags list with new executable.
}
}
/*****************************************************************************/
/**
* Makes the "tags tree" display an error message.
*
* @param errorMessage The message to display.
*/
private void setErrorMessage(String message) {
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
DefaultMutableTreeNode node = new DefaultMutableTreeNode(message);
root.add(node);
treeModel.setRoot(root);
}
/*****************************************************************************/
/**
* Sets whether HTML tooltips are used in this source browser.
*
* @param use Whether or not to use HTML tooltips.
* @see #getUseHTMLToolTips
*/
public void setUseHTMLToolTips(boolean use) {
useHTMLToolTips = use;
}
/*****************************************************************************/
/**
* Called just before this <code>Plugin</code> is removed from an
* RText instance. Here we uninstall any listeners we registered.
*
* @return Whether the uninstall went cleanly.
*/
public boolean uninstall() {
owner.getMainView().removeCurrentTextAreaListener(this);
return true;
}
/*****************************************************************************/
/**
* This method is overridden so that the embedded tree and its right-
* click popup menu are updated.
*/
public void updateUI() {
super.updateUI();
if (sourceTree!=null) {
treeRenderer = new SourceTreeCellRenderer();
sourceTree.setCellRenderer(treeRenderer); // So it picks up new LnF's colors??
}
if (rightClickMenu!=null)
javax.swing.SwingUtilities.updateComponentTreeUI(rightClickMenu);
}
/*****************************************************************************/
/**
* Called when the user clicks on a tree node. This method attempts to
* find the declaration of the selected item in the current text area, and
* if it is found (which it should be, unless it was removed, it is
* selected.
*
* @param e The tree selection event.
*/
public void valueChanged(TreeSelectionEvent e) {
TreePath path = sourceTree.getSelectionPath();
// Must check for null, otherwise we get an exception on shutdown.
if (path!=null) {
Object object = ((DefaultMutableTreeNode)path.
getLastPathComponent()).getUserObject();
if (object instanceof TagEntry) {
TagEntry entry = (TagEntry)object;
RTextEditorPane textArea = owner.getMainView().currentTextArea;
if (entry.pattern!=null) {
// FIXME: Fix me to look line by line (as it's
// guaranteed to be just a a line!).
String pattern = RTextUtilities.getRegularExpressionForLine(
entry.pattern.substring(2, entry.pattern.length()-2), true);
if (pattern!=null) { // i.e., the regex is okay.
Point pos = FindDialog.getNextMatchPosRegEx(pattern,
textArea.getText(), 0, true, true, false);
if (pos!=null) {
textArea.setCaretPosition(pos.x);
textArea.moveCaretPosition(pos.y);
owner.setMessages(null, lineFoundText);
}
else {
UIManager.getLookAndFeel().
provideErrorFeedback(this);
owner.setMessages(null, cantFindLineText);
}
}
}
else { // Must use line number (used by C macros, for instance).
Element map = textArea.getDocument().getDefaultRootElement();
Element line = map.getElement((int)entry.lineNumber-1);
textArea.setCaretPosition(line.getStartOffset());
textArea.moveCaretPosition(line.getEndOffset()-1);
}
textArea.requestFocusInWindow(); // So we can see the highlighted line.
}
}
}
/*****************************************************************************/
/************************* INNER CLASSES *************************************/
/*****************************************************************************/
/**
* A tag entry with an extra field to cache the tooltip text.
*/
class ExtendedTagEntry extends TagEntry {
public String cachedToolTipText;
public ExtendedTagEntry(String line) {
super(line);
}
}
/*****************************************************************************/
/**
* Sets the appropriate icons for tree nodes (the '+' and '-' icons
* for nodes that can be expanded/contracted).
*/
class SourceTreeCellRenderer extends DefaultTreeCellRenderer {
private Icon yellowBullet;
private Icon greenBullet;
public SourceTreeCellRenderer() {
super();
PluginClassLoader cl = (PluginClassLoader)this.getClass().
getClassLoader();
yellowBullet = new ImageIcon(cl.getResource(YELLOW_BULLET));
greenBullet = new ImageIcon(cl.getResource(GREEN_BULLET));
}
public Component getTreeCellRendererComponent(JTree tree,
Object value, boolean sel, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel,
expanded, leaf, row, hasFocus);
// /*
Object obj = ((DefaultMutableTreeNode)value).getUserObject();
if (obj instanceof String) { // As opposed to TagEntry.
String str = (String)obj;
int index = str.indexOf('(');
if (index>-1) { // Not true if ctags not found.
setText("<html>" + str.substring(0,index) + "<b>" +
str.substring(index) + "</b></html>");
}
}
// */
if (leaf && value.toString().indexOf("(0)")==-1) {
setIcon(greenBullet);
}
else {
setIcon(row==0 ? fileIcon : yellowBullet);
}
return this;
}
}
/*****************************************************************************/
/**
* UI for the source browser tree. This class allows for any number of
* left-mouse-button clicks to toggle a tree branch's expanded state.
*/
class SourceBrowserTreeUI extends BasicTreeUI {
/**
* Overridden so any number of left mouse clicks toggles the tree
* node's expansion.
*/
protected boolean isToggleEvent(MouseEvent e) {
if(!SwingUtilities.isLeftMouseButton(e))
return false;
return true;
}
}
/*****************************************************************************/
/**
* Reads output of the SourceBrowser process in a separate thread. We
* do this because ctags 5.5.4 (at least on Windows) will freeze if you
* have it parse an invalid source file (such as a Java file containing
* only "ssss"). Running this in a separate thread allows us to kill the
* thread if the process takes too long to end and prevent the GUI from
* locking up. Not doing this would result in the user having to kill
* the main RText process, as well as the then-zombied ctags process.
*/
private class ReaderThread extends Thread {
private String toExecute;
private Process process;
private Object stopKey;
public void destroyProcessIfNecessary() {
// Be sure and always kill the process!
if (process!=null) {
process.destroy();
process = null;
}
}
public void run() {
try {
process = Runtime.getRuntime().exec(toExecute);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
//process.waitFor();
String line = reader.readLine();
while (line!=null && stopKey!=null) {
TagEntry entry = new ExtendedTagEntry(line);
ArrayList list = (ArrayList)map.get(entry.kind);
if (list!=null) { // A supported tag type for this language.
// Get rid of any escapes added for '/''s.
if (entry.pattern!=null)
entry.pattern = entry.pattern.replaceAll("\\\\/", "/");
list.add(entry);
}
line = reader.readLine();
}
reader.close();
} catch (Throwable t) {
t.printStackTrace();
} finally {
destroyProcessIfNecessary();
}
}
public void start(String toExecute) {
stopKey = this;
this.toExecute = toExecute;
super.start();
}
// Recommended by Java's API as a "safe" way to stop a thread.
// stop() is deprecated and is unsafe, so we must set up a variable
// that is polled periodically by the thread.
public void stopSafely() {
stopKey = null;
}
}
/*****************************************************************************/
/**
* Toggles the visibility of this source browser.
*/
private class ViewAction extends AbstractAction {
public ViewAction(ResourceBundle msg) {
putValue(NAME, msg.getString("MenuItem.View"));
putValue(MNEMONIC_KEY, new Integer(
msg.getString("MenuItem.View.Mnemonic").charAt(0)));
putValue(LONG_DESCRIPTION, msg.getString("MenuItem.View.Desc"));
}
public void actionPerformed(ActionEvent e) {
setActive(!isActive());
}
}
/*****************************************************************************/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -