提交 ff5f6fca 编写于 作者: S Skylot

fix(gui): fix "Go to declaration" and "Find usage" menu actions

上级 3578f7d6
......@@ -3,6 +3,9 @@ package jadx.gui.ui.codearea;
import javax.swing.*;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -28,9 +31,8 @@ public final class CodeArea extends AbstractCodeArea {
setSyntaxEditingStyle(node.getSyntaxName());
if (node instanceof JClass) {
JClass jClsNode = (JClass) this.node;
((RSyntaxDocument) getDocument()).setSyntaxStyle(new JadxTokenMaker(this));
addMenuItems(jClsNode);
addMenuItems();
}
setHyperlinksEnabled(true);
......@@ -47,9 +49,9 @@ public final class CodeArea extends AbstractCodeArea {
}
}
private void addMenuItems(JClass jCls) {
FindUsageAction findUsage = new FindUsageAction(contentPanel, this);
GoToDeclarationAction goToDeclaration = new GoToDeclarationAction(contentPanel, this, jCls);
private void addMenuItems() {
FindUsageAction findUsage = new FindUsageAction(this);
GoToDeclarationAction goToDeclaration = new GoToDeclarationAction(this);
JPopupMenu popup = getPopupMenu();
popup.addSeparator();
......@@ -59,11 +61,46 @@ public final class CodeArea extends AbstractCodeArea {
popup.addPopupMenuListener(goToDeclaration);
}
public int adjustOffsetForToken(@Nullable Token token) {
if (token == null) {
return -1;
}
int type = token.getType();
final int sourceOffset;
if (node instanceof JClass) {
if (type == TokenTypes.IDENTIFIER) {
sourceOffset = token.getOffset();
} else if (type == TokenTypes.ANNOTATION && token.length() > 1) {
sourceOffset = token.getOffset() + 1;
} else {
return -1;
}
} else {
if (type == TokenTypes.MARKUP_TAG_ATTRIBUTE_VALUE) {
sourceOffset = token.getOffset() + 1; // skip quote at start (")
} else {
return -1;
}
}
// fast skip
if (token.length() == 1) {
char ch = token.getTextArray()[token.getTextOffset()];
if (ch == '.' || ch == ',' || ch == ';') {
return -1;
}
}
return sourceOffset;
}
/**
* Search node by offset in {@code jCls} code and return its definition position
* (useful for jumps from usage)
*/
@Nullable
public JumpPosition getDefPosForNodeAtOffset(int offset) {
if (offset == -1) {
return null;
}
JavaNode foundNode = getJavaNodeAtOffset(offset);
if (foundNode == null) {
return null;
......
......@@ -9,11 +9,9 @@ import org.fife.ui.rsyntaxtextarea.LinkGenerator;
import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.Token;
import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JNode;
import jadx.gui.ui.ContentPanel;
import jadx.gui.utils.JumpPosition;
......@@ -38,33 +36,10 @@ public class CodeLinkGenerator implements LinkGenerator, HyperlinkListener {
return null;
}
Token token = textArea.modelToToken(offset);
if (token == null) {
int sourceOffset = codeArea.adjustOffsetForToken(token);
if (sourceOffset == -1) {
return null;
}
int type = token.getType();
final int sourceOffset;
if (jNode instanceof JClass) {
if (type == TokenTypes.IDENTIFIER) {
sourceOffset = token.getOffset();
} else if (type == TokenTypes.ANNOTATION && token.length() > 1) {
sourceOffset = token.getOffset() + 1;
} else {
return null;
}
} else {
if (type == TokenTypes.MARKUP_TAG_ATTRIBUTE_VALUE) {
sourceOffset = token.getOffset() + 1; // skip quote at start (")
} else {
return null;
}
}
// fast skip
if (token.length() == 1) {
char ch = token.getTextArray()[token.getTextOffset()];
if (ch == '.' || ch == ',' || ch == ';') {
return null;
}
}
final JumpPosition defPos = codeArea.getDefPosForNodeAtOffset(sourceOffset);
if (defPos == null) {
return null;
......
package jadx.gui.ui.codearea;
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.fife.ui.rsyntaxtextarea.Token;
import jadx.api.JavaNode;
import jadx.gui.treemodel.JNode;
import jadx.gui.ui.ContentPanel;
import jadx.gui.ui.MainWindow;
import jadx.gui.ui.UsageDialog;
import jadx.gui.utils.NLS;
public final class FindUsageAction extends AbstractAction implements PopupMenuListener {
public final class FindUsageAction extends JNodeMenuAction {
private static final long serialVersionUID = 4692546569977976384L;
private final transient ContentPanel contentPanel;
private final transient CodeArea codeArea;
private transient JavaNode node;
public FindUsageAction(ContentPanel contentPanel, CodeArea codeArea) {
super(NLS.str("popup.find_usage"));
this.contentPanel = contentPanel;
this.codeArea = codeArea;
public FindUsageAction(CodeArea codeArea) {
super(NLS.str("popup.find_usage"), codeArea);
}
@Override
public void actionPerformed(ActionEvent e) {
if (node == null) {
if (jumpPos == null) {
return;
}
MainWindow mainWindow = contentPanel.getTabbedPane().getMainWindow();
JNode jNode = mainWindow.getCacheObject().getNodeCache().makeFrom(node);
UsageDialog usageDialog = new UsageDialog(mainWindow, jNode);
MainWindow mainWindow = codeArea.getContentPanel().getTabbedPane().getMainWindow();
UsageDialog usageDialog = new UsageDialog(mainWindow, jumpPos.getNode());
usageDialog.setVisible(true);
}
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
node = null;
Point pos = codeArea.getMousePosition();
if (pos != null) {
Token token = codeArea.viewToToken(pos);
if (token != null) {
node = codeArea.getJavaNodeAtOffset(token.getOffset());
}
}
setEnabled(node != null);
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// do nothing
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
}
}
package jadx.gui.ui.codearea;
import java.awt.Point;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.fife.ui.rsyntaxtextarea.Token;
import jadx.api.JavaNode;
import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JNode;
import jadx.gui.ui.ContentPanel;
import jadx.gui.ui.MainWindow;
import jadx.gui.utils.JumpPosition;
import jadx.gui.utils.NLS;
public final class GoToDeclarationAction extends AbstractAction implements PopupMenuListener {
public final class GoToDeclarationAction extends JNodeMenuAction {
private static final long serialVersionUID = -1186470538894941301L;
private final transient ContentPanel contentPanel;
private final transient CodeArea codeArea;
private final transient JClass jCls;
private transient JavaNode node;
public GoToDeclarationAction(ContentPanel contentPanel, CodeArea codeArea, JClass jCls) {
super(NLS.str("popup.go_to_declaration"));
this.contentPanel = contentPanel;
this.codeArea = codeArea;
this.jCls = jCls;
public GoToDeclarationAction(CodeArea codeArea) {
super(NLS.str("popup.go_to_declaration"), codeArea);
}
@Override
public void actionPerformed(ActionEvent e) {
if (node == null) {
return;
if (jumpPos != null) {
codeArea.getContentPanel().getTabbedPane().codeJump(jumpPos);
}
MainWindow mainWindow = contentPanel.getTabbedPane().getMainWindow();
JNode jNode = mainWindow.getCacheObject().getNodeCache().makeFrom(node);
mainWindow.getTabbedPane().codeJump(new JumpPosition(jNode, jNode.getLine()));
}
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
node = null;
Point pos = codeArea.getMousePosition();
if (pos != null) {
Token token = codeArea.viewToToken(pos);
if (token != null) {
node = codeArea.getJavaNodeAtOffset(token.getOffset());
}
}
setEnabled(node != null);
}
super.popupMenuWillBecomeVisible(e);
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// do nothing
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
putValue(Action.SMALL_ICON, jumpPos == null ? null : jumpPos.getNode().getIcon());
}
}
package jadx.gui.ui.codearea;
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.fife.ui.rsyntaxtextarea.Token;
import org.jetbrains.annotations.Nullable;
import jadx.gui.utils.JumpPosition;
public abstract class JNodeMenuAction extends AbstractAction implements PopupMenuListener {
protected final transient CodeArea codeArea;
@Nullable
protected transient JumpPosition jumpPos;
public JNodeMenuAction(String name, CodeArea codeArea) {
super(name);
this.codeArea = codeArea;
}
@Override
public abstract void actionPerformed(ActionEvent e);
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
jumpPos = getJumpPos();
setEnabled(jumpPos != null);
}
@Nullable
private JumpPosition getJumpPos() {
Point pos = codeArea.getMousePosition();
if (pos != null) {
Token token = codeArea.viewToToken(pos);
int offset = codeArea.adjustOffsetForToken(token);
return codeArea.getDefPosForNodeAtOffset(offset);
}
return null;
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// do nothing
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册