Commit 5ed5ec5f authored by Skylot's avatar Skylot

gui: refactor UI classes

parent 95795620
package jadx.gui;
import jadx.cli.JadxCLIArgs;
import jadx.gui.ui.MainWindow;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
......@@ -19,17 +20,17 @@ public class JadxGUI {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JadxWrapper wrapper = new JadxWrapper(jadxArgs);
MainWindow mainWindow = new MainWindow(wrapper);
mainWindow.pack();
mainWindow.setLocationAndPosition();
mainWindow.setVisible(true);
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
MainWindow window = new MainWindow(wrapper);
window.pack();
window.setLocationAndPosition();
window.setVisible(true);
window.setLocationRelativeTo(null);
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
if (jadxArgs.getInput().isEmpty()) {
mainWindow.openFile();
window.openFile();
} 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.gui.treemodel.JClass;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultCaret;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import org.fife.ui.rsyntaxtextarea.LinkGenerator;
import org.fife.ui.rsyntaxtextarea.LinkGeneratorResult;
......@@ -18,8 +24,8 @@ import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JadxTextArea extends RSyntaxTextArea {
private static final Logger LOG = LoggerFactory.getLogger(JadxTextArea.class);
class CodeArea extends RSyntaxTextArea {
private static final Logger LOG = LoggerFactory.getLogger(CodeArea.class);
private static final long serialVersionUID = 6312736869579635796L;
......@@ -27,13 +33,12 @@ public class JadxTextArea extends RSyntaxTextArea {
private static final Color JUMP_FOREGROUND = new Color(0x785523);
private static final Color JUMP_BACKGROUND = new Color(0xE6E6FF);
private final CodePanel codePanel;
private final JClass cls;
private final MainWindow rootWindow;
public JadxTextArea(MainWindow mainWindow, JClass cls) {
this.rootWindow = mainWindow;
this.cls = cls;
CodeArea(CodePanel panel) {
this.codePanel = panel;
this.cls = panel.getCls();
setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
SyntaxScheme scheme = getSyntaxScheme();
......@@ -43,7 +48,11 @@ public class JadxTextArea extends RSyntaxTextArea {
setBackground(BACKGROUND);
setAntiAliasingEnabled(true);
setEditable(false);
getCaret().setVisible(true);
Caret caret = getCaret();
if (caret instanceof DefaultCaret) {
((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
}
caret.setVisible(true);
setHyperlinksEnabled(true);
CodeLinkGenerator codeLinkProcessor = new CodeLinkGenerator(cls);
......@@ -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 final JClass jCls;
......@@ -124,7 +173,7 @@ public class JadxTextArea extends RSyntaxTextArea {
if (obj instanceof CodePosition) {
CodePosition pos = (CodePosition) obj;
JClass cls = new JClass(pos.getJavaClass());
rootWindow.showCode(cls, pos.getLine());
codePanel.getCodePanel().showCode(cls, pos.getLine());
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.JNode;
import jadx.gui.treemodel.JRoot;
import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.ProgressMonitor;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeWillExpandListener;
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.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
......@@ -40,21 +33,16 @@ import javax.swing.tree.TreeSelectionModel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.DisplayMode;
import java.awt.FlowLayout;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
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.LoggerFactory;
......@@ -70,7 +58,6 @@ public class MainWindow extends JFrame {
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_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_SEARCH = Utils.openIcon("magnifier");
......@@ -80,9 +67,7 @@ public class MainWindow extends JFrame {
private JTree tree;
private DefaultTreeModel treeModel;
private final JTabbedPane tabbedPane = new JTabbedPane();
private final Map<JClass, Component> openTabs = new HashMap<JClass, Component>();
private TabbedPane tabbedPane;
public MainWindow(JadxWrapper wrapper) {
this.wrapper = wrapper;
......@@ -138,126 +123,19 @@ public class MainWindow extends JFrame {
}
}
private void toggleSearch() {
SearchBar searchBar = getSearchBar((JPanel) tabbedPane.getSelectedComponent());
searchBar.toggle();
}
private void treeClickAction() {
Object obj = tree.getLastSelectedPathComponent();
if (obj instanceof JNode) {
JNode node = (JNode) obj;
JClass cls = node.getRootClass();
if (cls != null) {
showCode(cls, node.getLine());
tabbedPane.showCode(cls, node.getLine());
}
}
}
private JPanel newCodePane(final JClass cls) {
JadxTextArea textArea = new JadxTextArea(this, cls);
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 toggleSearch() {
tabbedPane.getSelectedCodePanel().getSearchBar().toggle();
}
private void initMenuAndToolbar() {
......@@ -396,7 +274,7 @@ public class MainWindow extends JFrame {
JScrollPane treeScrollPane = new JScrollPane(tree);
splitPane.setLeftComponent(treeScrollPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
tabbedPane = new TabbedPane(this);
splitPane.setRightComponent(tabbedPane);
setContentPane(mainPanel);
......
package jadx.gui;
package jadx.gui.ui;
import jadx.gui.utils.NLS;
import jadx.gui.utils.Utils;
......@@ -20,7 +20,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.SearchContext;
import org.fife.ui.rtextarea.SearchEngine;
public class SearchBar extends JToolBar {
class SearchBar extends JToolBar {
private static final long serialVersionUID = 1836871286618633003L;
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% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment