fix: workaround for link clicks in RSyntaxTextArea (#929)

This commit is contained in:
Skylot
2020-05-08 19:53:20 +01:00
parent 692536c584
commit 45b7304630
2 changed files with 57 additions and 21 deletions
@@ -1,5 +1,9 @@
package jadx.gui.ui.codearea;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import org.fife.ui.rsyntaxtextarea.RSyntaxDocument;
@@ -38,9 +42,21 @@ public final class CodeArea extends AbstractCodeArea {
}
setHyperlinksEnabled(true);
CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(this);
setLinkGenerator(codeLinkProcessor);
addHyperlinkListener(codeLinkProcessor);
setLinkScanningMask(InputEvent.CTRL_DOWN_MASK);
CodeLinkGenerator codeLinkGenerator = new CodeLinkGenerator(this);
setLinkGenerator(codeLinkGenerator);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.isControlDown()) {
int offs = viewToModel(e.getPoint());
JumpPosition jump = codeLinkGenerator.getJumpLinkAtOffset(CodeArea.this, offs);
if (jump != null) {
contentPanel.getTabbedPane().codeJump(jump);
}
}
}
});
}
@Override
@@ -3,52 +3,61 @@ package jadx.gui.ui.codearea;
import java.util.Objects;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException;
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.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.gui.treemodel.JNode;
import jadx.gui.ui.ContentPanel;
import jadx.gui.utils.JumpPosition;
public class CodeLinkGenerator implements LinkGenerator, HyperlinkListener {
public class CodeLinkGenerator implements LinkGenerator {
private static final Logger LOG = LoggerFactory.getLogger(CodeLinkGenerator.class);
private final ContentPanel contentPanel;
private final CodeArea codeArea;
private final JNode jNode;
public CodeLinkGenerator(CodeArea codeArea) {
this.contentPanel = codeArea.getContentPanel();
this.codeArea = codeArea;
this.jNode = codeArea.getNode();
}
@Nullable
public JumpPosition getJumpLinkAtOffset(RSyntaxTextArea textArea, int offset) {
try {
if (jNode.getCodeInfo() == null) {
return null;
}
int sourceOffset = getLinkSourceOffset(textArea, offset);
if (sourceOffset == -1) {
return null;
}
return getJumpBySourceOffset(textArea, sourceOffset);
} catch (Exception e) {
LOG.error("getJumpLinkAtOffset error", e);
return null;
}
}
@Override
public LinkGeneratorResult isLinkAtOffset(RSyntaxTextArea textArea, int offset) {
try {
if (jNode.getCodeInfo() == null) {
return null;
}
Token token = textArea.modelToToken(offset);
int sourceOffset = codeArea.adjustOffsetForToken(token);
int sourceOffset = getLinkSourceOffset(textArea, offset);
if (sourceOffset == -1) {
return null;
}
final JumpPosition defPos = codeArea.getDefPosForNodeAtOffset(sourceOffset);
JumpPosition defPos = getJumpBySourceOffset(textArea, sourceOffset);
if (defPos == null) {
return null;
}
if (Objects.equals(defPos.getNode().getRootClass(), jNode)
&& defPos.getLine() == textArea.getLineOfOffset(sourceOffset) + 1) {
// ignore self jump
return null;
}
return new LinkGeneratorResult() {
@Override
public HyperlinkEvent execute() {
@@ -67,11 +76,22 @@ public class CodeLinkGenerator implements LinkGenerator, HyperlinkListener {
}
}
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
Object obj = e.getSource();
if (obj instanceof JumpPosition) {
contentPanel.getTabbedPane().codeJump((JumpPosition) obj);
private int getLinkSourceOffset(RSyntaxTextArea textArea, int offset) {
Token token = textArea.modelToToken(offset);
return codeArea.adjustOffsetForToken(token);
}
@Nullable
private JumpPosition getJumpBySourceOffset(RSyntaxTextArea textArea, int sourceOffset) throws BadLocationException {
final JumpPosition defPos = codeArea.getDefPosForNodeAtOffset(sourceOffset);
if (defPos == null) {
return null;
}
if (Objects.equals(defPos.getNode().getRootClass(), jNode)
&& defPos.getLine() == textArea.getLineOfOffset(sourceOffset) + 1) {
// ignore self jump
return null;
}
return defPos;
}
}