Commit 571b5590 authored by Skylot's avatar Skylot

gui: add icons to classes tree

parent 7eb5defc
...@@ -104,3 +104,8 @@ under the terms of the GNU Lesser General Public License version 2.1 ...@@ -104,3 +104,8 @@ under the terms of the GNU Lesser General Public License version 2.1
as published by the Free Software Foundation. as published by the Free Software Foundation.
******************************************************************************* *******************************************************************************
GUI icons copied from several places:
- Eclipse Project (JDT UI) - licensed under EPL v1.0 (http://www.eclipse.org/legal/epl-v10.html)
- famfamfam silk icon set (http://www.famfamfam.com/lab/icons/silk/) - licensed under Creative Commons Attribution 2.5 License (http://creativecommons.org/licenses/by/2.5/)
...@@ -56,11 +56,7 @@ public final class Decompiler { ...@@ -56,11 +56,7 @@ public final class Decompiler {
} }
public void loadFile(File file) throws IOException, DecodeException { public void loadFile(File file) throws IOException, DecodeException {
List<File> files = args.getInput(); setInput(file);
files.clear();
files.add(file);
loadInput();
parseDex(); parseDex();
} }
...@@ -119,11 +115,17 @@ public final class Decompiler { ...@@ -119,11 +115,17 @@ public final class Decompiler {
} }
private void loadInput() throws IOException, DecodeException { private void loadInput() throws IOException, DecodeException {
inputFiles.clear();
for (File file : args.getInput()) { for (File file : args.getInput()) {
inputFiles.add(new InputFile(file)); inputFiles.add(new InputFile(file));
} }
} }
private void setInput(File file) throws IOException, DecodeException {
inputFiles.clear();
inputFiles.add(new InputFile(file));
}
private void parseDex() throws DecodeException { private void parseDex() throws DecodeException {
ClassInfo.clearCache(); ClassInfo.clearCache();
ErrorsCounter.reset(); ErrorsCounter.reset();
......
...@@ -23,6 +23,9 @@ public class InputFile { ...@@ -23,6 +23,9 @@ public class InputFile {
public InputFile(File file) throws IOException, DecodeException { public InputFile(File file) throws IOException, DecodeException {
this.file = file; this.file = file;
if (!file.exists()) {
throw new IOException("File not found: " + file.getAbsolutePath());
}
String fileName = file.getName(); String fileName = file.getName();
...@@ -81,5 +84,4 @@ public class InputFile { ...@@ -81,5 +84,4 @@ public class InputFile {
public String toString() { public String toString() {
return file.toString(); return file.toString();
} }
} }
...@@ -2,7 +2,8 @@ package jadx.gui; ...@@ -2,7 +2,8 @@ package jadx.gui;
import jadx.cli.JadxArgs; import jadx.cli.JadxArgs;
import javax.swing.*; import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -25,7 +26,7 @@ public class JadxGUI { ...@@ -25,7 +26,7 @@ public class JadxGUI {
MainWindow mainWindow = new MainWindow(jadxArgs); MainWindow mainWindow = new MainWindow(jadxArgs);
mainWindow.setVisible(true); mainWindow.setVisible(true);
if(!jadxArgs.getInput().isEmpty()) { if (!jadxArgs.getInput().isEmpty()) {
mainWindow.openFile(jadxArgs.getInput().get(0)); mainWindow.openFile(jadxArgs.getInput().get(0));
} }
} }
......
package jadx.gui; package jadx.gui;
import jadx.api.IJadxArgs;
import jadx.api.Decompiler; import jadx.api.Decompiler;
import jadx.api.IJadxArgs;
import jadx.api.JavaClass; import jadx.api.JavaClass;
import jadx.api.JavaPackage; import jadx.api.JavaPackage;
import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.DecodeException;
...@@ -12,12 +12,14 @@ import java.util.List; ...@@ -12,12 +12,14 @@ import java.util.List;
public class JadxWrapper { public class JadxWrapper {
private final Decompiler decompiler; private final Decompiler decompiler;
private File openFile;
public JadxWrapper(IJadxArgs jadxArgs) { public JadxWrapper(IJadxArgs jadxArgs) {
this.decompiler = new Decompiler(jadxArgs); this.decompiler = new Decompiler(jadxArgs);
} }
public void openFile(File file) { public void openFile(File file) {
this.openFile = file;
try { try {
this.decompiler.loadFile(file); this.decompiler.loadFile(file);
} catch (IOException e) { } catch (IOException e) {
...@@ -35,4 +37,7 @@ public class JadxWrapper { ...@@ -35,4 +37,7 @@ public class JadxWrapper {
return decompiler.getPackages(); return decompiler.getPackages();
} }
public File getOpenFile() {
return openFile;
}
} }
package jadx.gui; package jadx.gui;
import jadx.api.JavaClass; import jadx.api.JavaClass;
import jadx.api.JavaPackage;
import jadx.cli.JadxArgs; import jadx.cli.JadxArgs;
import jadx.gui.model.JClass; import jadx.gui.treemodel.JClass;
import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.treemodel.JNode;
import jadx.gui.treemodel.JRoot;
import javax.swing.*;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
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.JTree;
import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener; import javax.swing.event.TreeSelectionListener;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel; import javax.swing.tree.TreeSelectionModel;
import java.awt.*; import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.File; import java.io.File;
import java.net.URL;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
...@@ -35,8 +45,8 @@ public class MainWindow extends JFrame { ...@@ -35,8 +45,8 @@ public class MainWindow extends JFrame {
private final JadxWrapper wrapper; private final JadxWrapper wrapper;
private JPanel mainPanel; private JPanel mainPanel;
private DefaultMutableTreeNode treeRoot;
private JTree tree; private JTree tree;
private DefaultTreeModel treeModel;
private RSyntaxTextArea textArea; private RSyntaxTextArea textArea;
public MainWindow(JadxArgs jadxArgs) { public MainWindow(JadxArgs jadxArgs) {
...@@ -52,7 +62,7 @@ public class MainWindow extends JFrame { ...@@ -52,7 +62,7 @@ public class MainWindow extends JFrame {
JMenu file = new JMenu("File"); JMenu file = new JMenu("File");
file.setMnemonic(KeyEvent.VK_F); file.setMnemonic(KeyEvent.VK_F);
JMenuItem exit = new JMenuItem("Exit", openIcon("application-exit")); JMenuItem exit = new JMenuItem("Exit", Utils.openIcon("cross"));
exit.setMnemonic(KeyEvent.VK_E); exit.setMnemonic(KeyEvent.VK_E);
exit.setToolTipText("Exit application"); exit.setToolTipText("Exit application");
exit.addActionListener(new ActionListener() { exit.addActionListener(new ActionListener() {
...@@ -61,7 +71,7 @@ public class MainWindow extends JFrame { ...@@ -61,7 +71,7 @@ public class MainWindow extends JFrame {
} }
}); });
JMenuItem open = new JMenuItem("Open", openIcon("document-open-5")); JMenuItem open = new JMenuItem("Open", Utils.openIcon("folder"));
open.setMnemonic(KeyEvent.VK_E); open.setMnemonic(KeyEvent.VK_E);
open.setToolTipText("Open file"); open.setToolTipText("Open file");
open.addActionListener(new ActionListener() { open.addActionListener(new ActionListener() {
...@@ -92,51 +102,46 @@ public class MainWindow extends JFrame { ...@@ -92,51 +102,46 @@ public class MainWindow extends JFrame {
} }
private void initTree() { private void initTree() {
treeRoot.removeAllChildren(); JRoot treeRoot = new JRoot(wrapper);
for (JavaPackage pkg : wrapper.getPackages()) { treeModel.setRoot(treeRoot);
MutableTreeNode child = new DefaultMutableTreeNode(pkg); treeModel.reload();
int i = 0;
for (JavaClass javaClass : pkg.getClasses()) {
MutableTreeNode cls = new DefaultMutableTreeNode(new JClass(javaClass));
child.insert(cls, i++);
}
treeRoot.add(child);
}
tree.expandRow(0); tree.expandRow(0);
} }
private ImageIcon openIcon(String name) {
String iconPath = "/icons-16/" + name + ".png";
URL resource = getClass().getResource(iconPath);
if (resource == null) {
throw new JadxRuntimeException("Icon not found: " + iconPath);
}
return new ImageIcon(resource);
}
private void initUI() { private void initUI() {
mainPanel = new JPanel(new BorderLayout()); mainPanel = new JPanel(new BorderLayout());
JSplitPane splitPane = new JSplitPane(); JSplitPane splitPane = new JSplitPane();
mainPanel.add(splitPane); mainPanel.add(splitPane);
treeRoot = new DefaultMutableTreeNode("Please open file"); DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("Please open file");
tree = new JTree(treeRoot); treeModel = new DefaultTreeModel(treeRoot);
tree = new JTree(treeModel);
// tree.setRootVisible(false); // tree.setRootVisible(false);
// tree.setBackground(BACKGROUND); // tree.setBackground(BACKGROUND);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.addTreeSelectionListener(new TreeSelectionListener() { tree.addTreeSelectionListener(new TreeSelectionListener() {
@Override @Override
public void valueChanged(TreeSelectionEvent e) { public void valueChanged(TreeSelectionEvent e) {
Object node = tree.getLastSelectedPathComponent(); Object obj = tree.getLastSelectedPathComponent();
if (node instanceof DefaultMutableTreeNode) { if (obj instanceof JClass) {
Object obj = ((DefaultMutableTreeNode) node).getUserObject(); JavaClass jc = ((JClass) obj).getCls();
if (obj instanceof JClass) { String code = jc.getCode();
JavaClass jc = ((JClass) obj).getCls(); textArea.setText(code);
String code = jc.getCode(); textArea.setCaretPosition(0);
textArea.setText(code); }
textArea.setCaretPosition(0); }
} });
tree.setCellRenderer(new DefaultTreeCellRenderer() {
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value, boolean selected, boolean expanded,
boolean isLeaf, int row, boolean focused) {
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, isLeaf, row, focused);
if (value instanceof JNode) {
setIcon(((JNode) value).getIcon());
} }
return c;
} }
}); });
......
package jadx.gui;
import jadx.core.utils.exceptions.JadxRuntimeException;
import javax.swing.ImageIcon;
import java.net.URL;
public class Utils {
public static ImageIcon openIcon(String name) {
String iconPath = "/icons-16/" + name + ".png";
URL resource = Utils.class.getResource(iconPath);
if (resource == null) {
throw new JadxRuntimeException("Icon not found: " + iconPath);
}
return new ImageIcon(resource);
}
}
package jadx.gui.model; package jadx.gui.treemodel;
import jadx.api.JavaClass; import jadx.api.JavaClass;
import jadx.gui.Utils;
public class JClass { import javax.swing.Icon;
import javax.swing.tree.DefaultMutableTreeNode;
public class JClass extends DefaultMutableTreeNode implements JNode {
private final JavaClass cls; private final JavaClass cls;
...@@ -15,6 +19,11 @@ public class JClass { ...@@ -15,6 +19,11 @@ public class JClass {
} }
@Override @Override
public Icon getIcon() {
return Utils.openIcon("class_obj");
}
@Override
public String toString() { public String toString() {
return cls.getShortName(); return cls.getShortName();
} }
......
package jadx.gui.treemodel;
import javax.swing.Icon;
public interface JNode {
Icon getIcon();
}
package jadx.gui.treemodel;
import jadx.api.JavaClass;
import jadx.api.JavaPackage;
import jadx.gui.Utils;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode;
public class JPackage extends DefaultMutableTreeNode implements JNode {
private static final ImageIcon PACKAGE_ICON = Utils.openIcon("package_obj");
private final JavaPackage pkg;
public JPackage(JavaPackage pkg) {
this.pkg = pkg;
for (JavaClass javaClass : pkg.getClasses()) {
add(new JClass(javaClass));
}
}
public JavaPackage getPkg() {
return pkg;
}
@Override
public Icon getIcon() {
return PACKAGE_ICON;
}
@Override
public String toString() {
return pkg.getName();
}
}
package jadx.gui.treemodel;
import jadx.api.JavaPackage;
import jadx.gui.JadxWrapper;
import jadx.gui.Utils;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.tree.DefaultMutableTreeNode;
import java.io.File;
public class JRoot extends DefaultMutableTreeNode implements JNode {
private static final ImageIcon ROOT_ICON = Utils.openIcon("java_model_obj");
private final JadxWrapper wrapper;
public JRoot(JadxWrapper wrapper) {
this.wrapper = wrapper;
for (JavaPackage pkg : wrapper.getPackages()) {
add(new JPackage(pkg));
}
}
@Override
public Icon getIcon() {
return ROOT_ICON;
}
@Override
public String toString() {
File file = wrapper.getOpenFile();
return file != null ? file.getName() : "File not open";
}
}
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