ListPanel.java revision cfead78069f3dc32998dc118ee08cab3867acea2
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2011 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 java.awt.*;
24import java.awt.event.*;
25import java.util.List;
26import java.util.*;
27
28import javax.swing.*;
29import javax.swing.event.*;
30
31/**
32 * This <code>Jpanel</code> allows the user to move and remove entries in a
33 * list and between lists. Extensions of this class should add buttons to add
34 * and possibly edit entries, and to set and get the resulting list.
35 *
36 * @author Eric Lafortune
37 */
38abstract class ListPanel extends JPanel
39{
40    protected final DefaultListModel listModel = new DefaultListModel();
41    protected final JList            list      = new JList(listModel);
42
43    protected int firstSelectionButton = 2;
44
45
46    protected ListPanel()
47    {
48        GridBagLayout layout = new GridBagLayout();
49        setLayout(layout);
50
51        GridBagConstraints listConstraints = new GridBagConstraints();
52        listConstraints.gridheight = GridBagConstraints.REMAINDER;
53        listConstraints.fill       = GridBagConstraints.BOTH;
54        listConstraints.weightx    = 1.0;
55        listConstraints.weighty    = 1.0;
56        listConstraints.anchor     = GridBagConstraints.NORTHWEST;
57        listConstraints.insets     = new Insets(0, 2, 0, 2);
58
59        // Make sure some buttons are disabled or enabled depending on whether
60        // the selection is empty or not.
61        list.addListSelectionListener(new ListSelectionListener()
62        {
63            public void valueChanged(ListSelectionEvent e)
64            {
65                enableSelectionButtons();
66            }
67        });
68
69        add(new JScrollPane(list), listConstraints);
70
71        // something like the following calls are up to the extending class:
72        //addAddButton();
73        //addEditButton();
74        //addRemoveButton();
75        //addUpButton();
76        //addDownButton();
77        //
78        //enableSelectionButtons();
79    }
80
81
82    protected void addRemoveButton()
83    {
84        JButton removeButton = new JButton(msg("remove"));
85        removeButton.addActionListener(new ActionListener()
86        {
87            public void actionPerformed(ActionEvent e)
88            {
89                // Remove the selected elements.
90                removeElementsAt(list.getSelectedIndices());
91            }
92        });
93
94        addButton(tip(removeButton, "removeTip"));
95    }
96
97
98    protected void addUpButton()
99    {
100        JButton upButton = new JButton(msg("moveUp"));
101        upButton.addActionListener(new ActionListener()
102        {
103            public void actionPerformed(ActionEvent e)
104            {
105                int[] selectedIndices = list.getSelectedIndices();
106                if (selectedIndices.length > 0 &&
107                    selectedIndices[0] > 0)
108                {
109                    // Move the selected elements up.
110                    moveElementsAt(selectedIndices, -1);
111                }
112            }
113        });
114
115        addButton(tip(upButton, "moveUpTip"));
116    }
117
118
119    protected void addDownButton()
120    {
121        JButton downButton = new JButton(msg("moveDown"));
122        downButton.addActionListener(new ActionListener()
123        {
124            public void actionPerformed(ActionEvent e)
125            {
126                int[] selectedIndices = list.getSelectedIndices();
127                if (selectedIndices.length > 0 &&
128                    selectedIndices[selectedIndices.length-1] < listModel.getSize()-1)
129                {
130                    // Move the selected elements down.
131                    moveElementsAt(selectedIndices, 1);
132                }
133            }
134        });
135
136        addButton(tip(downButton, "moveDownTip"));
137    }
138
139
140    /**
141     * Adds a button that allows to copy or move entries to another ListPanel.
142     *
143     * @param buttonTextKey the button text key.
144     * @param tipKey        the tool tip key.
145     * @param panel         the other ListPanel.
146     */
147    public void addCopyToPanelButton(String          buttonTextKey,
148                                     String          tipKey,
149                                     final ListPanel panel)
150    {
151        JButton moveButton = new JButton(msg(buttonTextKey));
152        moveButton.addActionListener(new ActionListener()
153        {
154            public void actionPerformed(ActionEvent e)
155            {
156                int[]    selectedIndices  = list.getSelectedIndices();
157                Object[] selectedElements = list.getSelectedValues();
158
159                // Remove the selected elements from this panel.
160                removeElementsAt(selectedIndices);
161
162                // Add the elements to the other panel.
163                panel.addElements(selectedElements);
164            }
165        });
166
167        addButton(tip(moveButton, tipKey));
168    }
169
170
171    protected void addButton(JComponent button)
172    {
173        GridBagConstraints buttonConstraints = new GridBagConstraints();
174        buttonConstraints.gridwidth = GridBagConstraints.REMAINDER;
175        buttonConstraints.fill      = GridBagConstraints.HORIZONTAL;
176        buttonConstraints.anchor    = GridBagConstraints.NORTHWEST;
177        buttonConstraints.insets    = new Insets(0, 2, 0, 2);
178
179        add(button, buttonConstraints);
180    }
181
182
183    /**
184     * Returns a list of all right-hand side buttons.
185     */
186    public List getButtons()
187    {
188        List list = new ArrayList(getComponentCount()-1);
189
190        // Add all buttons.
191        for (int index = 1; index < getComponentCount(); index++)
192        {
193            list.add(getComponent(index));
194        }
195
196        return list;
197    }
198
199
200    protected void addElement(Object element)
201    {
202        listModel.addElement(element);
203
204        // Make sure it is selected.
205        list.setSelectedIndex(listModel.size() - 1);
206    }
207
208
209    protected void addElements(Object[] elements)
210    {
211        // Add the elements one by one.
212        for (int index = 0; index < elements.length; index++)
213        {
214            listModel.addElement(elements[index]);
215        }
216
217        // Make sure they are selected.
218        int[] selectedIndices = new int[elements.length];
219        for (int index = 0; index < selectedIndices.length; index++)
220        {
221            selectedIndices[index] =
222                listModel.size() - selectedIndices.length + index;
223        }
224        list.setSelectedIndices(selectedIndices);
225    }
226
227
228    protected void moveElementsAt(int[] indices, int offset)
229    {
230        // Remember the selected elements.
231        Object[] selectedElements = list.getSelectedValues();
232
233        // Remove the selected elements.
234        removeElementsAt(indices);
235
236        // Update the element indices.
237        for (int index = 0; index < indices.length; index++)
238        {
239            indices[index] += offset;
240        }
241
242        // Reinsert the selected elements.
243        insertElementsAt(selectedElements, indices);
244    }
245
246
247    protected void insertElementsAt(Object[] elements, int[] indices)
248    {
249        for (int index = 0; index < elements.length; index++)
250        {
251            listModel.insertElementAt(elements[index], indices[index]);
252        }
253
254        // Make sure they are selected.
255        list.setSelectedIndices(indices);
256    }
257
258
259    protected void setElementAt(Object element, int index)
260    {
261        listModel.setElementAt(element, index);
262
263        // Make sure it is selected.
264        list.setSelectedIndex(index);
265    }
266
267
268    protected void setElementsAt(Object[] elements, int[] indices)
269    {
270        for (int index = 0; index < elements.length; index++)
271        {
272            listModel.setElementAt(elements[index], indices[index]);
273        }
274
275        // Make sure they are selected.
276        list.setSelectedIndices(indices);
277    }
278
279
280    protected void removeElementsAt(int[] indices)
281    {
282        for (int index = indices.length - 1; index >= 0; index--)
283        {
284            listModel.removeElementAt(indices[index]);
285        }
286
287        // Make sure nothing is selected.
288        list.clearSelection();
289
290        // Make sure the selection buttons are properly enabled,
291        // since the above method doesn't seem to notify the listener.
292        enableSelectionButtons();
293    }
294
295
296    protected void removeAllElements()
297    {
298        listModel.removeAllElements();
299
300        // Make sure the selection buttons are properly enabled,
301        // since the above method doesn't seem to notify the listener.
302        enableSelectionButtons();
303    }
304
305
306    /**
307     * Enables or disables the buttons that depend on a selection.
308     */
309    protected void enableSelectionButtons()
310    {
311        boolean selected = !list.isSelectionEmpty();
312
313        // Loop over all components, except the list itself and the Add button.
314        for (int index = firstSelectionButton; index < getComponentCount(); index++)
315        {
316            getComponent(index).setEnabled(selected);
317        }
318    }
319
320
321    /**
322     * Attaches the tool tip from the GUI resources that corresponds to the
323     * given key, to the given component.
324     */
325    private static JComponent tip(JComponent component, String messageKey)
326    {
327        component.setToolTipText(msg(messageKey));
328
329        return component;
330    }
331
332
333    /**
334     * Returns the message from the GUI resources that corresponds to the given
335     * key.
336     */
337    private static String msg(String messageKey)
338    {
339         return GUIResources.getMessage(messageKey);
340    }
341}
342