• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
21 package proguard.gui;
22 
23 import proguard.*;
24 import proguard.util.ListUtil;
25 
26 import javax.swing.*;
27 import java.awt.*;
28 import java.awt.event.*;
29 import java.io.File;
30 import java.util.List;
31 
32 /**
33  * This <code>ListPanel</code> allows the user to add, edit, filter, move, and
34  * remove ClassPathEntry objects in a ClassPath object.
35  *
36  * @author Eric Lafortune
37  */
38 class ClassPathPanel extends ListPanel
39 {
40     private final JFrame       owner;
41     private final boolean      inputAndOutput;
42     private final JFileChooser chooser;
43     private final FilterDialog filterDialog;
44 
45 
ClassPathPanel(JFrame owner, boolean inputAndOutput)46     public ClassPathPanel(JFrame owner, boolean inputAndOutput)
47     {
48         super();
49 
50         super.firstSelectionButton = inputAndOutput ? 3 : 2;
51 
52         this.owner          = owner;
53         this.inputAndOutput = inputAndOutput;
54 
55         list.setCellRenderer(new MyListCellRenderer());
56 
57         chooser = new JFileChooser("");
58         chooser.setMultiSelectionEnabled(true);
59         chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
60         chooser.addChoosableFileFilter(
61             new ExtensionFileFilter(msg("jarWarEarZipExtensions"),
62                                     new String[] { ".jar", ".war", ".ear", ".zip" }));
63         chooser.setApproveButtonText(msg("ok"));
64 
65         filterDialog = new FilterDialog(owner, msg("enterFilter"));
66 
67         addAddButton(inputAndOutput, false);
68         if (inputAndOutput)
69         {
70             addAddButton(inputAndOutput, true);
71         }
72         addEditButton();
73         addFilterButton();
74         addRemoveButton();
75         addUpButton();
76         addDownButton();
77 
78         enableSelectionButtons();
79     }
80 
81 
addAddButton(boolean inputAndOutput, final boolean isOutput)82     protected void addAddButton(boolean       inputAndOutput,
83                                 final boolean isOutput)
84     {
85         JButton addButton = new JButton(msg(inputAndOutput ?
86                                             isOutput       ? "addOutput" :
87                                                              "addInput" :
88                                                              "add"));
89         addButton.addActionListener(new ActionListener()
90         {
91             public void actionPerformed(ActionEvent e)
92             {
93                 chooser.setDialogTitle(msg("addJars"));
94                 chooser.setSelectedFile(null);
95                 chooser.setSelectedFiles(null);
96 
97                 int returnValue = chooser.showOpenDialog(owner);
98                 if (returnValue == JFileChooser.APPROVE_OPTION)
99                 {
100                     File[] selectedFiles = chooser.getSelectedFiles();
101                     ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput);
102 
103                     // Add the new elements.
104                     addElements(entries);
105                 }
106             }
107         });
108 
109         addButton(tip(addButton, inputAndOutput ?
110                                  isOutput       ? "addOutputTip" :
111                                                   "addInputTip" :
112                                                   "addTip"));
113     }
114 
115 
addEditButton()116     protected void addEditButton()
117     {
118         JButton editButton = new JButton(msg("edit"));
119         editButton.addActionListener(new ActionListener()
120         {
121             public void actionPerformed(ActionEvent e)
122             {
123                 boolean isOutput = false;
124 
125                 int[] selectedIndices = list.getSelectedIndices();
126 
127                 // Copy the Object array into a File array.
128                 File[] selectedFiles = new File[selectedIndices.length];
129                 for (int index = 0; index < selectedFiles.length; index++)
130                 {
131                     ClassPathEntry entry =
132                         (ClassPathEntry)listModel.getElementAt(selectedIndices[index]);
133 
134                     isOutput = entry.isOutput();
135 
136                     selectedFiles[index] = entry.getFile();
137                 }
138 
139                 chooser.setDialogTitle(msg("chooseJars"));
140 
141                 // Up to JDK 1.3.1, setSelectedFiles doesn't show in the file
142                 // chooser, so we just use setSelectedFile first. It also sets
143                 // the current directory.
144                 chooser.setSelectedFile(selectedFiles[0]);
145                 chooser.setSelectedFiles(selectedFiles);
146 
147                 int returnValue = chooser.showOpenDialog(owner);
148                 if (returnValue == JFileChooser.APPROVE_OPTION)
149                 {
150                     selectedFiles = chooser.getSelectedFiles();
151                     ClassPathEntry[] entries = classPathEntries(selectedFiles, isOutput);
152 
153                     // If there are the same number of files selected now as
154                     // there were before, we can just replace the old ones.
155                     if (selectedIndices.length == selectedFiles.length)
156                     {
157                         // Replace the old elements.
158                         setElementsAt(entries, selectedIndices);
159                     }
160                     else
161                     {
162                         // Remove the old elements.
163                         removeElementsAt(selectedIndices);
164 
165                         // Add the new elements.
166                         addElements(entries);
167                     }
168                 }
169             }
170         });
171 
172         addButton(tip(editButton, "editTip"));
173     }
174 
175 
addFilterButton()176     protected void addFilterButton()
177     {
178         JButton filterButton = new JButton(msg("filter"));
179         filterButton.addActionListener(new ActionListener()
180         {
181             public void actionPerformed(ActionEvent e)
182             {
183                 if (!list.isSelectionEmpty())
184                 {
185                     int[] selectedIndices = list.getSelectedIndices();
186 
187                     // Put the filters of the first selected entry in the dialog.
188                     getFiltersFrom(selectedIndices[0]);
189 
190                     int returnValue = filterDialog.showDialog();
191                     if (returnValue == FilterDialog.APPROVE_OPTION)
192                     {
193                         // Apply the entered filters to all selected entries.
194                         setFiltersAt(selectedIndices);
195                     }
196                 }
197             }
198         });
199 
200         addButton(tip(filterButton, "filterTip"));
201     }
202 
203 
204     /**
205      * Sets the ClassPath to be represented in this panel.
206      */
setClassPath(ClassPath classPath)207     public void setClassPath(ClassPath classPath)
208     {
209         listModel.clear();
210 
211         if (classPath != null)
212         {
213             for (int index = 0; index < classPath.size(); index++)
214             {
215                 listModel.addElement(classPath.get(index));
216             }
217         }
218 
219         // Make sure the selection buttons are properly enabled,
220         // since the clear method doesn't seem to notify the listener.
221         enableSelectionButtons();
222     }
223 
224 
225     /**
226      * Returns the ClassPath currently represented in this panel.
227      */
getClassPath()228     public ClassPath getClassPath()
229     {
230         int size = listModel.size();
231         if (size == 0)
232         {
233             return null;
234         }
235 
236         ClassPath classPath = new ClassPath();
237         for (int index = 0; index < size; index++)
238         {
239             classPath.add((ClassPathEntry)listModel.get(index));
240         }
241 
242         return classPath;
243     }
244 
245 
246     /**
247      * Converts the given array of File objects into a corresponding array of
248      * ClassPathEntry objects.
249      */
classPathEntries(File[] files, boolean isOutput)250     private ClassPathEntry[] classPathEntries(File[] files, boolean isOutput)
251     {
252         ClassPathEntry[] entries = new ClassPathEntry[files.length];
253         for (int index = 0; index < entries.length; index++)
254         {
255             entries[index] = new ClassPathEntry(files[index], isOutput);
256         }
257         return entries;
258     }
259 
260 
261     /**
262      * Sets up the filter dialog with the filters from the specified class path
263      * entry.
264      */
getFiltersFrom(int index)265     private void getFiltersFrom(int index)
266     {
267         ClassPathEntry firstEntry = (ClassPathEntry)listModel.get(index);
268 
269         filterDialog.setFilter(firstEntry.getFilter());
270         filterDialog.setJarFilter(firstEntry.getJarFilter());
271         filterDialog.setWarFilter(firstEntry.getWarFilter());
272         filterDialog.setEarFilter(firstEntry.getEarFilter());
273         filterDialog.setZipFilter(firstEntry.getZipFilter());
274     }
275 
276 
277     /**
278      * Applies the entered filter to the specified class path entries.
279      * Any previously set filters are discarded.
280      */
setFiltersAt(int[] indices)281     private void setFiltersAt(int[] indices)
282     {
283         for (int index = indices.length - 1; index >= 0; index--)
284         {
285             ClassPathEntry entry = (ClassPathEntry)listModel.get(indices[index]);
286             entry.setFilter(filterDialog.getFilter());
287             entry.setJarFilter(filterDialog.getJarFilter());
288             entry.setWarFilter(filterDialog.getWarFilter());
289             entry.setEarFilter(filterDialog.getEarFilter());
290             entry.setZipFilter(filterDialog.getZipFilter());
291         }
292 
293         // Make sure they are selected and thus repainted.
294         list.setSelectedIndices(indices);
295     }
296 
297 
298     /**
299      * Attaches the tool tip from the GUI resources that corresponds to the
300      * given key, to the given component.
301      */
tip(JComponent component, String messageKey)302     private static JComponent tip(JComponent component, String messageKey)
303     {
304         component.setToolTipText(msg(messageKey));
305 
306         return component;
307     }
308 
309 
310     /**
311      * Returns the message from the GUI resources that corresponds to the given
312      * key.
313      */
msg(String messageKey)314     private static String msg(String messageKey)
315     {
316          return GUIResources.getMessage(messageKey);
317     }
318 
319 
320     /**
321      * This ListCellRenderer renders ClassPathEntry objects.
322      */
323     private class MyListCellRenderer implements ListCellRenderer
324     {
325         private static final String ARROW_IMAGE_FILE = "arrow.gif";
326 
327         private final JPanel cellPanel    = new JPanel(new GridBagLayout());
328         private final JLabel iconLabel    = new JLabel("", JLabel.RIGHT);
329         private final JLabel jarNameLabel = new JLabel("", JLabel.RIGHT);
330         private final JLabel filterLabel  = new JLabel("", JLabel.RIGHT);
331 
332         private final Icon arrowIcon;
333 
334 
MyListCellRenderer()335         public MyListCellRenderer()
336         {
337             GridBagConstraints jarNameLabelConstraints = new GridBagConstraints();
338             jarNameLabelConstraints.anchor             = GridBagConstraints.WEST;
339             jarNameLabelConstraints.insets             = new Insets(1, 2, 1, 2);
340 
341             GridBagConstraints filterLabelConstraints  = new GridBagConstraints();
342             filterLabelConstraints.gridwidth           = GridBagConstraints.REMAINDER;
343             filterLabelConstraints.fill                = GridBagConstraints.HORIZONTAL;
344             filterLabelConstraints.weightx             = 1.0;
345             filterLabelConstraints.anchor              = GridBagConstraints.EAST;
346             filterLabelConstraints.insets              = jarNameLabelConstraints.insets;
347 
348             arrowIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(ARROW_IMAGE_FILE)));
349 
350             cellPanel.add(iconLabel,    jarNameLabelConstraints);
351             cellPanel.add(jarNameLabel, jarNameLabelConstraints);
352             cellPanel.add(filterLabel,  filterLabelConstraints);
353         }
354 
355 
356         // Implementations for ListCellRenderer.
357 
getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)358         public Component getListCellRendererComponent(JList   list,
359                                                       Object  value,
360                                                       int     index,
361                                                       boolean isSelected,
362                                                       boolean cellHasFocus)
363         {
364             ClassPathEntry entry = (ClassPathEntry)value;
365 
366             // Prepend an arrow to the output entries.
367             if (inputAndOutput && entry.isOutput())
368             {
369                 iconLabel.setIcon(arrowIcon);
370             }
371             else
372             {
373                 iconLabel.setIcon(null);
374             }
375 
376             // Set the entry name text.
377             jarNameLabel.setText(entry.getName());
378 
379             // Set the filter text.
380             StringBuffer filter = null;
381             filter = appendFilter(filter, entry.getZipFilter());
382             filter = appendFilter(filter, entry.getEarFilter());
383             filter = appendFilter(filter, entry.getWarFilter());
384             filter = appendFilter(filter, entry.getJarFilter());
385             filter = appendFilter(filter, entry.getFilter());
386 
387             if (filter != null)
388             {
389                 filter.append(')');
390             }
391 
392             filterLabel.setText(filter != null ? filter.toString() : "");
393 
394             // Set the colors.
395             if (isSelected)
396             {
397                 cellPanel.setBackground(list.getSelectionBackground());
398                 jarNameLabel.setForeground(list.getSelectionForeground());
399                 filterLabel.setForeground(list.getSelectionForeground());
400             }
401             else
402             {
403                 cellPanel.setBackground(list.getBackground());
404                 jarNameLabel.setForeground(list.getForeground());
405                 filterLabel.setForeground(list.getForeground());
406             }
407 
408             // Make the font color red if this is an input file that can't be read.
409             if (!(inputAndOutput && entry.isOutput()) &&
410                 !entry.getFile().canRead())
411             {
412                 jarNameLabel.setForeground(Color.red);
413             }
414 
415             cellPanel.setOpaque(true);
416 
417             return cellPanel;
418         }
419 
420 
appendFilter(StringBuffer filter, List additionalFilter)421         private StringBuffer appendFilter(StringBuffer filter, List additionalFilter)
422         {
423             if (filter != null)
424             {
425                 filter.append(';');
426             }
427 
428             if (additionalFilter != null)
429             {
430                 if (filter == null)
431                 {
432                     filter = new StringBuffer().append('(');
433                 }
434 
435                 filter.append(ListUtil.commaSeparatedString(additionalFilter));
436             }
437 
438             return filter;
439         }
440     }
441 }
442