• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  *             of Java bytecode.
4  *
5  * Copyright (c) 2002-2014 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("jarExtensions"),
62                                     new String[] { ".apk", ".ap_", ".jar", ".aar", ".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].getAbsoluteFile());
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.setApkFilter(firstEntry.getApkFilter());
271         filterDialog.setJarFilter(firstEntry.getJarFilter());
272         filterDialog.setAarFilter(firstEntry.getAarFilter());
273         filterDialog.setWarFilter(firstEntry.getWarFilter());
274         filterDialog.setEarFilter(firstEntry.getEarFilter());
275         filterDialog.setZipFilter(firstEntry.getZipFilter());
276     }
277 
278 
279     /**
280      * Applies the entered filter to the specified class path entries.
281      * Any previously set filters are discarded.
282      */
setFiltersAt(int[] indices)283     private void setFiltersAt(int[] indices)
284     {
285         for (int index = indices.length - 1; index >= 0; index--)
286         {
287             ClassPathEntry entry = (ClassPathEntry)listModel.get(indices[index]);
288             entry.setFilter(filterDialog.getFilter());
289             entry.setApkFilter(filterDialog.getApkFilter());
290             entry.setJarFilter(filterDialog.getJarFilter());
291             entry.setAarFilter(filterDialog.getAarFilter());
292             entry.setWarFilter(filterDialog.getWarFilter());
293             entry.setEarFilter(filterDialog.getEarFilter());
294             entry.setZipFilter(filterDialog.getZipFilter());
295         }
296 
297         // Make sure they are selected and thus repainted.
298         list.setSelectedIndices(indices);
299     }
300 
301 
302     /**
303      * Attaches the tool tip from the GUI resources that corresponds to the
304      * given key, to the given component.
305      */
tip(JComponent component, String messageKey)306     private static JComponent tip(JComponent component, String messageKey)
307     {
308         component.setToolTipText(msg(messageKey));
309 
310         return component;
311     }
312 
313 
314     /**
315      * Returns the message from the GUI resources that corresponds to the given
316      * key.
317      */
msg(String messageKey)318     private static String msg(String messageKey)
319     {
320          return GUIResources.getMessage(messageKey);
321     }
322 
323 
324     /**
325      * This ListCellRenderer renders ClassPathEntry objects.
326      */
327     private class MyListCellRenderer implements ListCellRenderer
328     {
329         private static final String ARROW_IMAGE_FILE = "arrow.gif";
330 
331         private final JPanel cellPanel    = new JPanel(new GridBagLayout());
332         private final JLabel iconLabel    = new JLabel("", JLabel.RIGHT);
333         private final JLabel jarNameLabel = new JLabel("", JLabel.RIGHT);
334         private final JLabel filterLabel  = new JLabel("", JLabel.RIGHT);
335 
336         private final Icon arrowIcon;
337 
338 
MyListCellRenderer()339         public MyListCellRenderer()
340         {
341             GridBagConstraints jarNameLabelConstraints = new GridBagConstraints();
342             jarNameLabelConstraints.anchor             = GridBagConstraints.WEST;
343             jarNameLabelConstraints.insets             = new Insets(1, 2, 1, 2);
344 
345             GridBagConstraints filterLabelConstraints  = new GridBagConstraints();
346             filterLabelConstraints.gridwidth           = GridBagConstraints.REMAINDER;
347             filterLabelConstraints.fill                = GridBagConstraints.HORIZONTAL;
348             filterLabelConstraints.weightx             = 1.0;
349             filterLabelConstraints.anchor              = GridBagConstraints.EAST;
350             filterLabelConstraints.insets              = jarNameLabelConstraints.insets;
351 
352             arrowIcon = new ImageIcon(Toolkit.getDefaultToolkit().getImage(this.getClass().getResource(ARROW_IMAGE_FILE)));
353 
354             cellPanel.add(iconLabel,    jarNameLabelConstraints);
355             cellPanel.add(jarNameLabel, jarNameLabelConstraints);
356             cellPanel.add(filterLabel,  filterLabelConstraints);
357         }
358 
359 
360         // Implementations for ListCellRenderer.
361 
getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)362         public Component getListCellRendererComponent(JList   list,
363                                                       Object  value,
364                                                       int     index,
365                                                       boolean isSelected,
366                                                       boolean cellHasFocus)
367         {
368             ClassPathEntry entry = (ClassPathEntry)value;
369 
370             // Prepend an arrow to the output entries.
371             if (inputAndOutput && entry.isOutput())
372             {
373                 iconLabel.setIcon(arrowIcon);
374             }
375             else
376             {
377                 iconLabel.setIcon(null);
378             }
379 
380             // Set the entry name text.
381             jarNameLabel.setText(entry.getName());
382 
383             // Set the filter text.
384             StringBuffer filter = null;
385             filter = appendFilter(filter, entry.getZipFilter());
386             filter = appendFilter(filter, entry.getEarFilter());
387             filter = appendFilter(filter, entry.getWarFilter());
388             filter = appendFilter(filter, entry.getAarFilter());
389             filter = appendFilter(filter, entry.getJarFilter());
390             filter = appendFilter(filter, entry.getApkFilter());
391             filter = appendFilter(filter, entry.getFilter());
392 
393             if (filter != null)
394             {
395                 filter.append(')');
396             }
397 
398             filterLabel.setText(filter != null ? filter.toString() : "");
399 
400             // Set the colors.
401             if (isSelected)
402             {
403                 cellPanel.setBackground(list.getSelectionBackground());
404                 jarNameLabel.setForeground(list.getSelectionForeground());
405                 filterLabel.setForeground(list.getSelectionForeground());
406             }
407             else
408             {
409                 cellPanel.setBackground(list.getBackground());
410                 jarNameLabel.setForeground(list.getForeground());
411                 filterLabel.setForeground(list.getForeground());
412             }
413 
414             // Make the font color red if this is an input file that can't be read.
415             if (!(inputAndOutput && entry.isOutput()) &&
416                 !entry.getFile().canRead())
417             {
418                 jarNameLabel.setForeground(Color.red);
419             }
420 
421             cellPanel.setOpaque(true);
422 
423             return cellPanel;
424         }
425 
426 
appendFilter(StringBuffer filter, List additionalFilter)427         private StringBuffer appendFilter(StringBuffer filter, List additionalFilter)
428         {
429             if (filter != null)
430             {
431                 filter.append(';');
432             }
433 
434             if (additionalFilter != null)
435             {
436                 if (filter == null)
437                 {
438                     filter = new StringBuffer().append('(');
439                 }
440 
441                 filter.append(ListUtil.commaSeparatedString(additionalFilter, true));
442             }
443 
444             return filter;
445         }
446     }
447 }
448