mirror of
https://github.com/skylot/jadx.git
synced 2024-11-23 12:50:02 +00:00
gui: initial tabbed ui implementation
This commit is contained in:
parent
2cfc208aa9
commit
b6befbdcf2
@ -7,16 +7,20 @@ 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;
|
||||
@ -25,6 +29,7 @@ import javax.swing.ProgressMonitor;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
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;
|
||||
@ -40,6 +45,8 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
|
||||
@ -63,15 +70,13 @@ 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 File WORK_DIR = new File(System.getProperty("user.dir"));
|
||||
|
||||
private final JadxWrapper wrapper;
|
||||
|
||||
private JPanel mainPanel;
|
||||
private JTree tree;
|
||||
private final JTabbedPane tabbedPane = new JTabbedPane();
|
||||
private DefaultTreeModel treeModel;
|
||||
private RSyntaxTextArea textArea;
|
||||
private JToolBar searchToolBar;
|
||||
private SearchBar searchBar;
|
||||
private Map<JClass, Integer> openTabs = new HashMap<JClass, Integer>();
|
||||
|
||||
public MainWindow(JadxWrapper wrapper) {
|
||||
this.wrapper = wrapper;
|
||||
@ -85,7 +90,6 @@ public class MainWindow extends JFrame {
|
||||
fileChooser.setAcceptAllFileFilterUsed(true);
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("supported files", "dex", "apk", "jar"));
|
||||
fileChooser.setToolTipText(NLS.str("file.open"));
|
||||
// fileChooser.setCurrentDirectory(WORK_DIR);
|
||||
int ret = fileChooser.showDialog(mainPanel, NLS.str("file.open"));
|
||||
if (ret == JFileChooser.APPROVE_OPTION) {
|
||||
openFile(fileChooser.getSelectedFile());
|
||||
@ -129,6 +133,7 @@ public class MainWindow extends JFrame {
|
||||
}
|
||||
|
||||
private void toggleSearch() {
|
||||
SearchBar searchBar = getSearchBar((JPanel) tabbedPane.getSelectedComponent());
|
||||
searchBar.toggle();
|
||||
}
|
||||
|
||||
@ -137,16 +142,100 @@ public class MainWindow extends JFrame {
|
||||
if (obj instanceof JNode) {
|
||||
JNode node = (JNode) obj;
|
||||
if (node.getJParent() != null) {
|
||||
textArea.setText(node.getJParent().getCode());
|
||||
scrollToLine(node.getLine());
|
||||
showCode(node.getJParent(), node.getLine());
|
||||
} else if (node.getClass() == JClass.class) {
|
||||
textArea.setText(((JClass) node).getCode());
|
||||
scrollToLine(node.getLine());
|
||||
showCode((JClass) node, node.getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scrollToLine(int line) {
|
||||
private JPanel newCodePane() {
|
||||
RSyntaxTextArea textArea = new RSyntaxTextArea();
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
textArea.setMarkOccurrences(true);
|
||||
textArea.setBackground(BACKGROUND);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setAntiAliasingEnabled(true);
|
||||
// textArea.setEditable(false);
|
||||
// textArea.setHyperlinksEnabled(true);
|
||||
textArea.setTabSize(4);
|
||||
|
||||
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 JTextArea getTextArea(JPanel panel) {
|
||||
RTextScrollPane scrollPane = (RTextScrollPane) panel.getComponent(1);
|
||||
return scrollPane.getTextArea();
|
||||
}
|
||||
|
||||
private void showCode(JClass cls, int line) {
|
||||
JPanel panel;
|
||||
if (openTabs.containsKey(cls)) {
|
||||
int id = openTabs.get(cls);
|
||||
panel = (JPanel) tabbedPane.getComponentAt(id);
|
||||
tabbedPane.setSelectedIndex(id);
|
||||
} else {
|
||||
panel = newCodePane();
|
||||
tabbedPane.add(panel);
|
||||
int id = tabbedPane.getTabCount() - 1;
|
||||
openTabs.put(cls, id);
|
||||
tabbedPane.setSelectedIndex(id);
|
||||
tabbedPane.setTabComponentAt(id, makeTabComponent(cls, panel));
|
||||
}
|
||||
if (panel != null) {
|
||||
JTextArea textArea = getTextArea(panel);
|
||||
textArea.setText(cls.getCode());
|
||||
scrollToLine(textArea, line);
|
||||
}
|
||||
}
|
||||
|
||||
private Component makeTabComponent(final JClass cls, final Component comp) {
|
||||
String name = cls.getCls().getFullName();
|
||||
JPanel p = new JPanel();
|
||||
JLabel label = new JLabel(name);
|
||||
p.add(label);
|
||||
JButton button = new JButton();
|
||||
button.setIcon(ICON_CLOSE);
|
||||
final int size = 12;
|
||||
button.setPreferredSize(new Dimension(size, size));
|
||||
button.setToolTipText("Close");
|
||||
button.setUI(new BasicButtonUI());
|
||||
button.setContentAreaFilled(false);
|
||||
button.setFocusable(false);
|
||||
button.setBorder(BorderFactory.createEtchedBorder());
|
||||
button.setBorderPainted(false);
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
tabbedPane.remove(comp);
|
||||
openTabs.remove(cls);
|
||||
}
|
||||
});
|
||||
p.add(button);
|
||||
p.doLayout();
|
||||
return p;
|
||||
}
|
||||
|
||||
private void scrollToLine(JTextArea textArea, int line) {
|
||||
if (line < 2) {
|
||||
return;
|
||||
}
|
||||
@ -233,14 +322,6 @@ public class MainWindow extends JFrame {
|
||||
searchButton.setToolTipText(NLS.str("search"));
|
||||
toolbar.add(searchButton);
|
||||
|
||||
KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK);
|
||||
Utils.addKeyBinding(textArea, key, "SearchAction", new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
toggleSearch();
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.addSeparator();
|
||||
|
||||
mainPanel.add(toolbar, BorderLayout.NORTH);
|
||||
@ -255,8 +336,6 @@ public class MainWindow extends JFrame {
|
||||
DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Please open file");
|
||||
treeModel = new DefaultTreeModel(treeRoot);
|
||||
tree = new JTree(treeModel);
|
||||
// tree.setRootVisible(false);
|
||||
// tree.setBackground(BACKGROUND);
|
||||
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
tree.addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@Override
|
||||
@ -281,24 +360,8 @@ public class MainWindow extends JFrame {
|
||||
JScrollPane treeScrollPane = new JScrollPane(tree);
|
||||
splitPane.setLeftComponent(treeScrollPane);
|
||||
|
||||
textArea = new RSyntaxTextArea();
|
||||
textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVA);
|
||||
textArea.setMarkOccurrences(true);
|
||||
textArea.setBackground(BACKGROUND);
|
||||
textArea.setCodeFoldingEnabled(true);
|
||||
textArea.setAntiAliasingEnabled(true);
|
||||
textArea.setEditable(false);
|
||||
// textArea.setHyperlinksEnabled(true);
|
||||
textArea.setTabSize(4);
|
||||
|
||||
RTextScrollPane scrollPane = new RTextScrollPane(textArea);
|
||||
scrollPane.setFoldIndicatorEnabled(true);
|
||||
|
||||
JPanel textPanel = new JPanel(new BorderLayout());
|
||||
searchBar = new SearchBar(textArea);
|
||||
textPanel.add(searchBar.getToolBar(), BorderLayout.NORTH);
|
||||
textPanel.add(scrollPane);
|
||||
splitPane.setRightComponent(textPanel);
|
||||
tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);
|
||||
splitPane.setRightComponent(tabbedPane);
|
||||
|
||||
setContentPane(mainPanel);
|
||||
setTitle(DEFAULT_TITLE);
|
||||
|
@ -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 {
|
||||
public class SearchBar extends JToolBar {
|
||||
private static final Color COLOR_BG_ERROR = new Color(0xFFDFDE);
|
||||
private static final Color COLOR_BG_WARN = new Color(0xFFFDD9);
|
||||
private static final Color COLOR_BG_NORMAL = new Color(0xFFFFFF);
|
||||
@ -30,7 +30,6 @@ public class SearchBar {
|
||||
private static final Icon ICON_CLOSE = Utils.openIcon("cross");
|
||||
|
||||
private final RSyntaxTextArea rTextArea;
|
||||
private final JToolBar toolBar;
|
||||
|
||||
private final JTextField searchField;
|
||||
private final JCheckBox markAllCB;
|
||||
@ -41,10 +40,9 @@ public class SearchBar {
|
||||
|
||||
public SearchBar(RSyntaxTextArea textArea) {
|
||||
rTextArea = textArea;
|
||||
toolBar = new JToolBar();
|
||||
|
||||
JLabel findLabel = new JLabel(NLS.str("search.find") + ":");
|
||||
toolBar.add(findLabel);
|
||||
add(findLabel);
|
||||
|
||||
searchField = new JTextField(30);
|
||||
searchField.addKeyListener(new KeyListener() {
|
||||
@ -76,7 +74,7 @@ public class SearchBar {
|
||||
search(1);
|
||||
}
|
||||
});
|
||||
toolBar.add(searchField);
|
||||
add(searchField);
|
||||
|
||||
JButton prevButton = new JButton(NLS.str("search.previous"));
|
||||
prevButton.setIcon(ICON_UP);
|
||||
@ -86,7 +84,7 @@ public class SearchBar {
|
||||
search(-1);
|
||||
}
|
||||
});
|
||||
toolBar.add(prevButton);
|
||||
add(prevButton);
|
||||
|
||||
JButton nextButton = new JButton(NLS.str("search.next"));
|
||||
nextButton.setIcon(ICON_DOWN);
|
||||
@ -96,23 +94,23 @@ public class SearchBar {
|
||||
search(1);
|
||||
}
|
||||
});
|
||||
toolBar.add(nextButton);
|
||||
add(nextButton);
|
||||
|
||||
markAllCB = new JCheckBox(NLS.str("search.mark_all"));
|
||||
markAllCB.addActionListener(new ForwardListener());
|
||||
toolBar.add(markAllCB);
|
||||
add(markAllCB);
|
||||
|
||||
regexCB = new JCheckBox(NLS.str("search.regex"));
|
||||
regexCB.addActionListener(new ForwardListener());
|
||||
toolBar.add(regexCB);
|
||||
add(regexCB);
|
||||
|
||||
matchCaseCB = new JCheckBox(NLS.str("search.match_case"));
|
||||
matchCaseCB.addActionListener(new ForwardListener());
|
||||
toolBar.add(matchCaseCB);
|
||||
add(matchCaseCB);
|
||||
|
||||
wholeWordCB = new JCheckBox(NLS.str("search.whole_word"));
|
||||
wholeWordCB.addActionListener(new ForwardListener());
|
||||
toolBar.add(wholeWordCB);
|
||||
add(wholeWordCB);
|
||||
|
||||
JButton closeButton = new JButton();
|
||||
closeButton.setIcon(ICON_CLOSE);
|
||||
@ -122,22 +120,19 @@ public class SearchBar {
|
||||
toggle();
|
||||
}
|
||||
});
|
||||
toolBar.add(closeButton);
|
||||
add(closeButton);
|
||||
|
||||
toolBar.setFloatable(false);
|
||||
toolBar.setVisible(false);
|
||||
}
|
||||
|
||||
public JToolBar getToolBar() {
|
||||
return toolBar;
|
||||
setFloatable(false);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
public boolean toggle() {
|
||||
boolean visible = !toolBar.isVisible();
|
||||
toolBar.setVisible(visible);
|
||||
boolean visible = !isVisible();
|
||||
setVisible(visible);
|
||||
|
||||
if (visible) {
|
||||
searchField.requestFocus();
|
||||
searchField.selectAll();
|
||||
} else {
|
||||
rTextArea.requestFocus();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user