001: /* $Id: ClassPathPanel.java,v 1.22 2007/08/18 10:34:56 eric Exp $
002: *
003: * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.gui;
022:
023: import java.awt.*;
024: import java.awt.event.*;
025: import java.io.File;
026:
027: import javax.swing.*;
028:
029: import proguard.*;
030:
031: /**
032: * This <code>ListPanel</code> allows the user to add, edit, filter, move, and
033: * remove ClassPathEntry objects in a ClassPath object.
034: *
035: * @author Eric Lafortune
036: */
037: class ClassPathPanel extends ListPanel {
038: private final JFrame owner;
039: private final boolean inputAndOutput;
040: private final JFileChooser chooser;
041: private final FilterDialog filterDialog;
042:
043: public ClassPathPanel(JFrame owner, boolean inputAndOutput) {
044: super ();
045:
046: super .firstSelectionButton = inputAndOutput ? 3 : 2;
047:
048: this .owner = owner;
049: this .inputAndOutput = inputAndOutput;
050:
051: list.setCellRenderer(new MyListCellRenderer());
052:
053: chooser = new JFileChooser("");
054: chooser.setMultiSelectionEnabled(true);
055: chooser
056: .setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
057: chooser.addChoosableFileFilter(new ExtensionFileFilter(
058: msg("jarWarEarZipExtensions"), new String[] { ".jar",
059: ".war", ".ear", ".zip" }));
060: chooser.setApproveButtonText(msg("ok"));
061:
062: filterDialog = new FilterDialog(owner, msg("enterFilter"));
063:
064: addAddButton(inputAndOutput, false);
065: if (inputAndOutput) {
066: addAddButton(inputAndOutput, true);
067: }
068: addEditButton();
069: addFilterButton();
070: addRemoveButton();
071: addUpButton();
072: addDownButton();
073:
074: enableSelectionButtons();
075: }
076:
077: protected void addAddButton(boolean inputAndOutput,
078: final boolean isOutput) {
079: JButton addButton = new JButton(
080: msg(inputAndOutput ? isOutput ? "addOutput"
081: : "addInput" : "add"));
082: addButton.addActionListener(new ActionListener() {
083: public void actionPerformed(ActionEvent e) {
084: chooser.setDialogTitle(msg("addJars"));
085: chooser.setSelectedFile(null);
086: chooser.setSelectedFiles(null);
087:
088: int returnValue = chooser.showOpenDialog(owner);
089: if (returnValue == JFileChooser.APPROVE_OPTION) {
090: File[] selectedFiles = chooser.getSelectedFiles();
091: ClassPathEntry[] entries = classPathEntries(
092: selectedFiles, isOutput);
093:
094: // Add the new elements.
095: addElements(entries);
096: }
097: }
098: });
099:
100: addButton(tip(addButton,
101: inputAndOutput ? isOutput ? "addOutputTip"
102: : "addInputTip" : "addTip"));
103: }
104:
105: protected void addEditButton() {
106: JButton editButton = new JButton(msg("edit"));
107: editButton.addActionListener(new ActionListener() {
108: public void actionPerformed(ActionEvent e) {
109: boolean isOutput = false;
110:
111: int[] selectedIndices = list.getSelectedIndices();
112:
113: // Copy the Object array into a File array.
114: File[] selectedFiles = new File[selectedIndices.length];
115: for (int index = 0; index < selectedFiles.length; index++) {
116: ClassPathEntry entry = (ClassPathEntry) listModel
117: .getElementAt(selectedIndices[index]);
118:
119: isOutput = entry.isOutput();
120:
121: selectedFiles[index] = entry.getFile();
122: }
123:
124: chooser.setDialogTitle(msg("chooseJars"));
125:
126: // Up to JDK 1.3.1, setSelectedFiles doesn't show in the file
127: // chooser, so we just use setSelectedFile first. It also sets
128: // the current directory.
129: chooser.setSelectedFile(selectedFiles[0]);
130: chooser.setSelectedFiles(selectedFiles);
131:
132: int returnValue = chooser.showOpenDialog(owner);
133: if (returnValue == JFileChooser.APPROVE_OPTION) {
134: selectedFiles = chooser.getSelectedFiles();
135: ClassPathEntry[] entries = classPathEntries(
136: selectedFiles, isOutput);
137:
138: // If there are the same number of files selected now as
139: // there were before, we can just replace the old ones.
140: if (selectedIndices.length == selectedFiles.length) {
141: // Replace the old elements.
142: setElementsAt(entries, selectedIndices);
143: } else {
144: // Remove the old elements.
145: removeElementsAt(selectedIndices);
146:
147: // Add the new elements.
148: addElements(entries);
149: }
150: }
151: }
152: });
153:
154: addButton(tip(editButton, "editTip"));
155: }
156:
157: protected void addFilterButton() {
158: JButton filterButton = new JButton(msg("filter"));
159: filterButton.addActionListener(new ActionListener() {
160: public void actionPerformed(ActionEvent e) {
161: if (!list.isSelectionEmpty()) {
162: int[] selectedIndices = list.getSelectedIndices();
163:
164: // Put the filters of the first selected entry in the dialog.
165: getFiltersFrom(selectedIndices[0]);
166:
167: int returnValue = filterDialog.showDialog();
168: if (returnValue == FilterDialog.APPROVE_OPTION) {
169: // Apply the entered filters to all selected entries.
170: setFiltersAt(selectedIndices);
171: }
172: }
173: }
174: });
175:
176: addButton(tip(filterButton, "filterTip"));
177: }
178:
179: /**
180: * Sets the ClassPath to be represented in this panel.
181: */
182: public void setClassPath(ClassPath classPath) {
183: listModel.clear();
184:
185: if (classPath != null) {
186: for (int index = 0; index < classPath.size(); index++) {
187: listModel.addElement(classPath.get(index));
188: }
189: }
190:
191: // Make sure the selection buttons are properly enabled,
192: // since the clear method doesn't seem to notify the listener.
193: enableSelectionButtons();
194: }
195:
196: /**
197: * Returns the ClassPath currently represented in this panel.
198: */
199: public ClassPath getClassPath() {
200: int size = listModel.size();
201: if (size == 0) {
202: return null;
203: }
204:
205: ClassPath classPath = new ClassPath();
206: for (int index = 0; index < size; index++) {
207: classPath.add((ClassPathEntry) listModel.get(index));
208: }
209:
210: return classPath;
211: }
212:
213: /**
214: * Converts the given array of File objects into a corresponding array of
215: * ClassPathEntry objects.
216: */
217: private ClassPathEntry[] classPathEntries(File[] files,
218: boolean isOutput) {
219: ClassPathEntry[] entries = new ClassPathEntry[files.length];
220: for (int index = 0; index < entries.length; index++) {
221: entries[index] = new ClassPathEntry(files[index], isOutput);
222: }
223: return entries;
224: }
225:
226: /**
227: * Sets up the filter dialog with the filters from the specified class path
228: * entry.
229: */
230: private void getFiltersFrom(int index) {
231: ClassPathEntry firstEntry = (ClassPathEntry) listModel
232: .get(index);
233:
234: filterDialog.setFilter(firstEntry.getFilter());
235: filterDialog.setJarFilter(firstEntry.getJarFilter());
236: filterDialog.setWarFilter(firstEntry.getWarFilter());
237: filterDialog.setEarFilter(firstEntry.getEarFilter());
238: filterDialog.setZipFilter(firstEntry.getZipFilter());
239: }
240:
241: /**
242: * Applies the entered filter to the specified class path entries.
243: * Any previously set filters are discarded.
244: */
245: private void setFiltersAt(int[] indices) {
246: for (int index = indices.length - 1; index >= 0; index--) {
247: ClassPathEntry entry = (ClassPathEntry) listModel
248: .get(indices[index]);
249: entry.setFilter(filterDialog.getFilter());
250: entry.setJarFilter(filterDialog.getJarFilter());
251: entry.setWarFilter(filterDialog.getWarFilter());
252: entry.setEarFilter(filterDialog.getEarFilter());
253: entry.setZipFilter(filterDialog.getZipFilter());
254: }
255:
256: // Make sure they are selected and thus repainted.
257: list.setSelectedIndices(indices);
258: }
259:
260: /**
261: * Attaches the tool tip from the GUI resources that corresponds to the
262: * given key, to the given component.
263: */
264: private static JComponent tip(JComponent component,
265: String messageKey) {
266: component.setToolTipText(msg(messageKey));
267:
268: return component;
269: }
270:
271: /**
272: * Returns the message from the GUI resources that corresponds to the given
273: * key.
274: */
275: private static String msg(String messageKey) {
276: return GUIResources.getMessage(messageKey);
277: }
278:
279: /**
280: * This ListCellRenderer renders ClassPathEntry objects.
281: */
282: private class MyListCellRenderer implements ListCellRenderer {
283: private static final String ARROW_IMAGE_FILE = "arrow.gif";
284:
285: private final JPanel cellPanel = new JPanel(new GridBagLayout());
286: private final JLabel iconLabel = new JLabel("", JLabel.RIGHT);
287: private final JLabel jarNameLabel = new JLabel("", JLabel.RIGHT);
288: private final JLabel filterLabel = new JLabel("", JLabel.RIGHT);
289:
290: private final Icon arrowIcon;
291:
292: public MyListCellRenderer() {
293: GridBagConstraints jarNameLabelConstraints = new GridBagConstraints();
294: jarNameLabelConstraints.anchor = GridBagConstraints.WEST;
295: jarNameLabelConstraints.insets = new Insets(1, 2, 1, 2);
296:
297: GridBagConstraints filterLabelConstraints = new GridBagConstraints();
298: filterLabelConstraints.gridwidth = GridBagConstraints.REMAINDER;
299: filterLabelConstraints.fill = GridBagConstraints.HORIZONTAL;
300: filterLabelConstraints.weightx = 1.0;
301: filterLabelConstraints.anchor = GridBagConstraints.EAST;
302: filterLabelConstraints.insets = jarNameLabelConstraints.insets;
303:
304: arrowIcon = new ImageIcon(Toolkit.getDefaultToolkit()
305: .getImage(
306: this .getClass().getResource(
307: ARROW_IMAGE_FILE)));
308:
309: cellPanel.add(iconLabel, jarNameLabelConstraints);
310: cellPanel.add(jarNameLabel, jarNameLabelConstraints);
311: cellPanel.add(filterLabel, filterLabelConstraints);
312: }
313:
314: // Implementations for ListCellRenderer.
315:
316: public Component getListCellRendererComponent(JList list,
317: Object value, int index, boolean isSelected,
318: boolean cellHasFocus) {
319: ClassPathEntry entry = (ClassPathEntry) value;
320:
321: // Prepend an arrow to the output entries.
322: if (inputAndOutput && entry.isOutput()) {
323: iconLabel.setIcon(arrowIcon);
324: } else {
325: iconLabel.setIcon(null);
326: }
327:
328: // Set the entry name text.
329: jarNameLabel.setText(entry.getName());
330:
331: // Set the filter text.
332: StringBuffer filter = null;
333: filter = appendFilter(filter, entry.getZipFilter());
334: filter = appendFilter(filter, entry.getEarFilter());
335: filter = appendFilter(filter, entry.getWarFilter());
336: filter = appendFilter(filter, entry.getJarFilter());
337: filter = appendFilter(filter, entry.getFilter());
338:
339: if (filter != null) {
340: filter.append(')');
341: }
342:
343: filterLabel
344: .setText(filter != null ? filter.toString() : "");
345:
346: // Set the colors.
347: if (isSelected) {
348: cellPanel.setBackground(list.getSelectionBackground());
349: jarNameLabel.setForeground(list
350: .getSelectionForeground());
351: filterLabel
352: .setForeground(list.getSelectionForeground());
353: } else {
354: cellPanel.setBackground(list.getBackground());
355: jarNameLabel.setForeground(list.getForeground());
356: filterLabel.setForeground(list.getForeground());
357: }
358:
359: // Make the font color red if this is an input file that can't be read.
360: if (!(inputAndOutput && entry.isOutput())
361: && !entry.getFile().canRead()) {
362: jarNameLabel.setForeground(Color.red);
363: }
364:
365: cellPanel.setOpaque(true);
366:
367: return cellPanel;
368: }
369:
370: private StringBuffer appendFilter(StringBuffer filter,
371: String additionalFilter) {
372: if (filter != null) {
373: filter.append(';');
374: }
375:
376: if (additionalFilter != null) {
377: if (filter == null) {
378: filter = new StringBuffer().append('(');
379: }
380:
381: filter.append(additionalFilter);
382: }
383:
384: return filter;
385: }
386: }
387: }
|