gui: add hyperlinks for classes and fields

This commit is contained in:
Skylot
2014-05-25 23:14:29 +04:00
parent 0a36bfb088
commit 0a1981f90e
20 changed files with 465 additions and 141 deletions
@@ -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;
}
}