提交 5ed5ec5f 编写于 作者: S Skylot

gui: refactor UI classes

上级 95795620
package jadx.gui; package jadx.gui;
import jadx.cli.JadxCLIArgs; import jadx.cli.JadxCLIArgs;
import jadx.gui.ui.MainWindow;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
...@@ -19,17 +20,17 @@ public class JadxGUI { ...@@ -19,17 +20,17 @@ public class JadxGUI {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
JadxWrapper wrapper = new JadxWrapper(jadxArgs); JadxWrapper wrapper = new JadxWrapper(jadxArgs);
MainWindow mainWindow = new MainWindow(wrapper); MainWindow window = new MainWindow(wrapper);
mainWindow.pack(); window.pack();
mainWindow.setLocationAndPosition(); window.setLocationAndPosition();
mainWindow.setVisible(true); window.setVisible(true);
mainWindow.setLocationRelativeTo(null); window.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
if (jadxArgs.getInput().isEmpty()) { if (jadxArgs.getInput().isEmpty()) {
mainWindow.openFile(); window.openFile();
} else { } else {
mainWindow.openFile(jadxArgs.getInput().get(0)); window.openFile(jadxArgs.getInput().get(0));
} }
} }
}); });
......
package jadx.gui; package jadx.gui.ui;
import jadx.api.CodePosition; import jadx.api.CodePosition;
import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JClass;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener; import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultCaret;
import java.awt.Color; import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import org.fife.ui.rsyntaxtextarea.LinkGenerator; import org.fife.ui.rsyntaxtextarea.LinkGenerator;
import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult; import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
...@@ -18,8 +24,8 @@ import org.fife.ui.rsyntaxtextarea.TokenTypes; ...@@ -18,8 +24,8 @@ import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class JadxTextArea extends RSyntaxTextArea { class CodeArea extends RSyntaxTextArea {
private static final Logger LOG = LoggerFactory.getLogger(JadxTextArea.class); private static final Logger LOG = LoggerFactory.getLogger(CodeArea.class);
private static final long serialVersionUID = 6312736869579635796L; private static final long serialVersionUID = 6312736869579635796L;
...@@ -27,13 +33,12 @@ public class JadxTextArea extends RSyntaxTextArea { ...@@ -27,13 +33,12 @@ public class JadxTextArea extends RSyntaxTextArea {
private static final Color JUMP_FOREGROUND = new Color(0x785523); private static final Color JUMP_FOREGROUND = new Color(0x785523);
private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF); private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF);
private final CodePanel codePanel;
private final JClass cls; private final JClass cls;
private final MainWindow rootWindow;
CodeArea(CodePanel panel) {
public JadxTextArea(MainWindow mainWindow, JClass cls) { this.codePanel = panel;
this.rootWindow = mainWindow; this.cls = panel.getCls();
this.cls = cls;
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA); setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
SyntaxScheme scheme = getSyntaxScheme(); SyntaxScheme scheme = getSyntaxScheme();
...@@ -43,7 +48,11 @@ public class JadxTextArea extends RSyntaxTextArea { ...@@ -43,7 +48,11 @@ public class JadxTextArea extends RSyntaxTextArea {
setBackground(BACKGROUND); setBackground(BACKGROUND);
setAntiAliasingEnabled(true); setAntiAliasingEnabled(true);
setEditable(false); setEditable(false);
getCaret().setVisible(true); Caret caret = getCaret();
if (caret instanceof DefaultCaret) {
((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
}
caret.setVisible(true);
setHyperlinksEnabled(true); setHyperlinksEnabled(true);
CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(cls); CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(cls);
...@@ -82,6 +91,46 @@ public class JadxTextArea extends RSyntaxTextArea { ...@@ -82,6 +91,46 @@ public class JadxTextArea extends RSyntaxTextArea {
} }
} }
void scrollToLine(int line) {
line--;
if (line < 0) {
line = 0;
}
setCaretAtLine(line);
centerCurrentLine();
forceCurrentLineHighlightRepaint();
}
public void centerCurrentLine() {
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, this);
if (viewport == null) {
return;
}
try {
Rectangle r = modelToView(getCaretPosition());
if (r == null) {
return;
}
int extentHeight = viewport.getExtentSize().height;
int viewHeight = viewport.getViewSize().height;
int y = Math.max(0, r.y - (extentHeight / 2));
y = Math.min(y, viewHeight - extentHeight);
viewport.setViewPosition(new Point(0, y));
} catch (BadLocationException e) {
LOG.debug("Can't center current line", e);
}
}
private void setCaretAtLine(int line) {
try {
setCaretPosition(getLineStartOffset(line));
} catch (BadLocationException e) {
LOG.debug("Can't scroll to " + line, e);
}
}
private class CodeLinkGenerator implements LinkGenerator, HyperlinkListener { private class CodeLinkGenerator implements LinkGenerator, HyperlinkListener {
private final JClass jCls; private final JClass jCls;
...@@ -124,7 +173,7 @@ public class JadxTextArea extends RSyntaxTextArea { ...@@ -124,7 +173,7 @@ public class JadxTextArea extends RSyntaxTextArea {
if (obj instanceof CodePosition) { if (obj instanceof CodePosition) {
CodePosition pos = (CodePosition) obj; CodePosition pos = (CodePosition) obj;
JClass cls = new JClass(pos.getJavaClass()); JClass cls = new JClass(pos.getJavaClass());
rootWindow.showCode(cls, pos.getLine()); codePanel.getCodePanel().showCode(cls, pos.getLine());
LOG.debug("Code jump to: {}", pos); LOG.debug("Code jump to: {}", pos);
} }
} }
......
package jadx.gui.ui;
import jadx.gui.treemodel.JClass;
import jadx.gui.utils.Utils;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import org.fife.ui.rtextarea.RTextScrollPane;
class CodePanel extends JPanel {
private final TabbedPane codePanel;
private final JClass jClass;
private final SearchBar searchBar;
private final CodeArea codeArea;
private final RTextScrollPane scrollPane;
CodePanel(TabbedPane panel, JClass cls) {
codePanel = panel;
jClass = cls;
codeArea = new CodeArea(this);
searchBar = new SearchBar(codeArea);
scrollPane = new RTextScrollPane(codeArea);
scrollPane.setFoldIndicatorEnabled(true);
setLayout(new BorderLayout());
add(searchBar, BorderLayout.NORTH);
add(scrollPane);
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
Utils.addKeyBinding(codeArea, key, "SearchAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
searchBar.toggle();
}
});
}
TabbedPane getCodePanel() {
return codePanel;
}
JClass getCls() {
return jClass;
}
SearchBar getSearchBar() {
return searchBar;
}
CodeArea getCodeArea() {
return codeArea;
}
RTextScrollPane getScrollPane() {
return scrollPane;
}
}
package jadx.gui; package jadx.gui.ui;
import jadx.gui.JadxWrapper;
import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JNode;
import jadx.gui.treemodel.JRoot; import jadx.gui.treemodel.JRoot;
import jadx.gui.utils.NLS; import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils; import jadx.gui.utils.Utils;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton; import javax.swing.JToggleButton;
import javax.swing.JToolBar; import javax.swing.JToolBar;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.ProgressMonitor; import javax.swing.ProgressMonitor;
import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener; import javax.swing.event.TreeWillExpandListener;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.text.BadLocationException;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
...@@ -40,21 +33,16 @@ import javax.swing.tree.TreeSelectionModel; ...@@ -40,21 +33,16 @@ import javax.swing.tree.TreeSelectionModel;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Component; import java.awt.Component;
import java.awt.DisplayMode; import java.awt.DisplayMode;
import java.awt.FlowLayout;
import java.awt.GraphicsDevice; import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment; import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -70,7 +58,6 @@ public class MainWindow extends JFrame { ...@@ -70,7 +58,6 @@ public class MainWindow extends JFrame {
private static final ImageIcon ICON_OPEN = Utils.openIcon("folder"); private static final ImageIcon ICON_OPEN = Utils.openIcon("folder");
private static final ImageIcon ICON_SAVE_ALL = Utils.openIcon("disk_multiple"); private static final ImageIcon ICON_SAVE_ALL = Utils.openIcon("disk_multiple");
private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross"); private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross");
private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed");
private static final ImageIcon ICON_FLAT_PKG = Utils.openIcon("empty_logical_package_obj"); 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_SEARCH = Utils.openIcon("magnifier");
...@@ -80,9 +67,7 @@ public class MainWindow extends JFrame { ...@@ -80,9 +67,7 @@ public class MainWindow extends JFrame {
private JTree tree; private JTree tree;
private DefaultTreeModel treeModel; private DefaultTreeModel treeModel;
private TabbedPane tabbedPane;
private final JTabbedPane tabbedPane = new JTabbedPane();
private final Map<JClass, Component> openTabs = new HashMap<JClass, Component>();
public MainWindow(JadxWrapper wrapper) { public MainWindow(JadxWrapper wrapper) {
this.wrapper = wrapper; this.wrapper = wrapper;
...@@ -138,126 +123,19 @@ public class MainWindow extends JFrame { ...@@ -138,126 +123,19 @@ public class MainWindow extends JFrame {
} }
} }
private void toggleSearch() {
SearchBar searchBar = getSearchBar((JPanel) tabbedPane.getSelectedComponent());
searchBar.toggle();
}
private void treeClickAction() { private void treeClickAction() {
Object obj = tree.getLastSelectedPathComponent(); Object obj = tree.getLastSelectedPathComponent();
if (obj instanceof JNode) { if (obj instanceof JNode) {
JNode node = (JNode) obj; JNode node = (JNode) obj;
JClass cls = node.getRootClass(); JClass cls = node.getRootClass();
if (cls != null) { if (cls != null) {
showCode(cls, node.getLine()); tabbedPane.showCode(cls, node.getLine());
} }
} }
} }
private JPanel newCodePane(final JClass cls) { private void toggleSearch() {
JadxTextArea textArea = new JadxTextArea(this, cls); tabbedPane.getSelectedCodePanel().getSearchBar().toggle();
RTextScrollPane scrollPane = new RTextScrollPane(textArea);
scrollPane.setFoldIndicatorEnabled(true);
JPanel textPanel = new JPanel(new BorderLayout());
SearchBar searchBar = new SearchBar(textArea);
textPanel.add(searchBar, BorderLayout.NORTH);
textPanel.add(scrollPane);
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
Utils.addKeyBinding(textArea, key, "SearchAction", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
toggleSearch();
}
});
return textPanel;
}
private SearchBar getSearchBar(JPanel panel) {
return (SearchBar) panel.getComponent(0);
}
private JadxTextArea getTextArea(JPanel panel) {
RTextScrollPane scrollPane = (RTextScrollPane) panel.getComponent(1);
return (JadxTextArea) scrollPane.getTextArea();
}
void showCode(JClass cls, int line) {
JPanel panel = (JPanel) openTabs.get(cls);
if (panel != null) {
panel = (JPanel) openTabs.get(cls);
tabbedPane.setSelectedComponent(panel);
} else {
panel = newCodePane(cls);
tabbedPane.add(panel);
openTabs.put(cls, panel);
int id = tabbedPane.indexOfComponent(panel);
tabbedPane.setTabComponentAt(id, makeTabComponent(cls, panel));
tabbedPane.setSelectedIndex(id);
}
JadxTextArea textArea = getTextArea(panel);
scrollToLine(textArea, line);
}
private Component makeTabComponent(final JClass cls, final Component comp) {
String name = cls.getCls().getFullName();
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
panel.setOpaque(false);
final JLabel label = new JLabel(name);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
label.setIcon(cls.getIcon());
final JButton button = new JButton();
button.setIcon(ICON_CLOSE_INACTIVE);
button.setRolloverIcon(ICON_CLOSE);
button.setRolloverEnabled(true);
button.setOpaque(false);
button.setUI(new BasicButtonUI());
button.setContentAreaFilled(false);
button.setFocusable(false);
button.setBorder(null);
button.setBorderPainted(false);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
closeCodeTab(cls, comp);
}
});
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON2) {
closeCodeTab(cls, comp);
} else {
// TODO: make correct event delegation to tabbed pane
tabbedPane.setSelectedComponent(comp);
}
}
});
panel.add(label);
panel.add(button);
panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
return panel;
}
private void closeCodeTab(JClass cls, Component comp) {
tabbedPane.remove(comp);
openTabs.remove(cls);
}
private void scrollToLine(JTextArea textArea, int line) {
if (line == 0) {
line = 1;
}
try {
textArea.setCaretPosition(textArea.getLineStartOffset(line - 1));
} catch (BadLocationException e) {
LOG.error("Can't scroll to " + line, e);
}
} }
private void initMenuAndToolbar() { private void initMenuAndToolbar() {
...@@ -396,7 +274,7 @@ public class MainWindow extends JFrame { ...@@ -396,7 +274,7 @@ public class MainWindow extends JFrame {
JScrollPane treeScrollPane = new JScrollPane(tree); JScrollPane treeScrollPane = new JScrollPane(tree);
splitPane.setLeftComponent(treeScrollPane); splitPane.setLeftComponent(treeScrollPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT); tabbedPane = new TabbedPane(this);
splitPane.setRightComponent(tabbedPane); splitPane.setRightComponent(tabbedPane);
setContentPane(mainPanel); setContentPane(mainPanel);
......
package jadx.gui; package jadx.gui.ui;
import jadx.gui.utils.NLS; import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils; import jadx.gui.utils.Utils;
...@@ -20,7 +20,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; ...@@ -20,7 +20,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.SearchContext; import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine; import org.fife.ui.rtextarea.SearchEngine;
public class SearchBar extends JToolBar { class SearchBar extends JToolBar {
private static final long serialVersionUID = 1836871286618633003L; private static final long serialVersionUID = 1836871286618633003L;
private static final Color COLOR_BG_ERROR = new Color(0xFFDFDE); private static final Color COLOR_BG_ERROR = new Color(0xFFDFDE);
......
package jadx.gui.ui;
import jadx.gui.treemodel.JClass;
import jadx.gui.utils.Utils;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
class TabbedPane extends JTabbedPane {
private static final ImageIcon ICON_CLOSE = Utils.openIcon("cross");
private static final ImageIcon ICON_CLOSE_INACTIVE = Utils.openIcon("cross_grayed");
private final MainWindow mainWindow;
private final Map<JClass, CodePanel> openTabs = new HashMap<JClass, CodePanel>();
TabbedPane(MainWindow window) {
mainWindow = window;
setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
private void addCodePanel(CodePanel codePanel) {
add(codePanel);
openTabs.put(codePanel.getCls(), codePanel);
}
private void closeCodePanel(CodePanel codePanel) {
remove(codePanel);
openTabs.remove(codePanel.getCls());
}
void showCode(JClass cls, int line) {
CodePanel panel = openTabs.get(cls);
if (panel == null) {
panel = new CodePanel(this, cls);
addCodePanel(panel);
setTabComponentAt(indexOfComponent(panel), makeTabComponent(panel));
}
setSelectedComponent(panel);
CodeArea codeArea = panel.getCodeArea();
codeArea.scrollToLine(line);
codeArea.requestFocus();
}
private Component makeTabComponent(final CodePanel codePanel) {
JClass cls = codePanel.getCls();
String name = cls.getCls().getFullName();
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 0));
panel.setOpaque(false);
final JLabel label = new JLabel(name);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 10));
label.setIcon(cls.getIcon());
final JButton button = new JButton();
button.setIcon(ICON_CLOSE_INACTIVE);
button.setRolloverIcon(ICON_CLOSE);
button.setRolloverEnabled(true);
button.setOpaque(false);
button.setUI(new BasicButtonUI());
button.setContentAreaFilled(false);
button.setFocusable(false);
button.setBorder(null);
button.setBorderPainted(false);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
closeCodePanel(codePanel);
}
});
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON2) {
closeCodePanel(codePanel);
} else {
// TODO: make correct event delegation to tabbed pane
setSelectedComponent(codePanel);
}
}
});
panel.add(label);
panel.add(button);
panel.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
return panel;
}
CodePanel getSelectedCodePanel() {
return (CodePanel) getSelectedComponent();
}
MainWindow getMainWindow() {
return mainWindow;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册