package nf.co.haxter.gui.tabs;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import nf.co.haxter.exception.InvalidBytecodeException;
import nf.co.haxter.gui.MainWindow;
import nf.co.haxter.gui.extcomponents.TextLineNumber;
import nf.co.haxter.gui.layouts.WrapLayout;
import nf.co.haxter.util.BytecodeUtils;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceMethodVisitor;
public class MethodInfoPanel extends JPanel {
private final ButtonGroup buttonGroup = new ButtonGroup();
private JTextArea textAreaCodeEditor;
private JRadioButton rdbtnPublic;
private JRadioButton rdbtnProtected;
private JRadioButton rdbtnPrivate;
private JRadioButton rdbtnDefault;
private JCheckBox chckbxStatic;
private JCheckBox chckbxAbstract;
private JCheckBox chckbxFinal;
private JCheckBox chckbxSynchronized;
private JCheckBox chckbxNative;
private JCheckBox chckbxSynthetic;
private JCheckBox chckbxTransient;
private JCheckBox chckbxStrictfp;
private JPanel panelMethodListings;
private JList<MethodNode> listMethods;
private JLabel lblMethods;
private JPanel panelCodeEditorNorth;
private JLabel lblCodeEditor;
private JButton btnSaveMethod;
public MethodNode selectedMethod;
private JPanel panelControl;
private JButton btnNewMethod;
private JButton btnDeleteMethod;
/**
* Create the panel.
*/
public MethodInfoPanel(final ClassNode cNode) {
setLayout(new BorderLayout(0, 0));
panelControl = new JPanel();
add(panelControl, BorderLayout.NORTH);
panelControl.setLayout(new BoxLayout(panelControl, BoxLayout.X_AXIS));
btnNewMethod = new JButton("New Method... (this needs an icon)");
btnNewMethod.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectedMethod = new MethodNode();
selectedMethod.name = JOptionPane.showInputDialog("Method Name?");
cNode.methods.add(selectedMethod);
((DefaultListModel<MethodNode>)MethodInfoPanel.this.listMethods.getModel()).addElement(selectedMethod);
}
});
panelControl.add(btnNewMethod);
btnSaveMethod = new JButton("Save Method");
panelControl.add(btnSaveMethod);
btnDeleteMethod = new JButton("Delete Method");
btnDeleteMethod.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cNode.methods.remove(selectedMethod);
((DefaultListModel<MethodNode>)MethodInfoPanel.this.listMethods.getModel()).removeElement(selectedMethod);
}
});
panelControl.add(btnDeleteMethod);
btnSaveMethod.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
saveMethod(MethodInfoPanel.this.selectedMethod);
}
});
JSplitPane splitPane = new JSplitPane();
add(splitPane, BorderLayout.CENTER);
JPanel panel = new JPanel();
splitPane.setRightComponent(panel);
panel.setLayout(new BorderLayout(0, 0));
JPanel panelModifiers = new JPanel();
panel.add(panelModifiers, BorderLayout.NORTH);
panelModifiers.setLayout(new BorderLayout(0, 0));
JLabel lblModifiers = new JLabel("Modifiers:");
lblModifiers.setHorizontalAlignment(SwingConstants.LEFT);
panelModifiers.add(lblModifiers, BorderLayout.NORTH);
JPanel panelAllModifiers = new JPanel();
panelAllModifiers.setBorder(new LineBorder(new Color(0, 0, 0), 1, true));
panelModifiers.add(panelAllModifiers);
panelAllModifiers.setLayout(new BoxLayout(panelAllModifiers, BoxLayout.X_AXIS));
JPanel panelAccessModifiers = new JPanel();
panelAllModifiers.add(panelAccessModifiers);
panelAccessModifiers.setLayout(new BoxLayout(panelAccessModifiers, BoxLayout.Y_AXIS));
rdbtnPublic = new JRadioButton("PUBLIC");
buttonGroup.add(rdbtnPublic);
panelAccessModifiers.add(rdbtnPublic);
rdbtnProtected = new JRadioButton("PROTECTED");
buttonGroup.add(rdbtnProtected);
panelAccessModifiers.add(rdbtnProtected);
rdbtnPrivate = new JRadioButton("PRIVATE");
buttonGroup.add(rdbtnPrivate);
panelAccessModifiers.add(rdbtnPrivate);
rdbtnDefault = new JRadioButton("DEFAULT");
buttonGroup.add(rdbtnDefault);
panelAccessModifiers.add(rdbtnDefault);
JPanel panelOtherModifiers = new JPanel();
panelAllModifiers.add(panelOtherModifiers);
panelOtherModifiers.setAutoscrolls(true);
WrapLayout wl_panelOtherModifiers = new WrapLayout();
wl_panelOtherModifiers.setAlignment(FlowLayout.LEADING);
panelOtherModifiers.setLayout(wl_panelOtherModifiers);
chckbxStatic = new JCheckBox("STATIC");
panelOtherModifiers.add(chckbxStatic);
chckbxAbstract = new JCheckBox("ABSTRACT");
panelOtherModifiers.add(chckbxAbstract);
chckbxFinal = new JCheckBox("FINAL");
panelOtherModifiers.add(chckbxFinal);
chckbxSynchronized = new JCheckBox("SYNCHRONIZED");
panelOtherModifiers.add(chckbxSynchronized);
chckbxNative = new JCheckBox("NATIVE");
panelOtherModifiers.add(chckbxNative);
chckbxSynthetic = new JCheckBox("SYNTHETIC");
panelOtherModifiers.add(chckbxSynthetic);
chckbxTransient = new JCheckBox("TRANSIENT");
panelOtherModifiers.add(chckbxTransient);
chckbxStrictfp = new JCheckBox("STRICTFP");
panelOtherModifiers.add(chckbxStrictfp);
JPanel panelMethodCode = new JPanel();
panel.add(panelMethodCode, BorderLayout.CENTER);
panelMethodCode.setLayout(new BorderLayout(0, 0));
textAreaCodeEditor = new JTextArea();
JScrollPane scrollPane = new JScrollPane(textAreaCodeEditor);
scrollPane.setRowHeaderView(new TextLineNumber(textAreaCodeEditor));
panelMethodCode.add(scrollPane, BorderLayout.CENTER);
panelCodeEditorNorth = new JPanel();
scrollPane.setColumnHeaderView(panelCodeEditorNorth);
panelCodeEditorNorth.setLayout(new BorderLayout(0, 0));
lblCodeEditor = new JLabel("Code Editor:");
panelCodeEditorNorth.add(lblCodeEditor);
panelMethodListings = new JPanel();
splitPane.setLeftComponent(panelMethodListings);
listMethods = new JList<MethodNode>();
DefaultListModel<MethodNode> listModel = new DefaultListModel<MethodNode>();
for (MethodNode mn : (List<MethodNode>) cNode.methods) {
listModel.addElement(mn);
}
listMethods.setModel(listModel);
listMethods.setCellRenderer(new DefaultListCellRenderer(){
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel && value instanceof MethodNode) {
MethodNode mn = (MethodNode) value;
((JLabel)c).setText(mn.name + mn.desc);
}
return c;
}
});
listMethods.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent arg0) {
onMethodChange(MethodInfoPanel.this.selectedMethod = listMethods.getSelectedValue());
}
});
panelMethodListings.setLayout(new BorderLayout(0, 0));
lblMethods = new JLabel("Methods: ");
panelMethodListings.add(lblMethods, BorderLayout.NORTH);
listMethods.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
panelMethodListings.add(listMethods);
}
public void onMethodChange(MethodNode mn) {
if (mn == null) {
this.chckbxAbstract.setSelected(false);
this.chckbxFinal.setSelected(false);
this.chckbxNative.setSelected(false);
this.chckbxStatic.setSelected(false);
this.chckbxStrictfp.setSelected(false);
this.chckbxSynchronized.setSelected(false);
this.chckbxSynthetic.setSelected(false);
this.chckbxTransient.setSelected(false);
this.rdbtnDefault.setSelected(false);
this.rdbtnProtected.setSelected(false);
this.rdbtnPrivate.setSelected(false);
this.rdbtnPublic.setSelected(false);
return;
}
this.chckbxAbstract.setSelected(BytecodeUtils.isAbstract(mn.access));
this.chckbxFinal.setSelected(BytecodeUtils.isFinal(mn.access));
this.chckbxNative.setSelected(BytecodeUtils.isNative(mn.access));
this.chckbxStatic.setSelected(BytecodeUtils.isStatic(mn.access));
this.chckbxStrictfp.setSelected(BytecodeUtils.isStrictFP(mn.access));
this.chckbxSynchronized.setSelected(BytecodeUtils.isSynchronized(mn.access));
this.chckbxSynthetic.setSelected(BytecodeUtils.isSynthetic(mn.access));
this.chckbxTransient.setSelected(BytecodeUtils.isTransient(mn.access));
boolean
isPrivate = BytecodeUtils.isPrivate(mn.access),
isPublic = BytecodeUtils.isPublic(mn.access),
isProtected = BytecodeUtils.isProtected(mn.access);
this.rdbtnPrivate.setSelected(isPrivate);
this.rdbtnPublic.setSelected(isPublic);
this.rdbtnProtected.setSelected(isProtected);
this.rdbtnDefault.setSelected(!isPublic && !isPrivate && !isProtected);
// DEBUG
Printer printer = new Textifier();
TraceMethodVisitor tmv = new TraceMethodVisitor(printer);
mn.accept(tmv);
for (Object o : printer.text) {
System.out.println(o);
}
// DEBUG
String code = "";
for (String s : BytecodeUtils.bytecodeToText(mn.instructions)) {
code += s + '\n';
}
this.textAreaCodeEditor.setText(code);
MainWindow.updateStatus("Selected method '" + mn.name + mn.desc + "'!");
}
public void saveMethod(MethodNode mn) {
// TODO method saving
// modifiers
mn.access = 0;
if (this.rdbtnDefault.isSelected()) {
} else if (this.rdbtnPrivate.isSelected()) {
mn.access |= Opcodes.ACC_PRIVATE;
} else if (this.rdbtnProtected.isSelected()) {
mn.access |= Opcodes.ACC_PROTECTED;
} else if (this.rdbtnPublic.isSelected()) {
mn.access |= Opcodes.ACC_PUBLIC;
}
if (this.chckbxAbstract.isSelected()) {
mn.access |= Opcodes.ACC_ABSTRACT;
}
if (this.chckbxFinal.isSelected()) {
mn.access |= Opcodes.ACC_FINAL;
}
if (this.chckbxNative.isSelected()) {
mn.access |= Opcodes.ACC_NATIVE;
}
if (this.chckbxStatic.isSelected()) {
mn.access |= Opcodes.ACC_STATIC;
}
if (this.chckbxStrictfp.isSelected()) {
mn.access |= Opcodes.ACC_STRICT;
}
if (this.chckbxSynchronized.isSelected()) {
mn.access |= Opcodes.ACC_SYNCHRONIZED;
}
if (this.chckbxSynthetic.isSelected()) {
mn.access |= Opcodes.ACC_SYNTHETIC;
}
if (this.chckbxTransient.isSelected()) {
mn.access |= Opcodes.ACC_TRANSIENT;
}
// modifiers
// code
try {
mn.instructions = BytecodeUtils.generateInsnListFromScript(this.textAreaCodeEditor.getText().split("\n"));
} catch (InvalidBytecodeException e) {
e.printStackTrace();
}
// code
MainWindow.updateStatus("Saved method '" + mn.name + mn.desc + "'!");
// DEBUG
String a = "";
for (String s : BytecodeUtils.bytecodeToText(mn.instructions)) {
a += s + '\n';
}
System.out.println(a);
// DEBUG
}
}