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.*;
24import proguard.classfile.ClassConstants;
25import proguard.classfile.util.ClassUtil;
26
27import javax.swing.*;
28import java.awt.*;
29import java.awt.event.*;
30import java.util.*;
31import java.util.List;
32
33
34/**
35 * This <code>ListPanel</code> allows the user to add, edit, move, and remove
36 * MemberSpecification entries in a list.
37 *
38 * @author Eric Lafortune
39 */
40final class MemberSpecificationsPanel extends ListPanel
41{
42    private final MemberSpecificationDialog fieldSpecificationDialog;
43    private final MemberSpecificationDialog methodSpecificationDialog;
44
45
46    public MemberSpecificationsPanel(JDialog owner, boolean fullKeepOptions)
47    {
48        super();
49
50        super.firstSelectionButton = fullKeepOptions ? 3 : 2;
51
52        list.setCellRenderer(new MyListCellRenderer());
53
54        fieldSpecificationDialog  = new MemberSpecificationDialog(owner, true);
55        methodSpecificationDialog = new MemberSpecificationDialog(owner, false);
56
57        if (fullKeepOptions)
58        {
59            addAddFieldButton();
60        }
61        addAddMethodButton();
62        addEditButton();
63        addRemoveButton();
64        addUpButton();
65        addDownButton();
66
67        enableSelectionButtons();
68    }
69
70
71    protected void addAddFieldButton()
72    {
73        JButton addFieldButton = new JButton(msg("addField"));
74        addFieldButton.addActionListener(new ActionListener()
75        {
76            public void actionPerformed(ActionEvent e)
77            {
78                fieldSpecificationDialog.setMemberSpecification(new MemberSpecification());
79                int returnValue = fieldSpecificationDialog.showDialog();
80                if (returnValue == MemberSpecificationDialog.APPROVE_OPTION)
81                {
82                    // Add the new element.
83                    addElement(new MyMemberSpecificationWrapper(fieldSpecificationDialog.getMemberSpecification(),
84                                                                  true));
85                }
86            }
87        });
88
89        addButton(tip(addFieldButton, "addFieldTip"));
90    }
91
92
93    protected void addAddMethodButton()
94    {
95        JButton addMethodButton = new JButton(msg("addMethod"));
96        addMethodButton.addActionListener(new ActionListener()
97        {
98            public void actionPerformed(ActionEvent e)
99            {
100                methodSpecificationDialog.setMemberSpecification(new MemberSpecification());
101                int returnValue = methodSpecificationDialog.showDialog();
102                if (returnValue == MemberSpecificationDialog.APPROVE_OPTION)
103                {
104                    // Add the new element.
105                    addElement(new MyMemberSpecificationWrapper(methodSpecificationDialog.getMemberSpecification(),
106                                                                  false));
107                }
108            }
109        });
110
111        addButton(tip(addMethodButton, "addMethodTip"));
112    }
113
114
115    protected void addEditButton()
116    {
117        JButton editButton = new JButton(msg("edit"));
118        editButton.addActionListener(new ActionListener()
119        {
120            public void actionPerformed(ActionEvent e)
121            {
122                MyMemberSpecificationWrapper wrapper =
123                    (MyMemberSpecificationWrapper)list.getSelectedValue();
124
125                MemberSpecificationDialog memberSpecificationDialog =
126                    wrapper.isField ?
127                        fieldSpecificationDialog :
128                        methodSpecificationDialog;
129
130                memberSpecificationDialog.setMemberSpecification(wrapper.memberSpecification);
131                int returnValue = memberSpecificationDialog.showDialog();
132                if (returnValue == MemberSpecificationDialog.APPROVE_OPTION)
133                {
134                    // Replace the old element.
135                    wrapper.memberSpecification = memberSpecificationDialog.getMemberSpecification();
136                    setElementAt(wrapper,
137                                 list.getSelectedIndex());
138                }
139            }
140        });
141
142        addButton(tip(editButton, "editTip"));
143    }
144
145
146    /**
147     * Sets the MemberSpecification instances to be represented in this panel.
148     */
149    public void setMemberSpecifications(List fieldSpecifications,
150                                        List methodSpecifications)
151    {
152        listModel.clear();
153
154        if (fieldSpecifications != null)
155        {
156            for (int index = 0; index < fieldSpecifications.size(); index++)
157            {
158                listModel.addElement(
159                    new MyMemberSpecificationWrapper((MemberSpecification)fieldSpecifications.get(index),
160                                                     true));
161            }
162        }
163
164        if (methodSpecifications != null)
165        {
166            for (int index = 0; index < methodSpecifications.size(); index++)
167            {
168                listModel.addElement(
169                    new MyMemberSpecificationWrapper((MemberSpecification)methodSpecifications.get(index),
170                                                     false));
171            }
172        }
173
174        // Make sure the selection buttons are properly enabled,
175        // since the clear method doesn't seem to notify the listener.
176        enableSelectionButtons();
177    }
178
179
180    /**
181     * Returns the MemberSpecification instances currently represented in
182     * this panel, referring to fields or to methods.
183     *
184     * @param isField specifies whether specifications referring to fields or
185     *                specifications referring to methods should be returned.
186     */
187    public List getMemberSpecifications(boolean isField)
188    {
189        int size = listModel.size();
190        if (size == 0)
191        {
192            return null;
193        }
194
195        List memberSpecifications = new ArrayList(size);
196        for (int index = 0; index < size; index++)
197        {
198            MyMemberSpecificationWrapper wrapper =
199                (MyMemberSpecificationWrapper)listModel.get(index);
200
201            if (wrapper.isField == isField)
202            {
203                memberSpecifications.add(wrapper.memberSpecification);
204            }
205        }
206
207        return memberSpecifications;
208    }
209
210
211    /**
212     * This ListCellRenderer renders MemberSpecification objects.
213     */
214    private static class MyListCellRenderer implements ListCellRenderer
215    {
216        private final JLabel label = new JLabel();
217
218
219        // Implementations for ListCellRenderer.
220
221        public Component getListCellRendererComponent(JList   list,
222                                                      Object  value,
223                                                      int     index,
224                                                      boolean isSelected,
225                                                      boolean cellHasFocus)
226        {
227            MyMemberSpecificationWrapper wrapper = (MyMemberSpecificationWrapper)value;
228
229            MemberSpecification option = wrapper.memberSpecification;
230            String name       = option.name;
231            String descriptor = option.descriptor;
232
233            label.setText(wrapper.isField ?
234                (descriptor == null ? name == null ?
235                    "<fields>" :
236                    "***" + ' ' + name :
237                    ClassUtil.externalFullFieldDescription(0,
238                                                           name == null ? "*" : name,
239                                                           descriptor)) :
240                (descriptor == null ? name == null ?
241                    "<methods>" :
242                    "***" + ' ' + name + "(...)" :
243                    ClassUtil.externalFullMethodDescription(ClassConstants.INTERNAL_METHOD_NAME_INIT,
244                                                            0,
245                                                            name == null ? "*" : name,
246                                                            descriptor)));
247
248            if (isSelected)
249            {
250                label.setBackground(list.getSelectionBackground());
251                label.setForeground(list.getSelectionForeground());
252            }
253            else
254            {
255                label.setBackground(list.getBackground());
256                label.setForeground(list.getForeground());
257            }
258
259            label.setOpaque(true);
260
261            return label;
262        }
263    }
264
265
266    /**
267     * Attaches the tool tip from the GUI resources that corresponds to the
268     * given key, to the given component.
269     */
270    private static JComponent tip(JComponent component, String messageKey)
271    {
272        component.setToolTipText(msg(messageKey));
273
274        return component;
275    }
276
277
278    /**
279     * Returns the message from the GUI resources that corresponds to the given
280     * key.
281     */
282    private static String msg(String messageKey)
283    {
284         return GUIResources.getMessage(messageKey);
285    }
286
287
288    /**
289     * This class wraps a MemberSpecification, additionally storing whether
290     * the option refers to a field or to a method.
291     */
292    private static class MyMemberSpecificationWrapper
293    {
294        public MemberSpecification memberSpecification;
295        public final boolean             isField;
296
297        public MyMemberSpecificationWrapper(MemberSpecification memberSpecification,
298                                            boolean             isField)
299        {
300            this.memberSpecification = memberSpecification;
301            this.isField                  = isField;
302        }
303    }
304}
305