fix(gui): fix "Go to declaration" and "Find usage" menu actions
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -1,66 +1,25 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +1,30 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user