1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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.classfile.util.ClassUtil; 25 import proguard.gui.splash.*; 26 import proguard.util.ListUtil; 27 28 import javax.swing.*; 29 import javax.swing.border.*; 30 import java.awt.*; 31 import java.awt.event.*; 32 import java.io.*; 33 import java.net.URL; 34 import java.util.*; 35 import java.util.List; 36 import java.lang.reflect.InvocationTargetException; 37 38 39 /** 40 * GUI for configuring and executing ProGuard and ReTrace. 41 * 42 * @author Eric Lafortune 43 */ 44 public class ProGuardGUI extends JFrame 45 { 46 private static final String NO_SPLASH_OPTION = "-nosplash"; 47 48 private static final String TITLE_IMAGE_FILE = "vtitle.png"; 49 private static final String BOILERPLATE_CONFIGURATION = "boilerplate.pro"; 50 private static final String DEFAULT_CONFIGURATION = "default.pro"; 51 52 private static final String OPTIMIZATIONS_DEFAULT = "*"; 53 private static final String KEEP_ATTRIBUTE_DEFAULT = "Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod"; 54 private static final String SOURCE_FILE_ATTRIBUTE_DEFAULT = "SourceFile"; 55 private static final String ADAPT_RESOURCE_FILE_NAMES_DEFAULT = "**.properties"; 56 private static final String ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT = "**.properties,META-INF/MANIFEST.MF"; 57 58 private static final Border BORDER = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); 59 60 static boolean systemOutRedirected; 61 62 private final JFileChooser configurationChooser = new JFileChooser(""); 63 private final JFileChooser fileChooser = new JFileChooser(""); 64 65 private final SplashPanel splashPanel; 66 67 private final ClassPathPanel programPanel = new ClassPathPanel(this, true); 68 private final ClassPathPanel libraryPanel = new ClassPathPanel(this, false); 69 70 private KeepClassSpecification[] boilerplateKeep; 71 private final JCheckBox[] boilerplateKeepCheckBoxes; 72 private final JTextField[] boilerplateKeepTextFields; 73 74 private final KeepSpecificationsPanel additionalKeepPanel = new KeepSpecificationsPanel(this, true, false, false, false, false); 75 76 private KeepClassSpecification[] boilerplateKeepNames; 77 private final JCheckBox[] boilerplateKeepNamesCheckBoxes; 78 private final JTextField[] boilerplateKeepNamesTextFields; 79 80 private final KeepSpecificationsPanel additionalKeepNamesPanel = new KeepSpecificationsPanel(this, true, false, true, false, false); 81 82 private ClassSpecification[] boilerplateNoSideEffectMethods; 83 private final JCheckBox[] boilerplateNoSideEffectMethodCheckBoxes; 84 85 private final ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false); 86 87 private final ClassSpecificationsPanel whyAreYouKeepingPanel = new ClassSpecificationsPanel(this, false); 88 89 private final JCheckBox shrinkCheckBox = new JCheckBox(msg("shrink")); 90 private final JCheckBox printUsageCheckBox = new JCheckBox(msg("printUsage")); 91 92 private final JCheckBox optimizeCheckBox = new JCheckBox(msg("optimize")); 93 private final JCheckBox allowAccessModificationCheckBox = new JCheckBox(msg("allowAccessModification")); 94 private final JCheckBox mergeInterfacesAggressivelyCheckBox = new JCheckBox(msg("mergeInterfacesAggressively")); 95 private final JLabel optimizationsLabel = new JLabel(msg("optimizations")); 96 private final JLabel optimizationPassesLabel = new JLabel(msg("optimizationPasses")); 97 98 private final JSpinner optimizationPassesSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1)); 99 100 private final JCheckBox obfuscateCheckBox = new JCheckBox(msg("obfuscate")); 101 private final JCheckBox printMappingCheckBox = new JCheckBox(msg("printMapping")); 102 private final JCheckBox applyMappingCheckBox = new JCheckBox(msg("applyMapping")); 103 private final JCheckBox obfuscationDictionaryCheckBox = new JCheckBox(msg("obfuscationDictionary")); 104 private final JCheckBox classObfuscationDictionaryCheckBox = new JCheckBox(msg("classObfuscationDictionary")); 105 private final JCheckBox packageObfuscationDictionaryCheckBox = new JCheckBox(msg("packageObfuscationDictionary")); 106 private final JCheckBox overloadAggressivelyCheckBox = new JCheckBox(msg("overloadAggressively")); 107 private final JCheckBox useUniqueClassMemberNamesCheckBox = new JCheckBox(msg("useUniqueClassMemberNames")); 108 private final JCheckBox useMixedCaseClassNamesCheckBox = new JCheckBox(msg("useMixedCaseClassNames")); 109 private final JCheckBox keepPackageNamesCheckBox = new JCheckBox(msg("keepPackageNames")); 110 private final JCheckBox flattenPackageHierarchyCheckBox = new JCheckBox(msg("flattenPackageHierarchy")); 111 private final JCheckBox repackageClassesCheckBox = new JCheckBox(msg("repackageClasses")); 112 private final JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes")); 113 private final JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute")); 114 private final JCheckBox adaptClassStringsCheckBox = new JCheckBox(msg("adaptClassStrings")); 115 private final JCheckBox adaptResourceFileNamesCheckBox = new JCheckBox(msg("adaptResourceFileNames")); 116 private final JCheckBox adaptResourceFileContentsCheckBox = new JCheckBox(msg("adaptResourceFileContents")); 117 118 private final JCheckBox preverifyCheckBox = new JCheckBox(msg("preverify")); 119 private final JCheckBox microEditionCheckBox = new JCheckBox(msg("microEdition")); 120 private final JCheckBox targetCheckBox = new JCheckBox(msg("target")); 121 122 private final JComboBox targetComboBox = new JComboBox(ListUtil.commaSeparatedList(msg("targets")).toArray()); 123 124 private final JCheckBox verboseCheckBox = new JCheckBox(msg("verbose")); 125 private final JCheckBox noteCheckBox = new JCheckBox(msg("note")); 126 private final JCheckBox warnCheckBox = new JCheckBox(msg("warn")); 127 private final JCheckBox ignoreWarningsCheckBox = new JCheckBox(msg("ignoreWarnings")); 128 private final JCheckBox skipNonPublicLibraryClassesCheckBox = new JCheckBox(msg("skipNonPublicLibraryClasses")); 129 private final JCheckBox skipNonPublicLibraryClassMembersCheckBox = new JCheckBox(msg("skipNonPublicLibraryClassMembers")); 130 private final JCheckBox keepDirectoriesCheckBox = new JCheckBox(msg("keepDirectories")); 131 private final JCheckBox forceProcessingCheckBox = new JCheckBox(msg("forceProcessing")); 132 private final JCheckBox printSeedsCheckBox = new JCheckBox(msg("printSeeds")); 133 private final JCheckBox printConfigurationCheckBox = new JCheckBox(msg("printConfiguration")); 134 private final JCheckBox dumpCheckBox = new JCheckBox(msg("dump")); 135 136 private final JTextField printUsageTextField = new JTextField(40); 137 private final JTextField optimizationsTextField = new JTextField(40); 138 private final JTextField printMappingTextField = new JTextField(40); 139 private final JTextField applyMappingTextField = new JTextField(40); 140 private final JTextField obfuscationDictionaryTextField = new JTextField(40); 141 private final JTextField classObfuscationDictionaryTextField = new JTextField(40); 142 private final JTextField packageObfuscationDictionaryTextField = new JTextField(40); 143 private final JTextField keepPackageNamesTextField = new JTextField(40); 144 private final JTextField flattenPackageHierarchyTextField = new JTextField(40); 145 private final JTextField repackageClassesTextField = new JTextField(40); 146 private final JTextField keepAttributesTextField = new JTextField(40); 147 private final JTextField newSourceFileAttributeTextField = new JTextField(40); 148 private final JTextField adaptClassStringsTextField = new JTextField(40); 149 private final JTextField adaptResourceFileNamesTextField = new JTextField(40); 150 private final JTextField adaptResourceFileContentsTextField = new JTextField(40); 151 private final JTextField noteTextField = new JTextField(40); 152 private final JTextField warnTextField = new JTextField(40); 153 private final JTextField keepDirectoriesTextField = new JTextField(40); 154 private final JTextField printSeedsTextField = new JTextField(40); 155 private final JTextField printConfigurationTextField = new JTextField(40); 156 private final JTextField dumpTextField = new JTextField(40); 157 158 private final JTextArea consoleTextArea = new JTextArea(msg("processingInfo"), 3, 40); 159 160 private final JCheckBox reTraceVerboseCheckBox = new JCheckBox(msg("verbose")); 161 private final JTextField reTraceMappingTextField = new JTextField(40); 162 private final JTextArea stackTraceTextArea = new JTextArea(3, 40); 163 private final JTextArea reTraceTextArea = new JTextArea(msg("reTraceInfo"), 3, 40); 164 165 166 /** 167 * Creates a new ProGuardGUI. 168 */ 169 public ProGuardGUI() 170 { 171 setTitle("ProGuard"); 172 setDefaultCloseOperation(EXIT_ON_CLOSE); 173 174 // Create some constraints that can be reused. 175 GridBagConstraints constraints = new GridBagConstraints(); 176 constraints.anchor = GridBagConstraints.WEST; 177 constraints.insets = new Insets(0, 4, 0, 4); 178 179 GridBagConstraints constraintsStretch = new GridBagConstraints(); 180 constraintsStretch.fill = GridBagConstraints.HORIZONTAL; 181 constraintsStretch.weightx = 1.0; 182 constraintsStretch.anchor = GridBagConstraints.WEST; 183 constraintsStretch.insets = constraints.insets; 184 185 GridBagConstraints constraintsLast = new GridBagConstraints(); 186 constraintsLast.gridwidth = GridBagConstraints.REMAINDER; 187 constraintsLast.anchor = GridBagConstraints.WEST; 188 constraintsLast.insets = constraints.insets; 189 190 GridBagConstraints constraintsLastStretch = new GridBagConstraints(); 191 constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; 192 constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; 193 constraintsLastStretch.weightx = 1.0; 194 constraintsLastStretch.anchor = GridBagConstraints.WEST; 195 constraintsLastStretch.insets = constraints.insets; 196 197 GridBagConstraints splashPanelConstraints = new GridBagConstraints(); 198 splashPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; 199 splashPanelConstraints.fill = GridBagConstraints.BOTH; 200 splashPanelConstraints.weightx = 1.0; 201 splashPanelConstraints.weighty = 0.02; 202 splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST; 203 //splashPanelConstraints.insets = constraints.insets; 204 205 GridBagConstraints welcomeTextAreaConstraints = new GridBagConstraints(); 206 welcomeTextAreaConstraints.gridwidth = GridBagConstraints.REMAINDER; 207 welcomeTextAreaConstraints.fill = GridBagConstraints.NONE; 208 welcomeTextAreaConstraints.weightx = 1.0; 209 welcomeTextAreaConstraints.weighty = 0.01; 210 welcomeTextAreaConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST; 211 welcomeTextAreaConstraints.insets = new Insets(20, 40, 20, 40); 212 213 GridBagConstraints panelConstraints = new GridBagConstraints(); 214 panelConstraints.gridwidth = GridBagConstraints.REMAINDER; 215 panelConstraints.fill = GridBagConstraints.HORIZONTAL; 216 panelConstraints.weightx = 1.0; 217 panelConstraints.anchor = GridBagConstraints.NORTHWEST; 218 panelConstraints.insets = constraints.insets; 219 220 GridBagConstraints stretchPanelConstraints = new GridBagConstraints(); 221 stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; 222 stretchPanelConstraints.fill = GridBagConstraints.BOTH; 223 stretchPanelConstraints.weightx = 1.0; 224 stretchPanelConstraints.weighty = 1.0; 225 stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST; 226 stretchPanelConstraints.insets = constraints.insets; 227 228 GridBagConstraints glueConstraints = new GridBagConstraints(); 229 glueConstraints.fill = GridBagConstraints.BOTH; 230 glueConstraints.weightx = 0.01; 231 glueConstraints.weighty = 0.01; 232 glueConstraints.anchor = GridBagConstraints.NORTHWEST; 233 glueConstraints.insets = constraints.insets; 234 235 GridBagConstraints bottomButtonConstraints = new GridBagConstraints(); 236 bottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; 237 bottomButtonConstraints.insets = new Insets(2, 2, 4, 6); 238 bottomButtonConstraints.ipadx = 10; 239 bottomButtonConstraints.ipady = 2; 240 241 GridBagConstraints lastBottomButtonConstraints = new GridBagConstraints(); 242 lastBottomButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; 243 lastBottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; 244 lastBottomButtonConstraints.insets = bottomButtonConstraints.insets; 245 lastBottomButtonConstraints.ipadx = bottomButtonConstraints.ipadx; 246 lastBottomButtonConstraints.ipady = bottomButtonConstraints.ipady; 247 248 // Leave room for a growBox on Mac OS X. 249 if (System.getProperty("os.name").toLowerCase().startsWith("mac os x")) 250 { 251 lastBottomButtonConstraints.insets = new Insets(2, 2, 4, 6 + 16); 252 } 253 254 GridBagLayout layout = new GridBagLayout(); 255 256 configurationChooser.addChoosableFileFilter( 257 new ExtensionFileFilter(msg("proExtension"), new String[] { ".pro" })); 258 259 // Create the opening panel. 260 Sprite splash = 261 new CompositeSprite(new Sprite[] 262 { 263 new ColorSprite(new ConstantColor(Color.gray), 264 new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 90)), 265 new TextSprite(new ConstantString("ProGuard"), 266 new ConstantInt(160), 267 new LinearInt(-10, 120, new SmoothTiming(500, 1000))))), 268 269 new ColorSprite(new ConstantColor(Color.white), 270 new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 45)), 271 new ShadowedSprite(new ConstantInt(3), 272 new ConstantInt(3), 273 new ConstantDouble(0.4), 274 new ConstantInt(1), 275 new CompositeSprite(new Sprite[] 276 { 277 new TextSprite(new ConstantString(msg("shrinking")), 278 new LinearInt(1000, 60, new SmoothTiming(1000, 2000)), 279 new ConstantInt(70)), 280 new TextSprite(new ConstantString(msg("optimization")), 281 new LinearInt(1000, 400, new SmoothTiming(1500, 2500)), 282 new ConstantInt(60)), 283 new TextSprite(new ConstantString(msg("obfuscation")), 284 new LinearInt(1000, 10, new SmoothTiming(2000, 3000)), 285 new ConstantInt(145)), 286 new TextSprite(new ConstantString(msg("preverification")), 287 new LinearInt(1000, 350, new SmoothTiming(2500, 3500)), 288 new ConstantInt(140)), 289 new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 30)), 290 new TextSprite(new TypeWriterString(msg("developed"), new LinearTiming(3500, 5500)), 291 new ConstantInt(250), 292 new ConstantInt(200))), 293 })))), 294 }); 295 splashPanel = new SplashPanel(splash, 0.5, 5500L); 296 splashPanel.setPreferredSize(new Dimension(0, 200)); 297 298 JTextArea welcomeTextArea = new JTextArea(msg("proGuardInfo"), 18, 50); 299 welcomeTextArea.setOpaque(false); 300 welcomeTextArea.setEditable(false); 301 welcomeTextArea.setLineWrap(true); 302 welcomeTextArea.setWrapStyleWord(true); 303 welcomeTextArea.setPreferredSize(new Dimension(0, 0)); 304 welcomeTextArea.setBorder(new EmptyBorder(20, 20, 20, 20)); 305 addBorder(welcomeTextArea, "welcome"); 306 307 JPanel proGuardPanel = new JPanel(layout); 308 proGuardPanel.add(splashPanel, splashPanelConstraints); 309 proGuardPanel.add(welcomeTextArea, welcomeTextAreaConstraints); 310 311 // Create the input panel. 312 // TODO: properly clone the ClassPath objects. 313 // This is awkward to implement in the generic ListPanel.addElements(...) 314 // method, since the Object.clone() method is not public. 315 programPanel.addCopyToPanelButton("moveToLibraries", "moveToLibrariesTip", libraryPanel); 316 libraryPanel.addCopyToPanelButton("moveToProgram", "moveToProgramTip", programPanel); 317 318 // Collect all buttons of these panels and make sure they are equally 319 // sized. 320 List panelButtons = new ArrayList(); 321 panelButtons.addAll(programPanel.getButtons()); 322 panelButtons.addAll(libraryPanel.getButtons()); 323 setCommonPreferredSize(panelButtons); 324 325 addBorder(programPanel, "programJars" ); 326 addBorder(libraryPanel, "libraryJars" ); 327 328 JPanel inputOutputPanel = new JPanel(layout); 329 inputOutputPanel.add(tip(programPanel, "programJarsTip"), stretchPanelConstraints); 330 inputOutputPanel.add(tip(libraryPanel, "libraryJarsTip"), stretchPanelConstraints); 331 332 // Load the boiler plate options. 333 loadBoilerplateConfiguration(); 334 335 // Create the boiler plate keep panels. 336 boilerplateKeepCheckBoxes = new JCheckBox[boilerplateKeep.length]; 337 boilerplateKeepTextFields = new JTextField[boilerplateKeep.length]; 338 339 JButton printUsageBrowseButton = createBrowseButton(printUsageTextField, 340 msg("selectUsageFile")); 341 342 JPanel shrinkingOptionsPanel = new JPanel(layout); 343 addBorder(shrinkingOptionsPanel, "options"); 344 345 shrinkingOptionsPanel.add(tip(shrinkCheckBox, "shrinkTip"), constraintsLastStretch); 346 shrinkingOptionsPanel.add(tip(printUsageCheckBox, "printUsageTip"), constraints); 347 shrinkingOptionsPanel.add(tip(printUsageTextField, "outputFileTip"), constraintsStretch); 348 shrinkingOptionsPanel.add(tip(printUsageBrowseButton, "selectUsageFile"), constraintsLast); 349 350 JPanel shrinkingPanel = new JPanel(layout); 351 352 shrinkingPanel.add(shrinkingOptionsPanel, panelConstraints); 353 addClassSpecifications(extractClassSpecifications(boilerplateKeep), 354 shrinkingPanel, 355 boilerplateKeepCheckBoxes, 356 boilerplateKeepTextFields); 357 358 addBorder(additionalKeepPanel, "keepAdditional"); 359 shrinkingPanel.add(tip(additionalKeepPanel, "keepAdditionalTip"), stretchPanelConstraints); 360 361 // Create the boiler plate keep names panels. 362 boilerplateKeepNamesCheckBoxes = new JCheckBox[boilerplateKeepNames.length]; 363 boilerplateKeepNamesTextFields = new JTextField[boilerplateKeepNames.length]; 364 365 JButton printMappingBrowseButton = createBrowseButton(printMappingTextField, 366 msg("selectPrintMappingFile")); 367 JButton applyMappingBrowseButton = createBrowseButton(applyMappingTextField, 368 msg("selectApplyMappingFile")); 369 JButton obfucationDictionaryBrowseButton = createBrowseButton(obfuscationDictionaryTextField, 370 msg("selectObfuscationDictionaryFile")); 371 JButton classObfucationDictionaryBrowseButton = createBrowseButton(classObfuscationDictionaryTextField, 372 msg("selectObfuscationDictionaryFile")); 373 JButton packageObfucationDictionaryBrowseButton = createBrowseButton(packageObfuscationDictionaryTextField, 374 msg("selectObfuscationDictionaryFile")); 375 376 JPanel obfuscationOptionsPanel = new JPanel(layout); 377 addBorder(obfuscationOptionsPanel, "options"); 378 379 obfuscationOptionsPanel.add(tip(obfuscateCheckBox, "obfuscateTip"), constraintsLastStretch); 380 obfuscationOptionsPanel.add(tip(printMappingCheckBox, "printMappingTip"), constraints); 381 obfuscationOptionsPanel.add(tip(printMappingTextField, "outputFileTip"), constraintsStretch); 382 obfuscationOptionsPanel.add(tip(printMappingBrowseButton, "selectPrintMappingFile"), constraintsLast); 383 obfuscationOptionsPanel.add(tip(applyMappingCheckBox, "applyMappingTip"), constraints); 384 obfuscationOptionsPanel.add(tip(applyMappingTextField, "inputFileTip"), constraintsStretch); 385 obfuscationOptionsPanel.add(tip(applyMappingBrowseButton, "selectApplyMappingFile"), constraintsLast); 386 obfuscationOptionsPanel.add(tip(obfuscationDictionaryCheckBox, "obfuscationDictionaryTip"), constraints); 387 obfuscationOptionsPanel.add(tip(obfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); 388 obfuscationOptionsPanel.add(tip(obfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); 389 obfuscationOptionsPanel.add(tip(classObfuscationDictionaryCheckBox, "classObfuscationDictionaryTip"), constraints); 390 obfuscationOptionsPanel.add(tip(classObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); 391 obfuscationOptionsPanel.add(tip(classObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); 392 obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryCheckBox, "packageObfuscationDictionaryTip"), constraints); 393 obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch); 394 obfuscationOptionsPanel.add(tip(packageObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast); 395 obfuscationOptionsPanel.add(tip(overloadAggressivelyCheckBox, "overloadAggressivelyTip"), constraintsLastStretch); 396 obfuscationOptionsPanel.add(tip(useUniqueClassMemberNamesCheckBox, "useUniqueClassMemberNamesTip"), constraintsLastStretch); 397 obfuscationOptionsPanel.add(tip(useMixedCaseClassNamesCheckBox, "useMixedCaseClassNamesTip"), constraintsLastStretch); 398 obfuscationOptionsPanel.add(tip(keepPackageNamesCheckBox, "keepPackageNamesTip"), constraints); 399 obfuscationOptionsPanel.add(tip(keepPackageNamesTextField, "packageNamesTip"), constraintsLastStretch); 400 obfuscationOptionsPanel.add(tip(flattenPackageHierarchyCheckBox, "flattenPackageHierarchyTip"), constraints); 401 obfuscationOptionsPanel.add(tip(flattenPackageHierarchyTextField, "packageTip"), constraintsLastStretch); 402 obfuscationOptionsPanel.add(tip(repackageClassesCheckBox, "repackageClassesTip"), constraints); 403 obfuscationOptionsPanel.add(tip(repackageClassesTextField, "packageTip"), constraintsLastStretch); 404 obfuscationOptionsPanel.add(tip(keepAttributesCheckBox, "keepAttributesTip"), constraints); 405 obfuscationOptionsPanel.add(tip(keepAttributesTextField, "attributesTip"), constraintsLastStretch); 406 obfuscationOptionsPanel.add(tip(newSourceFileAttributeCheckBox, "renameSourceFileAttributeTip"), constraints); 407 obfuscationOptionsPanel.add(tip(newSourceFileAttributeTextField, "sourceFileAttributeTip"), constraintsLastStretch); 408 obfuscationOptionsPanel.add(tip(adaptClassStringsCheckBox, "adaptClassStringsTip"), constraints); 409 obfuscationOptionsPanel.add(tip(adaptClassStringsTextField, "classNamesTip"), constraintsLastStretch); 410 obfuscationOptionsPanel.add(tip(adaptResourceFileNamesCheckBox, "adaptResourceFileNamesTip"), constraints); 411 obfuscationOptionsPanel.add(tip(adaptResourceFileNamesTextField, "fileNameFilterTip"), constraintsLastStretch); 412 obfuscationOptionsPanel.add(tip(adaptResourceFileContentsCheckBox, "adaptResourceFileContentsTip"), constraints); 413 obfuscationOptionsPanel.add(tip(adaptResourceFileContentsTextField, "fileNameFilterTip"), constraintsLastStretch); 414 415 JPanel obfuscationPanel = new JPanel(layout); 416 417 obfuscationPanel.add(obfuscationOptionsPanel, panelConstraints); 418 addClassSpecifications(extractClassSpecifications(boilerplateKeepNames), 419 obfuscationPanel, 420 boilerplateKeepNamesCheckBoxes, 421 boilerplateKeepNamesTextFields); 422 423 addBorder(additionalKeepNamesPanel, "keepNamesAdditional"); 424 obfuscationPanel.add(tip(additionalKeepNamesPanel, "keepNamesAdditionalTip"), stretchPanelConstraints); 425 426 // Create the boiler plate "no side effect methods" panels. 427 boilerplateNoSideEffectMethodCheckBoxes = new JCheckBox[boilerplateNoSideEffectMethods.length]; 428 429 JPanel optimizationOptionsPanel = new JPanel(layout); 430 addBorder(optimizationOptionsPanel, "options"); 431 432 JButton optimizationsButton = 433 createOptimizationsButton(optimizationsTextField); 434 435 optimizationOptionsPanel.add(tip(optimizeCheckBox, "optimizeTip"), constraintsLastStretch); 436 optimizationOptionsPanel.add(tip(allowAccessModificationCheckBox, "allowAccessModificationTip"), constraintsLastStretch); 437 optimizationOptionsPanel.add(tip(mergeInterfacesAggressivelyCheckBox, "mergeInterfacesAggressivelyTip"), constraintsLastStretch); 438 optimizationOptionsPanel.add(tip(optimizationsLabel, "optimizationsTip"), constraints); 439 optimizationOptionsPanel.add(tip(optimizationsTextField, "optimizationsFilterTip"), constraintsStretch); 440 optimizationOptionsPanel.add(tip(optimizationsButton, "optimizationsSelectTip"), constraintsLast); 441 optimizationOptionsPanel.add(tip(optimizationPassesLabel, "optimizationPassesTip"), constraints); 442 optimizationOptionsPanel.add(tip(optimizationPassesSpinner, "optimizationPassesTip"), constraintsLast); 443 444 JPanel optimizationPanel = new JPanel(layout); 445 446 optimizationPanel.add(optimizationOptionsPanel, panelConstraints); 447 addClassSpecifications(boilerplateNoSideEffectMethods, 448 optimizationPanel, 449 boilerplateNoSideEffectMethodCheckBoxes, 450 null); 451 452 addBorder(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditional"); 453 optimizationPanel.add(tip(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditionalTip"), stretchPanelConstraints); 454 455 // Create the options panel. 456 JPanel preverificationOptionsPanel = new JPanel(layout); 457 addBorder(preverificationOptionsPanel, "preverificationAndTargeting"); 458 459 preverificationOptionsPanel.add(tip(preverifyCheckBox, "preverifyTip"), constraintsLastStretch); 460 preverificationOptionsPanel.add(tip(microEditionCheckBox, "microEditionTip"), constraintsLastStretch); 461 preverificationOptionsPanel.add(tip(targetCheckBox, "targetTip"), constraints); 462 preverificationOptionsPanel.add(tip(targetComboBox, "targetTip"), constraintsLast); 463 464 JButton printSeedsBrowseButton = 465 createBrowseButton(printSeedsTextField, msg("selectSeedsFile")); 466 467 JButton printConfigurationBrowseButton = 468 createBrowseButton(printConfigurationTextField, msg( "selectConfigurationFile")); 469 470 JButton dumpBrowseButton = 471 createBrowseButton(dumpTextField, msg("selectDumpFile")); 472 473 // Select the most recent target by default. 474 targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1); 475 476 JPanel consistencyPanel = new JPanel(layout); 477 addBorder(consistencyPanel, "consistencyAndCorrectness"); 478 479 consistencyPanel.add(tip(verboseCheckBox, "verboseTip"), constraintsLastStretch); 480 consistencyPanel.add(tip(noteCheckBox, "noteTip"), constraints); 481 consistencyPanel.add(tip(noteTextField, "noteFilterTip"), constraintsLastStretch); 482 consistencyPanel.add(tip(warnCheckBox, "warnTip"), constraints); 483 consistencyPanel.add(tip(warnTextField, "warnFilterTip"), constraintsLastStretch); 484 consistencyPanel.add(tip(ignoreWarningsCheckBox, "ignoreWarningsTip"), constraintsLastStretch); 485 consistencyPanel.add(tip(skipNonPublicLibraryClassesCheckBox, "skipNonPublicLibraryClassesTip"), constraintsLastStretch); 486 consistencyPanel.add(tip(skipNonPublicLibraryClassMembersCheckBox, "skipNonPublicLibraryClassMembersTip"), constraintsLastStretch); 487 consistencyPanel.add(tip(keepDirectoriesCheckBox, "keepDirectoriesTip"), constraints); 488 consistencyPanel.add(tip(keepDirectoriesTextField, "directoriesTip"), constraintsLastStretch); 489 consistencyPanel.add(tip(forceProcessingCheckBox, "forceProcessingTip"), constraintsLastStretch); 490 consistencyPanel.add(tip(printSeedsCheckBox, "printSeedsTip"), constraints); 491 consistencyPanel.add(tip(printSeedsTextField, "outputFileTip"), constraintsStretch); 492 consistencyPanel.add(tip(printSeedsBrowseButton, "selectSeedsFile"), constraintsLast); 493 consistencyPanel.add(tip(printConfigurationCheckBox, "printConfigurationTip"), constraints); 494 consistencyPanel.add(tip(printConfigurationTextField, "outputFileTip"), constraintsStretch); 495 consistencyPanel.add(tip(printConfigurationBrowseButton, "selectConfigurationFile"), constraintsLast); 496 consistencyPanel.add(tip(dumpCheckBox, "dumpTip"), constraints); 497 consistencyPanel.add(tip(dumpTextField, "outputFileTip"), constraintsStretch); 498 consistencyPanel.add(tip(dumpBrowseButton, "selectDumpFile"), constraintsLast); 499 500 // Collect all components that are followed by text fields and make 501 // sure they are equally sized. That way the text fields start at the 502 // same horizontal position. 503 setCommonPreferredSize(Arrays.asList(new JComponent[] { 504 printMappingCheckBox, 505 applyMappingCheckBox, 506 flattenPackageHierarchyCheckBox, 507 repackageClassesCheckBox, 508 newSourceFileAttributeCheckBox, 509 })); 510 511 JPanel optionsPanel = new JPanel(layout); 512 513 optionsPanel.add(preverificationOptionsPanel, panelConstraints); 514 optionsPanel.add(consistencyPanel, panelConstraints); 515 516 addBorder(whyAreYouKeepingPanel, "whyAreYouKeeping"); 517 optionsPanel.add(tip(whyAreYouKeepingPanel, "whyAreYouKeepingTip"), stretchPanelConstraints); 518 519 // Create the process panel. 520 consoleTextArea.setOpaque(false); 521 consoleTextArea.setEditable(false); 522 consoleTextArea.setLineWrap(false); 523 consoleTextArea.setWrapStyleWord(false); 524 JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea); 525 consoleScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1)); 526 addBorder(consoleScrollPane, "processingConsole"); 527 528 JPanel processPanel = new JPanel(layout); 529 processPanel.add(consoleScrollPane, stretchPanelConstraints); 530 531 // Create the load, save, and process buttons. 532 JButton loadButton = new JButton(msg("loadConfiguration")); 533 loadButton.addActionListener(new MyLoadConfigurationActionListener()); 534 535 JButton viewButton = new JButton(msg("viewConfiguration")); 536 viewButton.addActionListener(new MyViewConfigurationActionListener()); 537 538 JButton saveButton = new JButton(msg("saveConfiguration")); 539 saveButton.addActionListener(new MySaveConfigurationActionListener()); 540 541 JButton processButton = new JButton(msg("process")); 542 processButton.addActionListener(new MyProcessActionListener()); 543 544 // Create the ReTrace panel. 545 JPanel reTraceSettingsPanel = new JPanel(layout); 546 addBorder(reTraceSettingsPanel, "reTraceSettings"); 547 548 JButton reTraceMappingBrowseButton = createBrowseButton(reTraceMappingTextField, 549 msg("selectApplyMappingFile")); 550 551 JLabel reTraceMappingLabel = new JLabel(msg("mappingFile")); 552 reTraceMappingLabel.setForeground(reTraceVerboseCheckBox.getForeground()); 553 554 reTraceSettingsPanel.add(tip(reTraceVerboseCheckBox, "verboseTip"), constraintsLastStretch); 555 reTraceSettingsPanel.add(tip(reTraceMappingLabel, "mappingFileTip"), constraints); 556 reTraceSettingsPanel.add(tip(reTraceMappingTextField, "inputFileTip"), constraintsStretch); 557 reTraceSettingsPanel.add(tip(reTraceMappingBrowseButton, "selectApplyMappingFile"), constraintsLast); 558 559 stackTraceTextArea.setOpaque(true); 560 stackTraceTextArea.setEditable(true); 561 stackTraceTextArea.setLineWrap(false); 562 stackTraceTextArea.setWrapStyleWord(true); 563 JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceTextArea); 564 addBorder(stackTraceScrollPane, "obfuscatedStackTrace"); 565 566 reTraceTextArea.setOpaque(false); 567 reTraceTextArea.setEditable(false); 568 reTraceTextArea.setLineWrap(true); 569 reTraceTextArea.setWrapStyleWord(true); 570 JScrollPane reTraceScrollPane = new JScrollPane(reTraceTextArea); 571 reTraceScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1)); 572 addBorder(reTraceScrollPane, "deobfuscatedStackTrace"); 573 574 JPanel reTracePanel = new JPanel(layout); 575 reTracePanel.add(reTraceSettingsPanel, panelConstraints); 576 reTracePanel.add(tip(stackTraceScrollPane, "obfuscatedStackTraceTip"), panelConstraints); 577 reTracePanel.add(reTraceScrollPane, stretchPanelConstraints); 578 579 // Create the load button. 580 JButton loadStackTraceButton = new JButton(msg("loadStackTrace")); 581 loadStackTraceButton.addActionListener(new MyLoadStackTraceActionListener()); 582 583 JButton reTraceButton = new JButton(msg("reTrace")); 584 reTraceButton.addActionListener(new MyReTraceActionListener()); 585 586 // Create the main tabbed pane. 587 TabbedPane tabs = new TabbedPane(); 588 tabs.add(msg("proGuardTab"), proGuardPanel); 589 tabs.add(msg("inputOutputTab"), inputOutputPanel); 590 tabs.add(msg("shrinkingTab"), shrinkingPanel); 591 tabs.add(msg("obfuscationTab"), obfuscationPanel); 592 tabs.add(msg("optimizationTab"), optimizationPanel); 593 tabs.add(msg("informationTab"), optionsPanel); 594 tabs.add(msg("processTab"), processPanel); 595 tabs.add(msg("reTraceTab"), reTracePanel); 596 tabs.addImage(Toolkit.getDefaultToolkit().getImage( 597 this.getClass().getResource(TITLE_IMAGE_FILE))); 598 599 // Add the bottom buttons to each panel. 600 proGuardPanel .add(Box.createGlue(), glueConstraints); 601 proGuardPanel .add(tip(loadButton, "loadConfigurationTip"), bottomButtonConstraints); 602 proGuardPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 603 604 inputOutputPanel .add(Box.createGlue(), glueConstraints); 605 inputOutputPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 606 inputOutputPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 607 608 shrinkingPanel .add(Box.createGlue(), glueConstraints); 609 shrinkingPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 610 shrinkingPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 611 612 obfuscationPanel .add(Box.createGlue(), glueConstraints); 613 obfuscationPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 614 obfuscationPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 615 616 optimizationPanel .add(Box.createGlue(), glueConstraints); 617 optimizationPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 618 optimizationPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 619 620 optionsPanel .add(Box.createGlue(), glueConstraints); 621 optionsPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 622 optionsPanel .add(createNextButton(tabs), lastBottomButtonConstraints); 623 624 processPanel .add(Box.createGlue(), glueConstraints); 625 processPanel .add(createPreviousButton(tabs), bottomButtonConstraints); 626 processPanel .add(tip(viewButton, "viewConfigurationTip"), bottomButtonConstraints); 627 processPanel .add(tip(saveButton, "saveConfigurationTip"), bottomButtonConstraints); 628 processPanel .add(tip(processButton, "processTip"), lastBottomButtonConstraints); 629 630 reTracePanel .add(Box.createGlue(), glueConstraints); 631 reTracePanel .add(tip(loadStackTraceButton, "loadStackTraceTip"), bottomButtonConstraints); 632 reTracePanel .add(tip(reTraceButton, "reTraceTip"), lastBottomButtonConstraints); 633 634 // Initialize the GUI settings to reasonable defaults. 635 loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION)); 636 637 // Add the main tabs to the frame and pack it. 638 getContentPane().add(tabs); 639 } 640 641 642 public void startSplash() 643 { 644 splashPanel.start(); 645 } 646 647 648 public void skipSplash() 649 { 650 splashPanel.stop(); 651 } 652 653 654 /** 655 * Loads the boilerplate keep class options from the boilerplate file 656 * into the boilerplate array. 657 */ 658 private void loadBoilerplateConfiguration() 659 { 660 try 661 { 662 // Parse the boilerplate configuration file. 663 ConfigurationParser parser = new ConfigurationParser( 664 this.getClass().getResource(BOILERPLATE_CONFIGURATION)); 665 Configuration configuration = new Configuration(); 666 667 try 668 { 669 parser.parse(configuration); 670 671 // We're interested in the keep options. 672 boilerplateKeep = 673 extractKeepSpecifications(configuration.keep, false, false); 674 675 // We're interested in the keep options. 676 boilerplateKeepNames = 677 extractKeepSpecifications(configuration.keep, true, false); 678 679 // We're interested in the side effects options. 680 boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()]; 681 configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods); 682 } 683 finally 684 { 685 parser.close(); 686 } 687 } 688 catch (Exception ex) 689 { 690 ex.printStackTrace(); 691 } 692 } 693 694 695 /** 696 * Returns an array containing the ClassSpecifications instances with 697 * matching flags. 698 */ 699 private KeepClassSpecification[] extractKeepSpecifications(List keepSpecifications, 700 boolean allowShrinking, 701 boolean allowObfuscation) 702 { 703 List matches = new ArrayList(); 704 705 for (int index = 0; index < keepSpecifications.size(); index++) 706 { 707 KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepSpecifications.get(index); 708 if (keepClassSpecification.allowShrinking == allowShrinking && 709 keepClassSpecification.allowObfuscation == allowObfuscation) 710 { 711 matches.add(keepClassSpecification); 712 } 713 } 714 715 KeepClassSpecification[] matchingKeepClassSpecifications = new KeepClassSpecification[matches.size()]; 716 matches.toArray(matchingKeepClassSpecifications); 717 718 return matchingKeepClassSpecifications; 719 } 720 721 722 /** 723 * Returns an array containing the ClassSpecification instances of the 724 * given array of KeepClassSpecification instances. 725 */ 726 private ClassSpecification[] extractClassSpecifications(KeepClassSpecification[] keepClassSpecifications) 727 { 728 ClassSpecification[] classSpecifications = new ClassSpecification[keepClassSpecifications.length]; 729 730 for (int index = 0; index < classSpecifications.length; index++) 731 { 732 classSpecifications[index] = keepClassSpecifications[index]; 733 } 734 735 return classSpecifications; 736 } 737 738 739 /** 740 * Creates a panel with the given boiler plate class specifications. 741 */ 742 private void addClassSpecifications(ClassSpecification[] boilerplateClassSpecifications, 743 JPanel classSpecificationsPanel, 744 JCheckBox[] boilerplateCheckBoxes, 745 JTextField[] boilerplateTextFields) 746 { 747 // Create some constraints that can be reused. 748 GridBagConstraints constraints = new GridBagConstraints(); 749 constraints.anchor = GridBagConstraints.WEST; 750 constraints.insets = new Insets(0, 4, 0, 4); 751 752 GridBagConstraints constraintsLastStretch = new GridBagConstraints(); 753 constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; 754 constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; 755 constraintsLastStretch.weightx = 1.0; 756 constraintsLastStretch.anchor = GridBagConstraints.WEST; 757 constraintsLastStretch.insets = constraints.insets; 758 759 GridBagConstraints panelConstraints = new GridBagConstraints(); 760 panelConstraints.gridwidth = GridBagConstraints.REMAINDER; 761 panelConstraints.fill = GridBagConstraints.HORIZONTAL; 762 panelConstraints.weightx = 1.0; 763 panelConstraints.anchor = GridBagConstraints.NORTHWEST; 764 panelConstraints.insets = constraints.insets; 765 766 GridBagLayout layout = new GridBagLayout(); 767 768 String lastPanelName = null; 769 JPanel keepSubpanel = null; 770 for (int index = 0; index < boilerplateClassSpecifications.length; index++) 771 { 772 // The panel structure is derived from the comments. 773 String comments = boilerplateClassSpecifications[index].comments; 774 int dashIndex = comments.indexOf('-'); 775 int periodIndex = comments.indexOf('.', dashIndex); 776 String panelName = comments.substring(0, dashIndex).trim(); 777 String optionName = comments.substring(dashIndex + 1, periodIndex).replace('_', '.').trim(); 778 String toolTip = comments.substring(periodIndex + 1); 779 if (keepSubpanel == null || !panelName.equals(lastPanelName)) 780 { 781 // Create a new keep subpanel and add it. 782 keepSubpanel = new JPanel(layout); 783 keepSubpanel.setBorder(BorderFactory.createTitledBorder(BORDER, panelName)); 784 classSpecificationsPanel.add(keepSubpanel, panelConstraints); 785 786 lastPanelName = panelName; 787 } 788 789 // Add the check box to the subpanel. 790 JCheckBox boilerplateCheckBox = new JCheckBox(optionName); 791 boilerplateCheckBox.setToolTipText(toolTip); 792 boilerplateCheckBoxes[index] = boilerplateCheckBox; 793 keepSubpanel.add(boilerplateCheckBox, 794 boilerplateTextFields != null ? 795 constraints : 796 constraintsLastStretch); 797 798 if (boilerplateTextFields != null) 799 { 800 // Add the text field to the subpanel. 801 boilerplateTextFields[index] = new JTextField(40); 802 keepSubpanel.add(tip(boilerplateTextFields[index], "classNamesTip"), constraintsLastStretch); 803 } 804 } 805 } 806 807 808 /** 809 * Adds a standard border with the title that corresponds to the given key 810 * in the GUI resources. 811 */ 812 private void addBorder(JComponent component, String titleKey) 813 { 814 Border oldBorder = component.getBorder(); 815 Border newBorder = BorderFactory.createTitledBorder(BORDER, msg(titleKey)); 816 817 component.setBorder(oldBorder == null ? 818 newBorder : 819 new CompoundBorder(newBorder, oldBorder)); 820 } 821 822 823 /** 824 * Creates a Previous button for the given tabbed pane. 825 */ 826 private JButton createPreviousButton(final TabbedPane tabbedPane) 827 { 828 JButton browseButton = new JButton(msg("previous")); 829 browseButton.addActionListener(new ActionListener() 830 { 831 public void actionPerformed(ActionEvent e) 832 { 833 tabbedPane.previous(); 834 } 835 }); 836 837 return browseButton; 838 } 839 840 841 /** 842 * Creates a Next button for the given tabbed pane. 843 */ 844 private JButton createNextButton(final TabbedPane tabbedPane) 845 { 846 JButton browseButton = new JButton(msg("next")); 847 browseButton.addActionListener(new ActionListener() 848 { 849 public void actionPerformed(ActionEvent e) 850 { 851 tabbedPane.next(); 852 } 853 }); 854 855 return browseButton; 856 } 857 858 859 /** 860 * Creates a browse button that opens a file browser for the given text field. 861 */ 862 private JButton createBrowseButton(final JTextField textField, 863 final String title) 864 { 865 JButton browseButton = new JButton(msg("browse")); 866 browseButton.addActionListener(new ActionListener() 867 { 868 public void actionPerformed(ActionEvent e) 869 { 870 // Update the file chooser. 871 fileChooser.setDialogTitle(title); 872 fileChooser.setSelectedFile(new File(textField.getText())); 873 874 int returnVal = fileChooser.showDialog(ProGuardGUI.this, msg("ok")); 875 if (returnVal == JFileChooser.APPROVE_OPTION) 876 { 877 // Update the text field. 878 textField.setText(fileChooser.getSelectedFile().getPath()); 879 } 880 } 881 }); 882 883 return browseButton; 884 } 885 886 887 protected JButton createOptimizationsButton(final JTextField textField) 888 { 889 final OptimizationsDialog optimizationsDialog = new OptimizationsDialog(ProGuardGUI.this); 890 891 JButton optimizationsButton = new JButton(msg("select")); 892 optimizationsButton.addActionListener(new ActionListener() 893 { 894 public void actionPerformed(ActionEvent e) 895 { 896 // Update the dialog. 897 optimizationsDialog.setFilter(textField.getText()); 898 899 int returnValue = optimizationsDialog.showDialog(); 900 if (returnValue == OptimizationsDialog.APPROVE_OPTION) 901 { 902 // Update the text field. 903 textField.setText(optimizationsDialog.getFilter()); 904 } 905 } 906 }); 907 908 return optimizationsButton; 909 } 910 911 912 /** 913 * Sets the preferred sizes of the given components to the maximum of their 914 * current preferred sizes. 915 */ 916 private void setCommonPreferredSize(List components) 917 { 918 // Find the maximum preferred size. 919 Dimension maximumSize = null; 920 for (int index = 0; index < components.size(); index++) 921 { 922 JComponent component = (JComponent)components.get(index); 923 Dimension size = component.getPreferredSize(); 924 if (maximumSize == null || 925 size.getWidth() > maximumSize.getWidth()) 926 { 927 maximumSize = size; 928 } 929 } 930 931 // Set the size that we found as the preferred size for all components. 932 for (int index = 0; index < components.size(); index++) 933 { 934 JComponent component = (JComponent)components.get(index); 935 component.setPreferredSize(maximumSize); 936 } 937 } 938 939 940 /** 941 * Updates to GUI settings to reflect the given ProGuard configuration. 942 */ 943 private void setProGuardConfiguration(Configuration configuration) 944 { 945 // Set up the input and output jars and directories. 946 programPanel.setClassPath(configuration.programJars); 947 libraryPanel.setClassPath(configuration.libraryJars); 948 949 // Set up the boilerplate keep options. 950 for (int index = 0; index < boilerplateKeep.length; index++) 951 { 952 String classNames = 953 findMatchingKeepSpecifications(boilerplateKeep[index], 954 configuration.keep); 955 956 boilerplateKeepCheckBoxes[index].setSelected(classNames != null); 957 boilerplateKeepTextFields[index].setText(classNames == null ? "*" : classNames); 958 } 959 960 961 // Set up the boilerplate keep names options. 962 for (int index = 0; index < boilerplateKeepNames.length; index++) 963 { 964 String classNames = 965 findMatchingKeepSpecifications(boilerplateKeepNames[index], 966 configuration.keep); 967 968 boilerplateKeepNamesCheckBoxes[index].setSelected(classNames != null); 969 boilerplateKeepNamesTextFields[index].setText(classNames == null ? "*" : classNames); 970 } 971 972 // Set up the additional keep options. Note that the matched boilerplate 973 // options have been removed from the list. 974 additionalKeepPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep, 975 false)); 976 977 // Set up the additional keep options. Note that the matched boilerplate 978 // options have been removed from the list. 979 additionalKeepNamesPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep, 980 true)); 981 982 983 // Set up the boilerplate "no side effect methods" options. 984 for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++) 985 { 986 boolean found = 987 findClassSpecification(boilerplateNoSideEffectMethods[index], 988 configuration.assumeNoSideEffects); 989 990 boilerplateNoSideEffectMethodCheckBoxes[index].setSelected(found); 991 } 992 993 // Set up the additional keep options. Note that the matched boilerplate 994 // options have been removed from the list. 995 additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects); 996 997 // Set up the "why are you keeping" options. 998 whyAreYouKeepingPanel.setClassSpecifications(configuration.whyAreYouKeeping); 999 1000 // Set up the other options. 1001 shrinkCheckBox .setSelected(configuration.shrink); 1002 printUsageCheckBox .setSelected(configuration.printUsage != null); 1003 1004 optimizeCheckBox .setSelected(configuration.optimize); 1005 allowAccessModificationCheckBox .setSelected(configuration.allowAccessModification); 1006 mergeInterfacesAggressivelyCheckBox .setSelected(configuration.mergeInterfacesAggressively); 1007 optimizationPassesSpinner.getModel() .setValue(new Integer(configuration.optimizationPasses)); 1008 1009 obfuscateCheckBox .setSelected(configuration.obfuscate); 1010 printMappingCheckBox .setSelected(configuration.printMapping != null); 1011 applyMappingCheckBox .setSelected(configuration.applyMapping != null); 1012 obfuscationDictionaryCheckBox .setSelected(configuration.obfuscationDictionary != null); 1013 classObfuscationDictionaryCheckBox .setSelected(configuration.classObfuscationDictionary != null); 1014 packageObfuscationDictionaryCheckBox .setSelected(configuration.packageObfuscationDictionary != null); 1015 overloadAggressivelyCheckBox .setSelected(configuration.overloadAggressively); 1016 useUniqueClassMemberNamesCheckBox .setSelected(configuration.useUniqueClassMemberNames); 1017 useMixedCaseClassNamesCheckBox .setSelected(configuration.useMixedCaseClassNames); 1018 keepPackageNamesCheckBox .setSelected(configuration.keepPackageNames != null); 1019 flattenPackageHierarchyCheckBox .setSelected(configuration.flattenPackageHierarchy != null); 1020 repackageClassesCheckBox .setSelected(configuration.repackageClasses != null); 1021 keepAttributesCheckBox .setSelected(configuration.keepAttributes != null); 1022 newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null); 1023 adaptClassStringsCheckBox .setSelected(configuration.adaptClassStrings != null); 1024 adaptResourceFileNamesCheckBox .setSelected(configuration.adaptResourceFileNames != null); 1025 adaptResourceFileContentsCheckBox .setSelected(configuration.adaptResourceFileContents != null); 1026 1027 preverifyCheckBox .setSelected(configuration.preverify); 1028 microEditionCheckBox .setSelected(configuration.microEdition); 1029 targetCheckBox .setSelected(configuration.targetClassVersion != 0); 1030 1031 verboseCheckBox .setSelected(configuration.verbose); 1032 noteCheckBox .setSelected(configuration.note == null || !configuration.note.isEmpty()); 1033 warnCheckBox .setSelected(configuration.warn == null || !configuration.warn.isEmpty()); 1034 ignoreWarningsCheckBox .setSelected(configuration.ignoreWarnings); 1035 skipNonPublicLibraryClassesCheckBox .setSelected(configuration.skipNonPublicLibraryClasses); 1036 skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers); 1037 keepDirectoriesCheckBox .setSelected(configuration.keepDirectories != null); 1038 forceProcessingCheckBox .setSelected(configuration.lastModified == Long.MAX_VALUE); 1039 printSeedsCheckBox .setSelected(configuration.printSeeds != null); 1040 printConfigurationCheckBox .setSelected(configuration.printConfiguration != null); 1041 dumpCheckBox .setSelected(configuration.dump != null); 1042 1043 printUsageTextField .setText(fileName(configuration.printUsage)); 1044 optimizationsTextField .setText(configuration.optimizations == null ? OPTIMIZATIONS_DEFAULT : ListUtil.commaSeparatedString(configuration.optimizations)); 1045 printMappingTextField .setText(fileName(configuration.printMapping)); 1046 applyMappingTextField .setText(fileName(configuration.applyMapping)); 1047 obfuscationDictionaryTextField .setText(fileName(configuration.obfuscationDictionary)); 1048 keepPackageNamesTextField .setText(configuration.keepPackageNames == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.keepPackageNames))); 1049 flattenPackageHierarchyTextField .setText(configuration.flattenPackageHierarchy); 1050 repackageClassesTextField .setText(configuration.repackageClasses); 1051 keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes)); 1052 newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute); 1053 adaptClassStringsTextField .setText(configuration.adaptClassStrings == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.adaptClassStrings))); 1054 adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames)); 1055 adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents)); 1056 noteTextField .setText(ListUtil.commaSeparatedString(configuration.note)); 1057 warnTextField .setText(ListUtil.commaSeparatedString(configuration.warn)); 1058 keepDirectoriesTextField .setText(ListUtil.commaSeparatedString(configuration.keepDirectories)); 1059 printSeedsTextField .setText(fileName(configuration.printSeeds)); 1060 printConfigurationTextField .setText(fileName(configuration.printConfiguration)); 1061 dumpTextField .setText(fileName(configuration.dump)); 1062 1063 if (configuration.targetClassVersion != 0) 1064 { 1065 targetComboBox.setSelectedItem(ClassUtil.externalClassVersion(configuration.targetClassVersion)); 1066 } 1067 else 1068 { 1069 targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1); 1070 } 1071 1072 if (configuration.printMapping != null) 1073 { 1074 reTraceMappingTextField.setText(fileName(configuration.printMapping)); 1075 } 1076 } 1077 1078 1079 /** 1080 * Returns the ProGuard configuration that reflects the current GUI settings. 1081 */ 1082 private Configuration getProGuardConfiguration() 1083 { 1084 Configuration configuration = new Configuration(); 1085 1086 // Get the input and output jars and directories. 1087 configuration.programJars = programPanel.getClassPath(); 1088 configuration.libraryJars = libraryPanel.getClassPath(); 1089 1090 List keep = new ArrayList(); 1091 1092 // Collect the additional keep options. 1093 List additionalKeep = additionalKeepPanel.getClassSpecifications(); 1094 if (additionalKeep != null) 1095 { 1096 keep.addAll(additionalKeep); 1097 } 1098 1099 // Collect the additional keep names options. 1100 List additionalKeepNames = additionalKeepNamesPanel.getClassSpecifications(); 1101 if (additionalKeepNames != null) 1102 { 1103 keep.addAll(additionalKeepNames); 1104 } 1105 1106 // Collect the boilerplate keep options. 1107 for (int index = 0; index < boilerplateKeep.length; index++) 1108 { 1109 if (boilerplateKeepCheckBoxes[index].isSelected()) 1110 { 1111 keep.add(classSpecification(boilerplateKeep[index], 1112 boilerplateKeepTextFields[index].getText())); 1113 } 1114 } 1115 1116 // Collect the boilerplate keep names options. 1117 for (int index = 0; index < boilerplateKeepNames.length; index++) 1118 { 1119 if (boilerplateKeepNamesCheckBoxes[index].isSelected()) 1120 { 1121 keep.add(classSpecification(boilerplateKeepNames[index], 1122 boilerplateKeepNamesTextFields[index].getText())); 1123 } 1124 } 1125 1126 // Put the list of keep specifications in the configuration. 1127 if (keep.size() > 0) 1128 { 1129 configuration.keep = keep; 1130 } 1131 1132 1133 // Collect the boilerplate "no side effect methods" options. 1134 List noSideEffectMethods = new ArrayList(); 1135 1136 for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++) 1137 { 1138 if (boilerplateNoSideEffectMethodCheckBoxes[index].isSelected()) 1139 { 1140 noSideEffectMethods.add(boilerplateNoSideEffectMethods[index]); 1141 } 1142 } 1143 1144 // Collect the additional "no side effect methods" options. 1145 List additionalNoSideEffectOptions = additionalNoSideEffectsPanel.getClassSpecifications(); 1146 if (additionalNoSideEffectOptions != null) 1147 { 1148 noSideEffectMethods.addAll(additionalNoSideEffectOptions); 1149 } 1150 1151 // Put the list of "no side effect methods" options in the configuration. 1152 if (noSideEffectMethods.size() > 0) 1153 { 1154 configuration.assumeNoSideEffects = noSideEffectMethods; 1155 } 1156 1157 1158 // Collect the "why are you keeping" options. 1159 configuration.whyAreYouKeeping = whyAreYouKeepingPanel.getClassSpecifications(); 1160 1161 1162 // Get the other options. 1163 configuration.shrink = shrinkCheckBox .isSelected(); 1164 configuration.printUsage = printUsageCheckBox .isSelected() ? new File(printUsageTextField .getText()) : null; 1165 1166 configuration.optimize = optimizeCheckBox .isSelected(); 1167 configuration.allowAccessModification = allowAccessModificationCheckBox .isSelected(); 1168 configuration.mergeInterfacesAggressively = mergeInterfacesAggressivelyCheckBox .isSelected(); 1169 configuration.optimizations = optimizationsTextField.getText().length() > 1 ? ListUtil.commaSeparatedList(optimizationsTextField .getText()) : null; 1170 configuration.optimizationPasses = ((SpinnerNumberModel)optimizationPassesSpinner.getModel()).getNumber().intValue(); 1171 1172 configuration.obfuscate = obfuscateCheckBox .isSelected(); 1173 configuration.printMapping = printMappingCheckBox .isSelected() ? new File(printMappingTextField .getText()) : null; 1174 configuration.applyMapping = applyMappingCheckBox .isSelected() ? new File(applyMappingTextField .getText()) : null; 1175 configuration.obfuscationDictionary = obfuscationDictionaryCheckBox .isSelected() ? new File(obfuscationDictionaryTextField .getText()) : null; 1176 configuration.classObfuscationDictionary = classObfuscationDictionaryCheckBox .isSelected() ? new File(classObfuscationDictionaryTextField .getText()) : null; 1177 configuration.packageObfuscationDictionary = packageObfuscationDictionaryCheckBox .isSelected() ? new File(packageObfuscationDictionaryTextField .getText()) : null; 1178 configuration.overloadAggressively = overloadAggressivelyCheckBox .isSelected(); 1179 configuration.useUniqueClassMemberNames = useUniqueClassMemberNamesCheckBox .isSelected(); 1180 configuration.useMixedCaseClassNames = useMixedCaseClassNamesCheckBox .isSelected(); 1181 configuration.keepPackageNames = keepPackageNamesCheckBox .isSelected() ? keepPackageNamesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepPackageNamesTextField.getText())) : new ArrayList() : null; 1182 configuration.flattenPackageHierarchy = flattenPackageHierarchyCheckBox .isSelected() ? ClassUtil.internalClassName(flattenPackageHierarchyTextField .getText()) : null; 1183 configuration.repackageClasses = repackageClassesCheckBox .isSelected() ? ClassUtil.internalClassName(repackageClassesTextField .getText()) : null; 1184 configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField .getText()) : null; 1185 configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null; 1186 configuration.adaptClassStrings = adaptClassStringsCheckBox .isSelected() ? adaptClassStringsTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(adaptClassStringsTextField.getText())) : new ArrayList() : null; 1187 configuration.adaptResourceFileNames = adaptResourceFileNamesCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileNamesTextField .getText()) : null; 1188 configuration.adaptResourceFileContents = adaptResourceFileContentsCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileContentsTextField .getText()) : null; 1189 1190 configuration.preverify = preverifyCheckBox .isSelected(); 1191 configuration.microEdition = microEditionCheckBox .isSelected(); 1192 configuration.targetClassVersion = targetCheckBox .isSelected() ? ClassUtil.internalClassVersion(targetComboBox.getSelectedItem().toString()) : 0; 1193 1194 configuration.verbose = verboseCheckBox .isSelected(); 1195 configuration.note = noteCheckBox .isSelected() ? noteTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(noteTextField.getText())) : null : new ArrayList(); 1196 configuration.warn = warnCheckBox .isSelected() ? warnTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(warnTextField.getText())) : null : new ArrayList(); 1197 configuration.ignoreWarnings = ignoreWarningsCheckBox .isSelected(); 1198 configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClassesCheckBox .isSelected(); 1199 configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembersCheckBox.isSelected(); 1200 configuration.keepDirectories = keepDirectoriesCheckBox .isSelected() ? keepDirectoriesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepDirectoriesTextField.getText())) : new ArrayList() : null; 1201 configuration.lastModified = forceProcessingCheckBox .isSelected() ? Long.MAX_VALUE : System.currentTimeMillis(); 1202 configuration.printSeeds = printSeedsCheckBox .isSelected() ? new File(printSeedsTextField .getText()) : null; 1203 configuration.printConfiguration = printConfigurationCheckBox .isSelected() ? new File(printConfigurationTextField .getText()) : null; 1204 configuration.dump = dumpCheckBox .isSelected() ? new File(dumpTextField .getText()) : null; 1205 1206 return configuration; 1207 } 1208 1209 1210 /** 1211 * Looks in the given list for a class specification that is identical to 1212 * the given template. Returns true if it is found, and removes the matching 1213 * class specification as a side effect. 1214 */ 1215 private boolean findClassSpecification(ClassSpecification classSpecificationTemplate, 1216 List classSpecifications) 1217 { 1218 if (classSpecifications == null) 1219 { 1220 return false; 1221 } 1222 1223 for (int index = 0; index < classSpecifications.size(); index++) 1224 { 1225 if (classSpecificationTemplate.equals(classSpecifications.get(index))) 1226 { 1227 // Remove the matching option as a side effect. 1228 classSpecifications.remove(index); 1229 1230 return true; 1231 } 1232 } 1233 1234 return false; 1235 } 1236 1237 1238 /** 1239 * Returns the subset of the given list of keep specifications, with 1240 * matching shrinking flag. 1241 */ 1242 private List filteredKeepSpecifications(List keepSpecifications, 1243 boolean allowShrinking) 1244 { 1245 List filteredKeepSpecifications = new ArrayList(); 1246 1247 for (int index = 0; index < keepSpecifications.size(); index++) 1248 { 1249 KeepClassSpecification keepClassSpecification = 1250 (KeepClassSpecification)keepSpecifications.get(index); 1251 1252 if (keepClassSpecification.allowShrinking == allowShrinking) 1253 { 1254 filteredKeepSpecifications.add(keepClassSpecification); 1255 } 1256 } 1257 1258 return filteredKeepSpecifications; 1259 } 1260 1261 1262 /** 1263 * Looks in the given list for keep specifications that match the given 1264 * template. Returns a comma-separated string of class names from 1265 * matching keep specifications, and removes the matching keep 1266 * specifications as a side effect. 1267 */ 1268 private String findMatchingKeepSpecifications(KeepClassSpecification keepClassSpecificationTemplate, 1269 List keepSpecifications) 1270 { 1271 if (keepSpecifications == null) 1272 { 1273 return null; 1274 } 1275 1276 StringBuffer buffer = null; 1277 1278 for (int index = 0; index < keepSpecifications.size(); index++) 1279 { 1280 KeepClassSpecification listedKeepClassSpecification = 1281 (KeepClassSpecification)keepSpecifications.get(index); 1282 String className = listedKeepClassSpecification.className; 1283 keepClassSpecificationTemplate.className = className; 1284 if (keepClassSpecificationTemplate.equals(listedKeepClassSpecification)) 1285 { 1286 if (buffer == null) 1287 { 1288 buffer = new StringBuffer(); 1289 } 1290 else 1291 { 1292 buffer.append(','); 1293 } 1294 buffer.append(className == null ? "*" : ClassUtil.externalClassName(className)); 1295 1296 // Remove the matching option as a side effect. 1297 keepSpecifications.remove(index--); 1298 } 1299 } 1300 1301 return buffer == null ? null : buffer.toString(); 1302 } 1303 1304 1305 /** 1306 * Returns a class specification or keep specification, based on the given 1307 * template and the class name to be filled in. 1308 */ 1309 private ClassSpecification classSpecification(ClassSpecification classSpecificationTemplate, 1310 String className) 1311 { 1312 // Create a copy of the template. 1313 ClassSpecification classSpecification = 1314 (ClassSpecification)classSpecificationTemplate.clone(); 1315 1316 // Set the class name in the copy. 1317 classSpecification.className = 1318 className.equals("") || 1319 className.equals("*") ? 1320 null : 1321 ClassUtil.internalClassName(className); 1322 1323 // Return the modified copy. 1324 return classSpecification; 1325 } 1326 1327 1328 // Methods and internal classes related to actions. 1329 1330 /** 1331 * Loads the given ProGuard configuration into the GUI. 1332 */ 1333 private void loadConfiguration(File file) 1334 { 1335 // Set the default directory and file in the file choosers. 1336 configurationChooser.setSelectedFile(file.getAbsoluteFile()); 1337 fileChooser.setCurrentDirectory(file.getAbsoluteFile().getParentFile()); 1338 1339 try 1340 { 1341 // Parse the configuration file. 1342 ConfigurationParser parser = new ConfigurationParser(file); 1343 Configuration configuration = new Configuration(); 1344 1345 try 1346 { 1347 parser.parse(configuration); 1348 1349 // Let the GUI reflect the configuration. 1350 setProGuardConfiguration(configuration); 1351 } 1352 catch (ParseException ex) 1353 { 1354 JOptionPane.showMessageDialog(getContentPane(), 1355 msg("cantParseConfigurationFile", file.getPath()), 1356 msg("warning"), 1357 JOptionPane.ERROR_MESSAGE); 1358 } 1359 finally 1360 { 1361 parser.close(); 1362 } 1363 } 1364 catch (IOException ex) 1365 { 1366 JOptionPane.showMessageDialog(getContentPane(), 1367 msg("cantOpenConfigurationFile", file.getPath()), 1368 msg("warning"), 1369 JOptionPane.ERROR_MESSAGE); 1370 } 1371 } 1372 1373 1374 /** 1375 * Loads the given ProGuard configuration into the GUI. 1376 */ 1377 private void loadConfiguration(URL url) 1378 { 1379 try 1380 { 1381 // Parse the configuration file. 1382 ConfigurationParser parser = new ConfigurationParser(url); 1383 Configuration configuration = new Configuration(); 1384 1385 try 1386 { 1387 parser.parse(configuration); 1388 1389 // Let the GUI reflect the configuration. 1390 setProGuardConfiguration(configuration); 1391 } 1392 catch (ParseException ex) 1393 { 1394 JOptionPane.showMessageDialog(getContentPane(), 1395 msg("cantParseConfigurationFile", url), 1396 msg("warning"), 1397 JOptionPane.ERROR_MESSAGE); 1398 } 1399 finally 1400 { 1401 parser.close(); 1402 } 1403 } 1404 catch (IOException ex) 1405 { 1406 JOptionPane.showMessageDialog(getContentPane(), 1407 msg("cantOpenConfigurationFile", url), 1408 msg("warning"), 1409 JOptionPane.ERROR_MESSAGE); 1410 } 1411 } 1412 1413 1414 /** 1415 * Saves the current ProGuard configuration to the given file. 1416 */ 1417 private void saveConfiguration(File file) 1418 { 1419 try 1420 { 1421 // Save the configuration file. 1422 ConfigurationWriter writer = new ConfigurationWriter(file); 1423 writer.write(getProGuardConfiguration()); 1424 writer.close(); 1425 } 1426 catch (Exception ex) 1427 { 1428 JOptionPane.showMessageDialog(getContentPane(), 1429 msg("cantSaveConfigurationFile", file.getPath()), 1430 msg("warning"), 1431 JOptionPane.ERROR_MESSAGE); 1432 } 1433 } 1434 1435 1436 /** 1437 * Loads the given stack trace into the GUI. 1438 */ 1439 private void loadStackTrace(String fileName) 1440 { 1441 try 1442 { 1443 StringBuffer buffer = new StringBuffer(1024); 1444 1445 Reader reader = new BufferedReader(new FileReader(fileName)); 1446 try 1447 { 1448 while (true) 1449 { 1450 int c = reader.read(); 1451 if (c < 0) 1452 { 1453 break; 1454 } 1455 1456 buffer.append(c); 1457 } 1458 } 1459 finally 1460 { 1461 reader.close(); 1462 } 1463 1464 // Put the stack trace in the text area. 1465 stackTraceTextArea.setText(buffer.toString()); 1466 } 1467 catch (IOException ex) 1468 { 1469 JOptionPane.showMessageDialog(getContentPane(), 1470 msg("cantOpenStackTraceFile", fileName), 1471 msg("warning"), 1472 JOptionPane.ERROR_MESSAGE); 1473 } 1474 } 1475 1476 1477 /** 1478 * This ActionListener loads a ProGuard configuration file and initializes 1479 * the GUI accordingly. 1480 */ 1481 private class MyLoadConfigurationActionListener implements ActionListener 1482 { 1483 public void actionPerformed(ActionEvent e) 1484 { 1485 configurationChooser.setDialogTitle(msg("selectConfigurationFile")); 1486 1487 int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this); 1488 if (returnValue == JFileChooser.APPROVE_OPTION) 1489 { 1490 loadConfiguration(configurationChooser.getSelectedFile()); 1491 } 1492 } 1493 } 1494 1495 1496 /** 1497 * This ActionListener saves a ProGuard configuration file based on the 1498 * current GUI settings. 1499 */ 1500 private class MySaveConfigurationActionListener implements ActionListener 1501 { 1502 public void actionPerformed(ActionEvent e) 1503 { 1504 configurationChooser.setDialogTitle(msg("saveConfigurationFile")); 1505 1506 int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this); 1507 if (returnVal == JFileChooser.APPROVE_OPTION) 1508 { 1509 saveConfiguration(configurationChooser.getSelectedFile()); 1510 } 1511 } 1512 } 1513 1514 1515 /** 1516 * This ActionListener displays the ProGuard configuration specified by the 1517 * current GUI settings. 1518 */ 1519 private class MyViewConfigurationActionListener implements ActionListener 1520 { 1521 public void actionPerformed(ActionEvent e) 1522 { 1523 // Make sure System.out has not been redirected yet. 1524 if (!systemOutRedirected) 1525 { 1526 consoleTextArea.setText(""); 1527 1528 TextAreaOutputStream outputStream = 1529 new TextAreaOutputStream(consoleTextArea); 1530 1531 try 1532 { 1533 // TODO: write out relative path names and path names with system properties. 1534 1535 // Write the configuration. 1536 ConfigurationWriter writer = new ConfigurationWriter(outputStream); 1537 try 1538 { 1539 writer.write(getProGuardConfiguration()); 1540 } 1541 finally 1542 { 1543 writer.close(); 1544 } 1545 } 1546 catch (IOException ex) 1547 { 1548 // This shouldn't happen. 1549 } 1550 1551 // Scroll to the top of the configuration. 1552 consoleTextArea.setCaretPosition(0); 1553 } 1554 } 1555 } 1556 1557 1558 /** 1559 * This ActionListener executes ProGuard based on the current GUI settings. 1560 */ 1561 private class MyProcessActionListener implements ActionListener 1562 { 1563 public void actionPerformed(ActionEvent e) 1564 { 1565 // Make sure System.out has not been redirected yet. 1566 if (!systemOutRedirected) 1567 { 1568 systemOutRedirected = true; 1569 1570 // Get the informational configuration file name. 1571 File configurationFile = configurationChooser.getSelectedFile(); 1572 String configurationFileName = configurationFile != null ? 1573 configurationFile.getName() : 1574 msg("sampleConfigurationFileName"); 1575 1576 // Create the ProGuard thread. 1577 Thread proGuardThread = 1578 new Thread(new ProGuardRunnable(consoleTextArea, 1579 getProGuardConfiguration(), 1580 configurationFileName)); 1581 1582 // Run it. 1583 proGuardThread.start(); 1584 } 1585 } 1586 } 1587 1588 1589 /** 1590 * This ActionListener loads an obfuscated stack trace from a file and puts 1591 * it in the proper text area. 1592 */ 1593 private class MyLoadStackTraceActionListener implements ActionListener 1594 { 1595 public void actionPerformed(ActionEvent e) 1596 { 1597 fileChooser.setDialogTitle(msg("selectStackTraceFile")); 1598 fileChooser.setSelectedFile(null); 1599 1600 int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this); 1601 if (returnValue == JFileChooser.APPROVE_OPTION) 1602 { 1603 File selectedFile = fileChooser.getSelectedFile(); 1604 String fileName = selectedFile.getPath(); 1605 1606 loadStackTrace(fileName); 1607 } 1608 } 1609 } 1610 1611 1612 /** 1613 * This ActionListener executes ReTrace based on the current GUI settings. 1614 */ 1615 private class MyReTraceActionListener implements ActionListener 1616 { 1617 public void actionPerformed(ActionEvent e) 1618 { 1619 // Make sure System.out has not been redirected yet. 1620 if (!systemOutRedirected) 1621 { 1622 systemOutRedirected = true; 1623 1624 boolean verbose = reTraceVerboseCheckBox.isSelected(); 1625 File retraceMappingFile = new File(reTraceMappingTextField.getText()); 1626 String stackTrace = stackTraceTextArea.getText(); 1627 1628 // Create the ReTrace runnable. 1629 Runnable reTraceRunnable = new ReTraceRunnable(reTraceTextArea, 1630 verbose, 1631 retraceMappingFile, 1632 stackTrace); 1633 1634 // Run it in this thread, because it won't take long anyway. 1635 reTraceRunnable.run(); 1636 } 1637 } 1638 } 1639 1640 1641 // Small utility methods. 1642 1643 /** 1644 * Returns the file name of the given file, if any. 1645 */ 1646 private static String fileName(File file) 1647 { 1648 return file == null ? "" : file.getAbsolutePath(); 1649 } 1650 1651 1652 /** 1653 * Attaches the tool tip from the GUI resources that corresponds to the 1654 * given key, to the given component. 1655 */ 1656 private static JComponent tip(JComponent component, String messageKey) 1657 { 1658 component.setToolTipText(msg(messageKey)); 1659 1660 return component; 1661 } 1662 1663 1664 /** 1665 * Returns the message from the GUI resources that corresponds to the given 1666 * key. 1667 */ 1668 private static String msg(String messageKey) 1669 { 1670 return GUIResources.getMessage(messageKey); 1671 } 1672 1673 1674 /** 1675 * Returns the message from the GUI resources that corresponds to the given 1676 * key and argument. 1677 */ 1678 private String msg(String messageKey, 1679 Object messageArgument) 1680 { 1681 return GUIResources.getMessage(messageKey, new Object[] {messageArgument}); 1682 } 1683 1684 1685 /** 1686 * The main method for the ProGuard GUI. 1687 */ 1688 public static void main(final String[] args) 1689 { 1690 try 1691 { 1692 SwingUtil.invokeAndWait(new Runnable() 1693 { 1694 public void run() 1695 { 1696 ProGuardGUI gui = new ProGuardGUI(); 1697 gui.pack(); 1698 1699 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 1700 Dimension guiSize = gui.getSize(); 1701 gui.setLocation((screenSize.width - guiSize.width) / 2, 1702 (screenSize.height - guiSize.height) / 2); 1703 gui.show(); 1704 1705 // Start the splash animation, unless specified otherwise. 1706 int argIndex = 0; 1707 if (argIndex < args.length && 1708 NO_SPLASH_OPTION.startsWith(args[argIndex])) 1709 { 1710 gui.skipSplash(); 1711 argIndex++; 1712 } 1713 else 1714 { 1715 gui.startSplash(); 1716 } 1717 1718 // Load an initial configuration, if specified. 1719 if (argIndex < args.length) 1720 { 1721 gui.loadConfiguration(new File(args[argIndex])); 1722 argIndex++; 1723 } 1724 1725 if (argIndex < args.length) 1726 { 1727 System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]"); 1728 } 1729 1730 } 1731 }); 1732 } 1733 catch (Exception e) 1734 { 1735 // Nothing. 1736 } 1737 } 1738 } 1739