package net.sourceforge.retroweaver.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.StringTokenizer; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.objectweb.asm.commons.EmptyVisitor; import net.sourceforge.retroweaver.RefVerifier; import net.sourceforge.retroweaver.RetroWeaver; import net.sourceforge.retroweaver.Weaver; import net.sourceforge.retroweaver.event.VerifierListener; import net.sourceforge.retroweaver.event.WeaveListener; /** * A simple graphical user interface for Retroweaver. */ public class RetroWeaverGui extends JPanel implements WeaveListener, VerifierListener { public static void main(String[] args) { String defaultPath = ""; if (args.length > 0) { if (args[0].equals("-console")) { String a[] = new String[args.length - 1]; System.arraycopy(args, 1, a, 0, args.length - 1); Weaver.main(a); return; } defaultPath = args[0]; } String version = Weaver.getVersion(); showInJFrame("RetroWeaver " + version, new RetroWeaverGui(defaultPath)); } private static void showInJFrame(String title, Component contents) { JFrame frame = new JFrame(title); frame.getContentPane().add(contents); frame.setSize(400, 300); centerOnScreen(frame); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } private static void centerOnScreen(JFrame frame) { Dimension frameSize = frame.getSize(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int x = (screenSize.width - frameSize.width) / 2; int y = (screenSize.height - frameSize.height) / 2; frame.setLocation(x, y); } public RetroWeaverGui(String defaultPath) { super(new BorderLayout()); refClassPath = new JTextField(); add(createParameterSection(), BorderLayout.NORTH); add(createMessageArea(), BorderLayout.CENTER); add(createSouthSection(), BorderLayout.SOUTH); pathField.setText(defaultPath); } public void weavingStarted(String msg) { displayWeavingMessage(msg); } public void weavingPath(String sourcePath) { String pathAsString = path.getAbsolutePath(); String p; if (sourcePath.startsWith(pathAsString)) { p = sourcePath.substring(pathAsString.length()); } else { p = sourcePath; } displayWeavingMessage(p); } public void weavingError(String msg) { displayWeavingMessage(msg); } public void weavingCompleted(String msg) { displayWeavingMessage(msg); } private void displayWeavingMessage(String msg) { messages.append("[RetroWeaver] " + msg + "\n"); messageScrollPane.getVerticalScrollBar().setValue( messageScrollPane.getVerticalScrollBar().getMaximum()); } public void verifyPathStarted(String msg) { displayVerifierMessage(msg); } public void verifyClassStarted(String msg) { displayVerifierMessage(msg); } public void acceptWarning(String msg) { displayVerifierMessage(msg); } public void displaySummary(int warningCount) { displayVerifierMessage("Verification complete, " + warningCount + " warning(s)."); } private void displayVerifierMessage(String msg) { messages.append("[RefVerifier] " + msg + "\n"); messageScrollPane.getVerticalScrollBar().setValue( messageScrollPane.getVerticalScrollBar().getMaximum()); } private Component createParameterSection() { JPanel ret = new JPanel(new GridBagLayout()); addAt(ret, 0, 0, new JLabel("Source:")); addAt(ret, 1, 0, GridBagConstraints.HORIZONTAL, 2, 0.0, createPathField()); addAt(ret, 3, 0, createBrowse()); addAt(ret, 0, 1, new JLabel("Target:")); addAt(ret, 1, 1, createTargetChooser()); addAt(ret, 2, 1, GridBagConstraints.HORIZONTAL, 1, 1.0, new JPanel()); addAt(ret, 0, 2, new JLabel("Ref Verify Classpath:")); addAt(ret, 1, 2, GridBagConstraints.HORIZONTAL, 2, 0.0, refClassPath); addAt(ret, 3, 2, GridBagConstraints.HORIZONTAL, 1, 1.0, new JPanel()); return ret; } private Component createSouthSection() { JPanel ret = new JPanel(new BorderLayout()); ret.add(createActionButtons(), BorderLayout.CENTER); ret.add(createStatus(), BorderLayout.SOUTH); ret.setBorder(BorderFactory.createEmptyBorder(INSET_SIZE, INSET_SIZE, INSET_SIZE, INSET_SIZE)); return ret; } private Component createActionButtons() { JPanel ret = new JPanel(new FlowLayout(FlowLayout.RIGHT)); ret.add(createTransform()); ret.add(createExit()); return ret; } private Component createPathField() { pathField = new JTextField(); pathField.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { doPathChanged(); } public void removeUpdate(DocumentEvent e) { doPathChanged(); } public void changedUpdate(DocumentEvent e) { // do nothing } }); return pathField; } private Component createBrowse() { JButton browse = new JButton("Browse..."); browse.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { doBrowse(); } }); return browse; } private Component createTargetChooser() { targetCombo = new JComboBox(new String[] { "1.4", "1.3", "1.2" }); targetCombo.setSelectedIndex(0); targetCombo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { status.setText(READY); } }); return targetCombo; } private Component createTransform() { JButton transform = new JButton("Transform"); transform.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { doTransform(); } }); return transform; } private Component createExit() { JButton exit = new JButton("Exit"); exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { doExit(); } }); return exit; } private Component createStatus() { status = new JLabel(READY); return status; } private Component createMessageArea() { JPanel ret = new JPanel(new BorderLayout()); ret.setBorder(BorderFactory.createTitledBorder("Messages")); messages = new JTextArea(); messageScrollPane = new JScrollPane(messages); ret.add(messageScrollPane, BorderLayout.CENTER); return ret; } private void addAt(Container container, int x, int y, Component component) { addAt(container, x, y, 0, 1, 0.0, component); } private void addAt(Container container, int x, int y, int fill, int gridwidth, double weightx, Component component) { GridBagConstraints constraints = new GridBagConstraints(); constraints.gridx = x; constraints.gridy = y; constraints.fill = fill; constraints.insets = INSETS; constraints.gridwidth = gridwidth; constraints.weightx = weightx; container.add(component, constraints); } private void doTransform() { if (runWeaverThread != null && runWeaverThread.isAlive()) { JOptionPane .showMessageDialog(this, "RetroWeaver is already running, wait until it has finished "); return; } path = new File(pathField.getText()); if (!path.exists()) { status.setText("Error: Path \"" + path + "\" does not exist"); return; } version = VERSION_NUMBERS[targetCombo.getSelectedIndex()]; runWeaverThread = createWeaverThread(); runWeaverThread.start(); } private void doBrowse() { JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) { return; } pathField.setText(fileChooser.getSelectedFile().getAbsolutePath()); status.setText(READY); } private void doExit() { JFrame frame = (JFrame) getTopLevelAncestor(); frame.dispose(); } private void doPathChanged() { status.setText(READY); } private JTextField pathField; private final JTextField refClassPath; private JComboBox targetCombo; private JLabel status; private JTextArea messages; private int version; private File path; private JScrollPane messageScrollPane; private static final String READY = "Ready"; private static final int INSET_SIZE = 3; private static final Insets INSETS = new Insets(INSET_SIZE, INSET_SIZE, INSET_SIZE, INSET_SIZE); private static final int[] VERSION_NUMBERS = new int[] { Weaver.VERSION_1_4, Weaver.VERSION_1_3, Weaver.VERSION_1_2 }; private volatile Thread runWeaverThread; private Thread createWeaverThread() { return new Thread(new Runnable() { public void run() { Cursor oldCursor = getTopLevelAncestor().getCursor(); getTopLevelAncestor().setCursor( Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); try { status.setText("Running"); RetroWeaver weaver = new RetroWeaver(version); messages.setText(""); weaver.setListener(RetroWeaverGui.this); String refCp = refClassPath.getText(); if (refCp.length() != 0) { java.util.List<String> classpath = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(refCp, File.pathSeparator); while (st.hasMoreTokens()) { classpath.add(st.nextToken()); } RefVerifier verifier = new RefVerifier(version, new EmptyVisitor(), classpath, RetroWeaverGui.this); weaver.setVerifier(verifier); } weaver.weave(path); status.setText("Done"); } catch (Exception ex) { status.setText("Error: " + ex.getMessage()); } finally { getTopLevelAncestor().setCursor(oldCursor); } } }); } }