gui: add hyperlinks for classes and fields
This commit is contained in:
@@ -36,7 +36,6 @@ public class JadxWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void saveAll(final File dir, final ProgressMonitor progressMonitor) {
|
||||
Runnable save = new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -106,6 +106,10 @@ public class JClass extends JNode {
|
||||
return jParent.getRootClass();
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return cls.getFullName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return cls.getDecompiledLine();
|
||||
|
||||
@@ -2,6 +2,7 @@ package jadx.gui.ui;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.utils.Position;
|
||||
|
||||
import javax.swing.JViewport;
|
||||
import javax.swing.SwingUtilities;
|
||||
@@ -64,7 +65,7 @@ class CodeArea extends RSyntaxTextArea {
|
||||
|
||||
private boolean isJumpToken(Token token) {
|
||||
if (token.getType() == TokenTypes.IDENTIFIER) {
|
||||
CodePosition pos = getCodePosition(cls, this, token.getOffset());
|
||||
Position pos = getPosition(cls, this, token.getOffset());
|
||||
if (pos != null) {
|
||||
return true;
|
||||
}
|
||||
@@ -80,15 +81,22 @@ class CodeArea extends RSyntaxTextArea {
|
||||
return super.getUnderlineForToken(t);
|
||||
}
|
||||
|
||||
static CodePosition getCodePosition(JClass jCls, RSyntaxTextArea textArea, int offset) {
|
||||
static Position getPosition(JClass jCls, RSyntaxTextArea textArea, int offset) {
|
||||
try {
|
||||
int line = textArea.getLineOfOffset(offset);
|
||||
int lineOffset = offset - textArea.getLineStartOffset(line);
|
||||
return jCls.getCls().getDefinitionPosition(line + 1, lineOffset + 1);
|
||||
CodePosition pos = jCls.getCls().getDefinitionPosition(line + 1, lineOffset + 1);
|
||||
if (pos != null && pos.isSet()) {
|
||||
return new Position(pos);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
LOG.error("Can't get line by offset", e);
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Position getCurrentPosition() {
|
||||
return new Position(cls, getCaretLineNumber());
|
||||
}
|
||||
|
||||
void scrollToLine(int line) {
|
||||
@@ -145,14 +153,14 @@ class CodeArea extends RSyntaxTextArea {
|
||||
if (token != null) {
|
||||
offset = token.getOffset();
|
||||
}
|
||||
final CodePosition defPos = getCodePosition(jCls, textArea, offset);
|
||||
final Position defPos = getPosition(jCls, textArea, offset);
|
||||
if (defPos != null) {
|
||||
final int sourceOffset = offset;
|
||||
return new LinkGeneratorResult() {
|
||||
@Override
|
||||
public HyperlinkEvent execute() {
|
||||
return new HyperlinkEvent(defPos, HyperlinkEvent.EventType.ACTIVATED, null,
|
||||
defPos.getJavaClass().getFullName());
|
||||
defPos.getCls().getFullName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,11 +178,13 @@ class CodeArea extends RSyntaxTextArea {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
Object obj = e.getSource();
|
||||
if (obj instanceof CodePosition) {
|
||||
CodePosition pos = (CodePosition) obj;
|
||||
JClass cls = new JClass(pos.getJavaClass());
|
||||
codePanel.getCodePanel().showCode(cls, pos.getLine());
|
||||
if (obj instanceof Position) {
|
||||
Position pos = (Position) obj;
|
||||
LOG.debug("Code jump to: {}", pos);
|
||||
TabbedPane tabbedPane = codePanel.getTabbedPane();
|
||||
tabbedPane.getJumpManager().addPosition(getCurrentPosition());
|
||||
tabbedPane.getJumpManager().addPosition(pos);
|
||||
tabbedPane.showCode(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,14 +17,14 @@ class CodePanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 5310536092010045565L;
|
||||
|
||||
private final TabbedPane codePanel;
|
||||
private final TabbedPane tabbedPane;
|
||||
private final JClass jClass;
|
||||
private final SearchBar searchBar;
|
||||
private final CodeArea codeArea;
|
||||
private final RTextScrollPane scrollPane;
|
||||
|
||||
CodePanel(TabbedPane panel, JClass cls) {
|
||||
codePanel = panel;
|
||||
tabbedPane = panel;
|
||||
jClass = cls;
|
||||
codeArea = new CodeArea(this);
|
||||
searchBar = new SearchBar(codeArea);
|
||||
@@ -49,8 +49,8 @@ class CodePanel extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
TabbedPane getCodePanel() {
|
||||
return codePanel;
|
||||
TabbedPane getTabbedPane() {
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
JClass getCls() {
|
||||
|
||||
@@ -61,6 +61,9 @@ public class MainWindow extends JFrame {
|
||||
private static final ImageIcon ICON_FLAT_PKG = Utils.openIcon("empty_logical_package_obj");
|
||||
private static final ImageIcon ICON_SEARCH = Utils.openIcon("magnifier");
|
||||
|
||||
private static final ImageIcon ICON_BACK = Utils.openIcon("icon_back");
|
||||
private static final ImageIcon ICON_FORWARD = Utils.openIcon("icon_forward");
|
||||
|
||||
private final JadxWrapper wrapper;
|
||||
|
||||
private JPanel mainPanel;
|
||||
@@ -219,6 +222,26 @@ public class MainWindow extends JFrame {
|
||||
|
||||
toolbar.addSeparator();
|
||||
|
||||
final JButton backButton = new JButton(ICON_BACK);
|
||||
backButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tabbedPane.navBack();
|
||||
}
|
||||
});
|
||||
backButton.setToolTipText(NLS.str("nav.back"));
|
||||
toolbar.add(backButton);
|
||||
|
||||
final JButton forwardButton = new JButton(ICON_FORWARD);
|
||||
forwardButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tabbedPane.navForward();
|
||||
}
|
||||
});
|
||||
forwardButton.setToolTipText(NLS.str("nav.forward"));
|
||||
toolbar.add(forwardButton);
|
||||
|
||||
mainPanel.add(toolbar, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package jadx.gui.ui;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.utils.JumpManager;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.Position;
|
||||
import jadx.gui.utils.Utils;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
@@ -36,6 +38,7 @@ class TabbedPane extends JTabbedPane {
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final Map<JClass, CodePanel> openTabs = new LinkedHashMap<JClass, CodePanel>();
|
||||
private JumpManager jumps = new JumpManager();
|
||||
|
||||
TabbedPane(MainWindow window) {
|
||||
mainWindow = window;
|
||||
@@ -63,18 +66,40 @@ class TabbedPane extends JTabbedPane {
|
||||
}
|
||||
|
||||
void showCode(final JClass cls, final int line) {
|
||||
final CodePanel codePanel = getCodePanel(cls);
|
||||
showCode(new Position(cls, line));
|
||||
}
|
||||
|
||||
void showCode(final Position pos) {
|
||||
final CodePanel codePanel = getCodePanel(pos.getCls());
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setSelectedComponent(codePanel);
|
||||
CodeArea codeArea = codePanel.getCodeArea();
|
||||
codeArea.scrollToLine(line);
|
||||
codeArea.scrollToLine(pos.getLine());
|
||||
codeArea.requestFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void navBack() {
|
||||
Position pos = jumps.getPrev();
|
||||
if (pos != null) {
|
||||
showCode(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public void navForward() {
|
||||
Position pos = jumps.getNext();
|
||||
if (pos != null) {
|
||||
showCode(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public JumpManager getJumpManager() {
|
||||
return jumps;
|
||||
}
|
||||
|
||||
private void addCodePanel(CodePanel codePanel) {
|
||||
openTabs.put(codePanel.getCls(), codePanel);
|
||||
add(codePanel);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class JumpManager {
|
||||
|
||||
private List<Position> list = new ArrayList<Position>();
|
||||
private int currentPos = 0;
|
||||
|
||||
public void addPosition(Position pos) {
|
||||
if (pos.equals(getCurrent())) {
|
||||
return;
|
||||
}
|
||||
currentPos++;
|
||||
if (currentPos >= list.size()) {
|
||||
list.add(pos);
|
||||
currentPos = list.size() - 1;
|
||||
} else {
|
||||
list.set(currentPos, pos);
|
||||
int size = list.size();
|
||||
for (int i = currentPos + 1; i < size; i++) {
|
||||
list.set(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Position getCurrent() {
|
||||
if (currentPos < list.size()) {
|
||||
return list.get(currentPos);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Position getPrev() {
|
||||
if (currentPos == 0) {
|
||||
return null;
|
||||
}
|
||||
currentPos--;
|
||||
return list.get(currentPos);
|
||||
}
|
||||
|
||||
public Position getNext() {
|
||||
int newPos = currentPos + 1;
|
||||
if (newPos >= list.size()) {
|
||||
currentPos = list.size() - 1;
|
||||
return null;
|
||||
}
|
||||
Position position = list.get(newPos);
|
||||
if (position == null) {
|
||||
return null;
|
||||
}
|
||||
currentPos = newPos;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package jadx.gui.utils;
|
||||
|
||||
import jadx.api.CodePosition;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
|
||||
public class Position {
|
||||
private final JClass cls;
|
||||
private final int line;
|
||||
|
||||
public Position(CodePosition pos) {
|
||||
this.cls = new JClass(pos.getJavaClass());
|
||||
this.line = pos.getLine();
|
||||
}
|
||||
|
||||
public Position(JClass cls, int line) {
|
||||
this.cls = cls;
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public JClass getCls() {
|
||||
return cls;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof Position)) {
|
||||
return false;
|
||||
}
|
||||
Position position = (Position) obj;
|
||||
return line == position.line && cls.equals(position.cls);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * cls.hashCode() + line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Position: " + cls + " : " + line;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user