From 944988e884b88565c0e10cd7fd5715c3cf34ac35 Mon Sep 17 00:00:00 2001 From: Clisprail Date: Thu, 7 Aug 2014 20:10:00 +0200 Subject: [PATCH] Reflection explorer early preview --- parabotv2/src/org/parabot/core/ui/BotUI.java | 6 + .../src/org/parabot/core/ui/ReflectUI.java | 198 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 parabotv2/src/org/parabot/core/ui/ReflectUI.java diff --git a/parabotv2/src/org/parabot/core/ui/BotUI.java b/parabotv2/src/org/parabot/core/ui/BotUI.java index 35894e4..52e6041 100644 --- a/parabotv2/src/org/parabot/core/ui/BotUI.java +++ b/parabotv2/src/org/parabot/core/ui/BotUI.java @@ -72,6 +72,7 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener, JMenuItem dialog = new JCheckBoxMenuItem("Disable dialog"); dialog.setSelected(true); + JMenuItem explorer = new JMenuItem("Reflection explorer"); JMenuItem exit = new JMenuItem("Exit"); run = new JMenuItem("Run"); @@ -87,6 +88,7 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener, proxy.addActionListener(this); dialog.addActionListener(this); + explorer.addActionListener(this); exit.addActionListener(this); run.addActionListener(this); @@ -99,6 +101,7 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener, file.add(dialog); } + file.add(explorer); file.add(exit); scripts.add(run); @@ -122,6 +125,9 @@ public class BotUI extends JFrame implements ActionListener, ComponentListener, case "Network": NetworkUI.getInstance().setVisible(true); break; + case "Reflection explorer": + new ReflectUI().setVisible(true); + break; case "Run": if(pauseScript) { pauseScript = false; diff --git a/parabotv2/src/org/parabot/core/ui/ReflectUI.java b/parabotv2/src/org/parabot/core/ui/ReflectUI.java new file mode 100644 index 0000000..1fa05eb --- /dev/null +++ b/parabotv2/src/org/parabot/core/ui/ReflectUI.java @@ -0,0 +1,198 @@ +package org.parabot.core.ui; + +import java.awt.Dimension; +import java.util.HashMap; + +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.TreePath; + +import org.parabot.core.Context; +import org.parabot.core.asm.ASMClassLoader; +import org.parabot.core.classpath.ClassPath; +import org.parabot.core.reflect.RefClass; +import org.parabot.core.reflect.RefField; + +/** + * + * A Reflection explorer + * + * @author Everel + * + */ +public class ReflectUI extends JFrame { + private static final long serialVersionUID = 98565034137367257L; + private DefaultMutableTreeNode root; + private DefaultTreeModel model; + private JEditorPane basicInfoPane; + private JEditorPane selectionInfoPane; + + private Object instance; + + private HashMap classes; + private HashMap fields; + + public ReflectUI() { + this.root = new DefaultMutableTreeNode("Classes"); + this.model = new DefaultTreeModel(root); + this.basicInfoPane = new JEditorPane(); + this.selectionInfoPane = new JEditorPane(); + this.classes = new HashMap<>(); + this.fields = new HashMap<>(); + this.instance = Context.getInstance().getClient(); + + fillModel(); + + setTitle("Reflection explorer"); + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + JPanel content = new JPanel(); + content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); + + JPanel exploreContent = new JPanel(); + exploreContent.setLayout(new BoxLayout(exploreContent, BoxLayout.X_AXIS)); + + JPanel infoContent = new JPanel(); + infoContent.setLayout(new BoxLayout(infoContent, BoxLayout.Y_AXIS)); + + JTree tree = new JTree(); + tree.setRootVisible(true); + tree.setShowsRootHandles(true); + tree.setModel(model); + tree.addTreeSelectionListener(new TreeSelectionListener() { + + @Override + public void valueChanged(TreeSelectionEvent event) { + TreePath path = event.getPath(); + Object[] pathElements = path.getPath(); + Object element = pathElements[pathElements.length-1]; + if(pathElements.length == 2) { + // class + setClassInfo(classes.get(element)); + } + if(pathElements.length == 3) { + // field + setFieldInfo(fields.get(element)); + } + } + + }); + + JScrollPane scrollTreePane = new JScrollPane(tree); + scrollTreePane.setPreferredSize(new Dimension(400, 300)); + + basicInfoPane.setContentType("text/html"); + basicInfoPane.setEditable(false); + + selectionInfoPane.setContentType("text/html"); + selectionInfoPane.setEditable(false); + + JScrollPane scrollBasicInfoPane = new JScrollPane(basicInfoPane); + scrollBasicInfoPane.setPreferredSize(new Dimension(400, 90)); + + JScrollPane scrollSelectInfoPane = new JScrollPane(selectionInfoPane); + scrollSelectInfoPane.setPreferredSize(new Dimension(400, 200)); + + infoContent.add(scrollBasicInfoPane); + infoContent.add(Box.createRigidArea(new Dimension(0, 10))); + infoContent.add(scrollSelectInfoPane); + + exploreContent.add(scrollTreePane); + exploreContent.add(Box.createRigidArea(new Dimension(10, 0))); + exploreContent.add(infoContent); + + content.add(exploreContent); + + JScrollPane contentPane = new JScrollPane(content); + Dimension prefSize = content.getPreferredSize(); + contentPane.setPreferredSize(new Dimension(prefSize.width + contentPane.getVerticalScrollBar().getPreferredSize().width, prefSize.height + contentPane.getHorizontalScrollBar().getPreferredSize().height)); + setContentPane(contentPane); + pack(); + setLocationRelativeTo(null); + setVisible(true); + } + + private void fillModel() { + Context context = Context.getInstance(); + ClassPath classPath = context.getClassPath(); + ASMClassLoader classLoader = context.getASMClassLoader(); + for (String className : classPath.classNames) { + try { + DefaultMutableTreeNode classNode = new DefaultMutableTreeNode( + "Class: " + className); + DefaultMutableTreeNode fieldNode; + + Class clazz = classLoader.loadClass(className); + + RefClass refClass = new RefClass(clazz); + if(refClass.instanceOf(this.instance)) { + refClass.setInstance(this.instance); + } + + for (RefField field : refClass.getFields()) { + fieldNode = new DefaultMutableTreeNode("Field: " + field.getName() + " [type: " + field.getASMType() + "] [value: " + field.asObject() + "]"); + classNode.add(fieldNode); + fields.put(fieldNode, field); + } + classes.put(classNode, refClass); + + root.add(classNode); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + + private void fillBasicInfoPane() { + Context context = Context.getInstance(); + ClassPath classPath = context.getClassPath(); + + StringBuilder builder = new StringBuilder(); + + builder.append("Classes: ").append(classPath.classNames.size()).append("
"); + builder.append("Using instance: ").append(instance.toString()).append("
"); + + basicInfoPane.setText(builder.toString()); + } + + private void setFieldInfo(RefField refField) { + StringBuilder builder = new StringBuilder(); + RefClass refClass = refField.getOwner(); + builder.append("

").append(refClass.getClassName()).append(".").append(refField.getName()).append("


"); + builder.append("Class: ").append(refClass.getClassName()).append("
"); + builder.append("Value: ").append(refField.asObject()).append("
"); + builder.append("Type: ").append(refField.getASMType().getClassName()).append("
"); + builder.append("Static: ").append(refField.isStatic() ? "yes" : "no").append("
"); + builder.append("Array: ").append(refField.isArray() ? refField.getArrayDimensions() + " dimension(s)" : "no").append("
"); + selectionInfoPane.setText(builder.toString()); + + fillBasicInfoPane(); + } + + private void setClassInfo(RefClass refClass) { + StringBuilder builder = new StringBuilder(); + builder.append("

").append(refClass.getClassName()).append("


"); + if(refClass.getClassName().contains(".")) { + builder.append("Package: ").append(refClass.getClassName().substring(0, refClass.getClassName().lastIndexOf("."))).append("
"); + } + builder.append("Abstract: ").append(refClass.isAbstract() ? "yes" : "no").append("
"); + builder.append("Interface: ").append(refClass.isInterface() ? "yes" : "no").append("
"); + builder.append("Superclass: ").append(refClass.hasSuperclass() ? refClass.getSuperclass().getClassName() : "no").append("
"); + builder.append("Fields: ").append(refClass.getFields().length).append("
"); + builder.append("Methods: ").append(refClass.getMethods().length).append("
"); + builder.append("Constructors: ").append(refClass.getConstructors().length).append("
"); + selectionInfoPane.setText(builder.toString()); + + fillBasicInfoPane(); + } + +}