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