1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.gui;
22
23import proguard.optimize.Optimizer;
24import proguard.util.*;
25
26import javax.swing.*;
27import javax.swing.border.*;
28import java.awt.*;
29import java.awt.event.*;
30
31/**
32 * This <code>JDialog</code> allows the user to enter a String.
33 *
34 * @author Eric Lafortune
35 */
36final class OptimizationsDialog extends JDialog
37{
38    /**
39     * Return value if the dialog is canceled (with the Cancel button or by
40     * closing the dialog window).
41     */
42    public static final int CANCEL_OPTION = 1;
43
44    /**
45     * Return value if the dialog is approved (with the Ok button).
46     */
47    public static final int APPROVE_OPTION = 0;
48
49
50    private final JCheckBox[] optimizationCheckBoxes = new JCheckBox[Optimizer.OPTIMIZATION_NAMES.length];
51
52    private int returnValue;
53
54
55    public OptimizationsDialog(JFrame owner)
56    {
57        super(owner, msg("selectOptimizations"), true);
58        setResizable(true);
59
60        // Create some constraints that can be reused.
61        GridBagConstraints constraintsLast = new GridBagConstraints();
62        constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
63        constraintsLast.anchor    = GridBagConstraints.WEST;
64        constraintsLast.insets    = new Insets(1, 2, 1, 2);
65
66        GridBagConstraints constraintsLastStretch = new GridBagConstraints();
67        constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
68        constraintsLastStretch.fill      = GridBagConstraints.HORIZONTAL;
69        constraintsLastStretch.weightx   = 1.0;
70        constraintsLastStretch.anchor    = GridBagConstraints.WEST;
71        constraintsLastStretch.insets    = constraintsLast.insets;
72
73        GridBagConstraints panelConstraints = new GridBagConstraints();
74        panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
75        panelConstraints.fill      = GridBagConstraints.HORIZONTAL;
76        panelConstraints.weightx   = 1.0;
77        panelConstraints.weighty   = 0.0;
78        panelConstraints.anchor    = GridBagConstraints.NORTHWEST;
79        panelConstraints.insets    = constraintsLast.insets;
80
81        GridBagConstraints selectButtonConstraints = new GridBagConstraints();
82        selectButtonConstraints.weighty = 1.0;
83        selectButtonConstraints.anchor  = GridBagConstraints.SOUTHWEST;
84        selectButtonConstraints.insets  = new Insets(4, 4, 8, 4);
85
86        GridBagConstraints okButtonConstraints = new GridBagConstraints();
87        okButtonConstraints.weightx = 1.0;
88        okButtonConstraints.weighty = 1.0;
89        okButtonConstraints.anchor  = GridBagConstraints.SOUTHEAST;
90        okButtonConstraints.insets  = selectButtonConstraints.insets;
91
92        GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
93        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
94        cancelButtonConstraints.weighty   = 1.0;
95        cancelButtonConstraints.anchor    = GridBagConstraints.SOUTHEAST;
96        cancelButtonConstraints.insets    = selectButtonConstraints.insets;
97
98        GridBagLayout layout = new GridBagLayout();
99
100        Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
101
102        // Create the optimizations panel.
103        JPanel optimizationsPanel     = new JPanel(layout);
104        JPanel optimizationSubpanel   = null;
105        String lastOptimizationPrefix = null;
106
107        for (int index = 0; index < Optimizer.OPTIMIZATION_NAMES.length; index++)
108        {
109            String optimizationName = Optimizer.OPTIMIZATION_NAMES[index];
110
111            String optimizationPrefix = optimizationName.substring(0, optimizationName.indexOf('/'));
112
113            if (optimizationSubpanel == null || !optimizationPrefix.equals(lastOptimizationPrefix))
114            {
115                // Create a new keep subpanel and add it.
116                optimizationSubpanel = new JPanel(layout);
117                optimizationSubpanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, msg(optimizationPrefix)));
118                optimizationsPanel.add(optimizationSubpanel, panelConstraints);
119
120                lastOptimizationPrefix = optimizationPrefix;
121            }
122
123            JCheckBox optimizationCheckBox = new JCheckBox(optimizationName);
124            optimizationCheckBoxes[index] = optimizationCheckBox;
125
126            optimizationSubpanel.add(tip(optimizationCheckBox, optimizationName.replace('/', '_')+"Tip"), constraintsLastStretch);
127        }
128
129        // Create the Select All button.
130        JButton selectAllButton = new JButton(msg("selectAll"));
131        selectAllButton.addActionListener(new ActionListener()
132        {
133            public void actionPerformed(ActionEvent e)
134            {
135                for (int index = 0; index < optimizationCheckBoxes.length; index++)
136                {
137                    optimizationCheckBoxes[index].setSelected(true);
138                }
139            }
140        });
141
142        // Create the Select All button.
143        JButton selectNoneButton = new JButton(msg("selectNone"));
144        selectNoneButton.addActionListener(new ActionListener()
145        {
146            public void actionPerformed(ActionEvent e)
147            {
148                for (int index = 0; index < optimizationCheckBoxes.length; index++)
149                {
150                    optimizationCheckBoxes[index].setSelected(false);
151                }
152            }
153        });
154
155        // Create the Ok button.
156        JButton okButton = new JButton(msg("ok"));
157        okButton.addActionListener(new ActionListener()
158        {
159            public void actionPerformed(ActionEvent e)
160            {
161                returnValue = APPROVE_OPTION;
162                hide();
163            }
164        });
165
166        // Create the Cancel button.
167        JButton cancelButton = new JButton(msg("cancel"));
168        cancelButton.addActionListener(new ActionListener()
169        {
170            public void actionPerformed(ActionEvent e)
171            {
172                hide();
173            }
174        });
175
176        // Add all panels to the main panel.
177        optimizationsPanel.add(selectAllButton,  selectButtonConstraints);
178        optimizationsPanel.add(selectNoneButton, selectButtonConstraints);
179        optimizationsPanel.add(okButton,         okButtonConstraints);
180        optimizationsPanel.add(cancelButton,     cancelButtonConstraints);
181
182        getContentPane().add(new JScrollPane(optimizationsPanel));
183    }
184
185
186    /**
187     * Sets the initial optimization filter to be used by the dialog.
188     */
189    public void setFilter(String optimizations)
190    {
191        StringMatcher filter = optimizations != null && optimizations.length() > 0 ?
192            new ListParser(new NameParser()).parse(optimizations) :
193            new FixedStringMatcher("");
194
195        for (int index = 0; index < Optimizer.OPTIMIZATION_NAMES.length; index++)
196        {
197            optimizationCheckBoxes[index].setSelected(filter.matches(Optimizer.OPTIMIZATION_NAMES[index]));
198        }
199    }
200
201
202    /**
203     * Returns the optimization filter composed from the settings in the dialog.
204     */
205    public String getFilter()
206    {
207        return new FilterBuilder(optimizationCheckBoxes, '/').buildFilter();
208    }
209
210
211    /**
212     * Shows this dialog. This method only returns when the dialog is closed.
213     *
214     * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>,
215     *         depending on the choice of the user.
216     */
217    public int showDialog()
218    {
219        returnValue = CANCEL_OPTION;
220
221        // Open the dialog in the right place, then wait for it to be closed,
222        // one way or another.
223        pack();
224        setLocationRelativeTo(getOwner());
225        show();
226
227        return returnValue;
228    }
229
230
231    /**
232     * Attaches the tool tip from the GUI resources that corresponds to the
233     * given key, to the given component.
234     */
235    private static JComponent tip(JComponent component, String messageKey)
236    {
237        component.setToolTipText(msg(messageKey));
238
239        return component;
240    }
241
242
243    /**
244     * Returns the message from the GUI resources that corresponds to the given
245     * key.
246     */
247    private static String msg(String messageKey)
248    {
249         return GUIResources.getMessage(messageKey);
250    }
251}