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