001    package net.sourceforge.retroweaver.gui;
002    
003    import java.awt.BorderLayout;
004    import java.awt.Component;
005    import java.awt.Container;
006    import java.awt.Cursor;
007    import java.awt.Dimension;
008    import java.awt.FlowLayout;
009    import java.awt.GridBagConstraints;
010    import java.awt.GridBagLayout;
011    import java.awt.Insets;
012    import java.awt.Toolkit;
013    import java.awt.event.ActionEvent;
014    import java.awt.event.ActionListener;
015    import java.io.File;
016    import java.util.ArrayList;
017    import java.util.StringTokenizer;
018    
019    import javax.swing.BorderFactory;
020    import javax.swing.JButton;
021    import javax.swing.JComboBox;
022    import javax.swing.JFileChooser;
023    import javax.swing.JFrame;
024    import javax.swing.JLabel;
025    import javax.swing.JOptionPane;
026    import javax.swing.JPanel;
027    import javax.swing.JScrollPane;
028    import javax.swing.JTextArea;
029    import javax.swing.JTextField;
030    import javax.swing.event.DocumentEvent;
031    import javax.swing.event.DocumentListener;
032    
033    import org.objectweb.asm.commons.EmptyVisitor;
034    
035    import net.sourceforge.retroweaver.RefVerifier;
036    import net.sourceforge.retroweaver.RetroWeaver;
037    import net.sourceforge.retroweaver.Weaver;
038    import net.sourceforge.retroweaver.event.VerifierListener;
039    import net.sourceforge.retroweaver.event.WeaveListener;
040    
041    /**
042     * A simple graphical user interface for Retroweaver.
043     */
044    public class RetroWeaverGui extends JPanel implements WeaveListener,
045                    VerifierListener {
046    
047            public static void main(String[] args) {
048                    String defaultPath = "";
049    
050                    if (args.length > 0) {
051                            if (args[0].equals("-console")) {
052                                    String a[] = new String[args.length - 1];
053                                    System.arraycopy(args, 1, a, 0, args.length - 1);
054                                    Weaver.main(a);
055                                    return;
056                            }
057                            defaultPath = args[0];
058                    }
059    
060                    String version = Weaver.getVersion();
061                    showInJFrame("RetroWeaver " + version, new RetroWeaverGui(defaultPath));
062            }
063    
064            private static void showInJFrame(String title, Component contents) {
065                    JFrame frame = new JFrame(title);
066                    frame.getContentPane().add(contents);
067                    frame.setSize(400, 300);
068                    centerOnScreen(frame);
069                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
070                    frame.setVisible(true);
071            }
072    
073            private static void centerOnScreen(JFrame frame) {
074                    Dimension frameSize = frame.getSize();
075                    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
076                    int x = (screenSize.width - frameSize.width) / 2;
077                    int y = (screenSize.height - frameSize.height) / 2;
078                    frame.setLocation(x, y);
079            }
080    
081            public RetroWeaverGui(String defaultPath) {
082                    super(new BorderLayout());
083                    refClassPath = new JTextField();
084                    add(createParameterSection(), BorderLayout.NORTH);
085                    add(createMessageArea(), BorderLayout.CENTER);
086                    add(createSouthSection(), BorderLayout.SOUTH);
087                    pathField.setText(defaultPath);
088            }
089    
090            public void weavingStarted(String msg) {
091                    displayWeavingMessage(msg);
092            }
093    
094            public void weavingPath(String sourcePath) {
095                    String pathAsString = path.getAbsolutePath();
096                    String p;
097                    if (sourcePath.startsWith(pathAsString)) {
098                            p = sourcePath.substring(pathAsString.length());
099                    } else {
100                            p = sourcePath;
101                    }
102                    displayWeavingMessage(p);
103            }
104    
105            public void weavingError(String msg) {
106                    displayWeavingMessage(msg);
107            }
108    
109            public void weavingCompleted(String msg) {
110                    displayWeavingMessage(msg);
111            }
112    
113            private void displayWeavingMessage(String msg) {
114                    messages.append("[RetroWeaver] " + msg + "\n");
115                    messageScrollPane.getVerticalScrollBar().setValue(
116                                    messageScrollPane.getVerticalScrollBar().getMaximum()); 
117            }
118    
119            public void verifyPathStarted(String msg) {
120                    displayVerifierMessage(msg);
121            }
122    
123            public void verifyClassStarted(String msg) {
124                    displayVerifierMessage(msg);
125            }
126    
127            public void acceptWarning(String msg) {
128                    displayVerifierMessage(msg);
129            }
130    
131            public void displaySummary(int warningCount) {
132                    displayVerifierMessage("Verification complete, " + warningCount
133                                    + " warning(s).");
134            }
135    
136            private void displayVerifierMessage(String msg) {
137                    messages.append("[RefVerifier] " + msg + "\n");
138                    messageScrollPane.getVerticalScrollBar().setValue(
139                                    messageScrollPane.getVerticalScrollBar().getMaximum());
140            }
141    
142            private Component createParameterSection() {
143                    JPanel ret = new JPanel(new GridBagLayout());
144                    addAt(ret, 0, 0, new JLabel("Source:"));
145                    addAt(ret, 1, 0, GridBagConstraints.HORIZONTAL, 2, 0.0,
146                                    createPathField());
147                    addAt(ret, 3, 0, createBrowse());
148                    addAt(ret, 0, 1, new JLabel("Target:"));
149                    addAt(ret, 1, 1, createTargetChooser());
150                    addAt(ret, 2, 1, GridBagConstraints.HORIZONTAL, 1, 1.0, new JPanel());
151                    addAt(ret, 0, 2, new JLabel("Ref Verify Classpath:"));
152                    addAt(ret, 1, 2, GridBagConstraints.HORIZONTAL, 2, 0.0, refClassPath);
153                    addAt(ret, 3, 2, GridBagConstraints.HORIZONTAL, 1, 1.0, new JPanel());
154                    return ret;
155            }
156    
157            private Component createSouthSection() {
158                    JPanel ret = new JPanel(new BorderLayout());
159                    ret.add(createActionButtons(), BorderLayout.CENTER);
160                    ret.add(createStatus(), BorderLayout.SOUTH);
161                    ret.setBorder(BorderFactory.createEmptyBorder(INSET_SIZE, INSET_SIZE,
162                                    INSET_SIZE, INSET_SIZE));
163                    return ret;
164            }
165    
166            private Component createActionButtons() {
167                    JPanel ret = new JPanel(new FlowLayout(FlowLayout.RIGHT));
168                    ret.add(createTransform());
169                    ret.add(createExit());
170                    return ret;
171            }
172    
173            private Component createPathField() {
174                    pathField = new JTextField();
175                    pathField.getDocument().addDocumentListener(new DocumentListener() {
176                            public void insertUpdate(DocumentEvent e) {
177                                    doPathChanged();
178                            }
179    
180                            public void removeUpdate(DocumentEvent e) {
181                                    doPathChanged();
182                            }
183    
184                            public void changedUpdate(DocumentEvent e) {
185                                    // do nothing
186                            }
187                    });
188                    return pathField;
189            }
190    
191            private Component createBrowse() {
192                    JButton browse = new JButton("Browse...");
193                    browse.addActionListener(new ActionListener() {
194                            public void actionPerformed(ActionEvent e) {
195                                    doBrowse();
196                            }
197                    });
198                    return browse;
199            }
200    
201            private Component createTargetChooser() {
202                    targetCombo = new JComboBox(new String[] { "1.4", "1.3", "1.2" });
203                    targetCombo.setSelectedIndex(0);
204                    targetCombo.addActionListener(new ActionListener() {
205                            public void actionPerformed(ActionEvent e) {
206                                    status.setText(READY);
207                            }
208                    });
209                    return targetCombo;
210            }
211    
212            private Component createTransform() {
213                    JButton transform = new JButton("Transform");
214                    transform.addActionListener(new ActionListener() {
215                            public void actionPerformed(ActionEvent e) {
216                                    doTransform();
217                            }
218                    });
219                    return transform;
220            }
221    
222            private Component createExit() {
223                    JButton exit = new JButton("Exit");
224                    exit.addActionListener(new ActionListener() {
225                            public void actionPerformed(ActionEvent e) {
226                                    doExit();
227                            }
228                    });
229                    return exit;
230            }
231    
232            private Component createStatus() {
233                    status = new JLabel(READY);
234                    return status;
235            }
236    
237            private Component createMessageArea() {
238                    JPanel ret = new JPanel(new BorderLayout());
239                    ret.setBorder(BorderFactory.createTitledBorder("Messages"));
240                    messages = new JTextArea();
241                    messageScrollPane = new JScrollPane(messages);
242                    ret.add(messageScrollPane, BorderLayout.CENTER);
243                    return ret;
244            }
245    
246            private void addAt(Container container, int x, int y, Component component) {
247                    addAt(container, x, y, 0, 1, 0.0, component);
248            }
249    
250            private void addAt(Container container, int x, int y, int fill,
251                            int gridwidth, double weightx, Component component) {
252                    GridBagConstraints constraints = new GridBagConstraints();
253                    constraints.gridx = x;
254                    constraints.gridy = y;
255                    constraints.fill = fill;
256                    constraints.insets = INSETS;
257                    constraints.gridwidth = gridwidth;
258                    constraints.weightx = weightx;
259                    container.add(component, constraints);
260            }
261    
262            private void doTransform() {
263    
264                    if (runWeaverThread != null && runWeaverThread.isAlive()) {
265                            JOptionPane
266                                            .showMessageDialog(this,
267                                                            "RetroWeaver is already running, wait until it has finished ");
268                            return;
269                    }
270    
271                    path = new File(pathField.getText());
272    
273                    if (!path.exists()) {
274                            status.setText("Error: Path \"" + path + "\" does not exist");
275                            return;
276                    }
277    
278                    version = VERSION_NUMBERS[targetCombo.getSelectedIndex()];
279                    runWeaverThread = createWeaverThread();
280                    runWeaverThread.start();
281            }
282    
283            private void doBrowse() {
284                    JFileChooser fileChooser = new JFileChooser();
285                    fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
286    
287                    if (fileChooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) {
288                            return;
289                    }
290    
291                    pathField.setText(fileChooser.getSelectedFile().getAbsolutePath());
292                    status.setText(READY);
293            }
294    
295            private void doExit() {
296                    JFrame frame = (JFrame) getTopLevelAncestor();
297                    frame.dispose();
298            }
299    
300            private void doPathChanged() {
301                    status.setText(READY);
302            }
303    
304            private JTextField pathField;
305    
306            private final JTextField refClassPath;
307    
308            private JComboBox targetCombo;
309    
310            private JLabel status;
311    
312            private JTextArea messages;
313    
314            private int version;
315    
316            private File path;
317    
318            private JScrollPane messageScrollPane;
319    
320            private static final String READY = "Ready";
321    
322            private static final int INSET_SIZE = 3;
323    
324            private static final Insets INSETS = new Insets(INSET_SIZE, INSET_SIZE,
325                            INSET_SIZE, INSET_SIZE);
326    
327            private static final int[] VERSION_NUMBERS = new int[] {
328                            Weaver.VERSION_1_4, Weaver.VERSION_1_3, Weaver.VERSION_1_2 };
329    
330            private volatile Thread runWeaverThread;
331    
332            private Thread createWeaverThread() {
333                    return new Thread(new Runnable() {
334                            public void run() {
335                                    Cursor oldCursor = getTopLevelAncestor().getCursor();
336                                    getTopLevelAncestor().setCursor(
337                                                    Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
338    
339                                    try {
340                                            status.setText("Running");
341                                            RetroWeaver weaver = new RetroWeaver(version);
342                                            messages.setText("");
343                                            weaver.setListener(RetroWeaverGui.this);
344    
345                                            String refCp = refClassPath.getText();
346    
347                                            if (refCp.length() != 0) {
348                                                    java.util.List<String> classpath = new ArrayList<String>();
349                                                    StringTokenizer st = new StringTokenizer(refCp,
350                                                                    File.pathSeparator);
351                                                    while (st.hasMoreTokens()) {
352                                                            classpath.add(st.nextToken());
353                                                    }
354                                                    RefVerifier verifier = new RefVerifier(version, new EmptyVisitor(), classpath,
355                                                                    RetroWeaverGui.this);
356                                                    weaver.setVerifier(verifier);
357                                            }
358    
359                                            weaver.weave(path);
360    
361                                            status.setText("Done");
362                                    } catch (Exception ex) {
363                                            status.setText("Error: " + ex.getMessage());
364                                    } finally {
365                                            getTopLevelAncestor().setCursor(oldCursor);
366                                    }
367                            }
368                    });
369            }
370    }