aboutsummaryrefslogtreecommitdiffstats
path: root/src/proguard/gui/ProGuardGUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/gui/ProGuardGUI.java')
-rw-r--r--src/proguard/gui/ProGuardGUI.java1738
1 files changed, 1738 insertions, 0 deletions
diff --git a/src/proguard/gui/ProGuardGUI.java b/src/proguard/gui/ProGuardGUI.java
new file mode 100644
index 0000000..f27d698
--- /dev/null
+++ b/src/proguard/gui/ProGuardGUI.java
@@ -0,0 +1,1738 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+package proguard.gui;
+
+import proguard.*;
+import proguard.classfile.util.ClassUtil;
+import proguard.gui.splash.*;
+import proguard.util.ListUtil;
+
+import javax.swing.*;
+import javax.swing.border.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.util.List;
+import java.lang.reflect.InvocationTargetException;
+
+
+/**
+ * GUI for configuring and executing ProGuard and ReTrace.
+ *
+ * @author Eric Lafortune
+ */
+public class ProGuardGUI extends JFrame
+{
+ private static final String NO_SPLASH_OPTION = "-nosplash";
+
+ private static final String TITLE_IMAGE_FILE = "vtitle.png";
+ private static final String BOILERPLATE_CONFIGURATION = "boilerplate.pro";
+ private static final String DEFAULT_CONFIGURATION = "default.pro";
+
+ private static final String OPTIMIZATIONS_DEFAULT = "*";
+ private static final String KEEP_ATTRIBUTE_DEFAULT = "Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod";
+ private static final String SOURCE_FILE_ATTRIBUTE_DEFAULT = "SourceFile";
+ private static final String ADAPT_RESOURCE_FILE_NAMES_DEFAULT = "**.properties";
+ private static final String ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT = "**.properties,META-INF/MANIFEST.MF";
+
+ private static final Border BORDER = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
+
+ static boolean systemOutRedirected;
+
+ private final JFileChooser configurationChooser = new JFileChooser("");
+ private final JFileChooser fileChooser = new JFileChooser("");
+
+ private final SplashPanel splashPanel;
+
+ private final ClassPathPanel programPanel = new ClassPathPanel(this, true);
+ private final ClassPathPanel libraryPanel = new ClassPathPanel(this, false);
+
+ private KeepClassSpecification[] boilerplateKeep;
+ private final JCheckBox[] boilerplateKeepCheckBoxes;
+ private final JTextField[] boilerplateKeepTextFields;
+
+ private final KeepSpecificationsPanel additionalKeepPanel = new KeepSpecificationsPanel(this, true, false, false, false, false);
+
+ private KeepClassSpecification[] boilerplateKeepNames;
+ private final JCheckBox[] boilerplateKeepNamesCheckBoxes;
+ private final JTextField[] boilerplateKeepNamesTextFields;
+
+ private final KeepSpecificationsPanel additionalKeepNamesPanel = new KeepSpecificationsPanel(this, true, false, true, false, false);
+
+ private ClassSpecification[] boilerplateNoSideEffectMethods;
+ private final JCheckBox[] boilerplateNoSideEffectMethodCheckBoxes;
+
+ private final ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false);
+
+ private final ClassSpecificationsPanel whyAreYouKeepingPanel = new ClassSpecificationsPanel(this, false);
+
+ private final JCheckBox shrinkCheckBox = new JCheckBox(msg("shrink"));
+ private final JCheckBox printUsageCheckBox = new JCheckBox(msg("printUsage"));
+
+ private final JCheckBox optimizeCheckBox = new JCheckBox(msg("optimize"));
+ private final JCheckBox allowAccessModificationCheckBox = new JCheckBox(msg("allowAccessModification"));
+ private final JCheckBox mergeInterfacesAggressivelyCheckBox = new JCheckBox(msg("mergeInterfacesAggressively"));
+ private final JLabel optimizationsLabel = new JLabel(msg("optimizations"));
+ private final JLabel optimizationPassesLabel = new JLabel(msg("optimizationPasses"));
+
+ private final JSpinner optimizationPassesSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1));
+
+ private final JCheckBox obfuscateCheckBox = new JCheckBox(msg("obfuscate"));
+ private final JCheckBox printMappingCheckBox = new JCheckBox(msg("printMapping"));
+ private final JCheckBox applyMappingCheckBox = new JCheckBox(msg("applyMapping"));
+ private final JCheckBox obfuscationDictionaryCheckBox = new JCheckBox(msg("obfuscationDictionary"));
+ private final JCheckBox classObfuscationDictionaryCheckBox = new JCheckBox(msg("classObfuscationDictionary"));
+ private final JCheckBox packageObfuscationDictionaryCheckBox = new JCheckBox(msg("packageObfuscationDictionary"));
+ private final JCheckBox overloadAggressivelyCheckBox = new JCheckBox(msg("overloadAggressively"));
+ private final JCheckBox useUniqueClassMemberNamesCheckBox = new JCheckBox(msg("useUniqueClassMemberNames"));
+ private final JCheckBox useMixedCaseClassNamesCheckBox = new JCheckBox(msg("useMixedCaseClassNames"));
+ private final JCheckBox keepPackageNamesCheckBox = new JCheckBox(msg("keepPackageNames"));
+ private final JCheckBox flattenPackageHierarchyCheckBox = new JCheckBox(msg("flattenPackageHierarchy"));
+ private final JCheckBox repackageClassesCheckBox = new JCheckBox(msg("repackageClasses"));
+ private final JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes"));
+ private final JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute"));
+ private final JCheckBox adaptClassStringsCheckBox = new JCheckBox(msg("adaptClassStrings"));
+ private final JCheckBox adaptResourceFileNamesCheckBox = new JCheckBox(msg("adaptResourceFileNames"));
+ private final JCheckBox adaptResourceFileContentsCheckBox = new JCheckBox(msg("adaptResourceFileContents"));
+
+ private final JCheckBox preverifyCheckBox = new JCheckBox(msg("preverify"));
+ private final JCheckBox microEditionCheckBox = new JCheckBox(msg("microEdition"));
+ private final JCheckBox targetCheckBox = new JCheckBox(msg("target"));
+
+ private final JComboBox targetComboBox = new JComboBox(ListUtil.commaSeparatedList(msg("targets")).toArray());
+
+ private final JCheckBox verboseCheckBox = new JCheckBox(msg("verbose"));
+ private final JCheckBox noteCheckBox = new JCheckBox(msg("note"));
+ private final JCheckBox warnCheckBox = new JCheckBox(msg("warn"));
+ private final JCheckBox ignoreWarningsCheckBox = new JCheckBox(msg("ignoreWarnings"));
+ private final JCheckBox skipNonPublicLibraryClassesCheckBox = new JCheckBox(msg("skipNonPublicLibraryClasses"));
+ private final JCheckBox skipNonPublicLibraryClassMembersCheckBox = new JCheckBox(msg("skipNonPublicLibraryClassMembers"));
+ private final JCheckBox keepDirectoriesCheckBox = new JCheckBox(msg("keepDirectories"));
+ private final JCheckBox forceProcessingCheckBox = new JCheckBox(msg("forceProcessing"));
+ private final JCheckBox printSeedsCheckBox = new JCheckBox(msg("printSeeds"));
+ private final JCheckBox printConfigurationCheckBox = new JCheckBox(msg("printConfiguration"));
+ private final JCheckBox dumpCheckBox = new JCheckBox(msg("dump"));
+
+ private final JTextField printUsageTextField = new JTextField(40);
+ private final JTextField optimizationsTextField = new JTextField(40);
+ private final JTextField printMappingTextField = new JTextField(40);
+ private final JTextField applyMappingTextField = new JTextField(40);
+ private final JTextField obfuscationDictionaryTextField = new JTextField(40);
+ private final JTextField classObfuscationDictionaryTextField = new JTextField(40);
+ private final JTextField packageObfuscationDictionaryTextField = new JTextField(40);
+ private final JTextField keepPackageNamesTextField = new JTextField(40);
+ private final JTextField flattenPackageHierarchyTextField = new JTextField(40);
+ private final JTextField repackageClassesTextField = new JTextField(40);
+ private final JTextField keepAttributesTextField = new JTextField(40);
+ private final JTextField newSourceFileAttributeTextField = new JTextField(40);
+ private final JTextField adaptClassStringsTextField = new JTextField(40);
+ private final JTextField adaptResourceFileNamesTextField = new JTextField(40);
+ private final JTextField adaptResourceFileContentsTextField = new JTextField(40);
+ private final JTextField noteTextField = new JTextField(40);
+ private final JTextField warnTextField = new JTextField(40);
+ private final JTextField keepDirectoriesTextField = new JTextField(40);
+ private final JTextField printSeedsTextField = new JTextField(40);
+ private final JTextField printConfigurationTextField = new JTextField(40);
+ private final JTextField dumpTextField = new JTextField(40);
+
+ private final JTextArea consoleTextArea = new JTextArea(msg("processingInfo"), 3, 40);
+
+ private final JCheckBox reTraceVerboseCheckBox = new JCheckBox(msg("verbose"));
+ private final JTextField reTraceMappingTextField = new JTextField(40);
+ private final JTextArea stackTraceTextArea = new JTextArea(3, 40);
+ private final JTextArea reTraceTextArea = new JTextArea(msg("reTraceInfo"), 3, 40);
+
+
+ /**
+ * Creates a new ProGuardGUI.
+ */
+ public ProGuardGUI()
+ {
+ setTitle("ProGuard");
+ setDefaultCloseOperation(EXIT_ON_CLOSE);
+
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 4, 0, 4);
+
+ GridBagConstraints constraintsStretch = new GridBagConstraints();
+ constraintsStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsStretch.weightx = 1.0;
+ constraintsStretch.anchor = GridBagConstraints.WEST;
+ constraintsStretch.insets = constraints.insets;
+
+ GridBagConstraints constraintsLast = new GridBagConstraints();
+ constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLast.anchor = GridBagConstraints.WEST;
+ constraintsLast.insets = constraints.insets;
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints splashPanelConstraints = new GridBagConstraints();
+ splashPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ splashPanelConstraints.fill = GridBagConstraints.BOTH;
+ splashPanelConstraints.weightx = 1.0;
+ splashPanelConstraints.weighty = 0.02;
+ splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ //splashPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints welcomeTextAreaConstraints = new GridBagConstraints();
+ welcomeTextAreaConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ welcomeTextAreaConstraints.fill = GridBagConstraints.NONE;
+ welcomeTextAreaConstraints.weightx = 1.0;
+ welcomeTextAreaConstraints.weighty = 0.01;
+ welcomeTextAreaConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST;
+ welcomeTextAreaConstraints.insets = new Insets(20, 40, 20, 40);
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
+ stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ stretchPanelConstraints.fill = GridBagConstraints.BOTH;
+ stretchPanelConstraints.weightx = 1.0;
+ stretchPanelConstraints.weighty = 1.0;
+ stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ stretchPanelConstraints.insets = constraints.insets;
+
+ GridBagConstraints glueConstraints = new GridBagConstraints();
+ glueConstraints.fill = GridBagConstraints.BOTH;
+ glueConstraints.weightx = 0.01;
+ glueConstraints.weighty = 0.01;
+ glueConstraints.anchor = GridBagConstraints.NORTHWEST;
+ glueConstraints.insets = constraints.insets;
+
+ GridBagConstraints bottomButtonConstraints = new GridBagConstraints();
+ bottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ bottomButtonConstraints.insets = new Insets(2, 2, 4, 6);
+ bottomButtonConstraints.ipadx = 10;
+ bottomButtonConstraints.ipady = 2;
+
+ GridBagConstraints lastBottomButtonConstraints = new GridBagConstraints();
+ lastBottomButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ lastBottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
+ lastBottomButtonConstraints.insets = bottomButtonConstraints.insets;
+ lastBottomButtonConstraints.ipadx = bottomButtonConstraints.ipadx;
+ lastBottomButtonConstraints.ipady = bottomButtonConstraints.ipady;
+
+ // Leave room for a growBox on Mac OS X.
+ if (System.getProperty("os.name").toLowerCase().startsWith("mac os x"))
+ {
+ lastBottomButtonConstraints.insets = new Insets(2, 2, 4, 6 + 16);
+ }
+
+ GridBagLayout layout = new GridBagLayout();
+
+ configurationChooser.addChoosableFileFilter(
+ new ExtensionFileFilter(msg("proExtension"), new String[] { ".pro" }));
+
+ // Create the opening panel.
+ Sprite splash =
+ new CompositeSprite(new Sprite[]
+ {
+ new ColorSprite(new ConstantColor(Color.gray),
+ new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 90)),
+ new TextSprite(new ConstantString("ProGuard"),
+ new ConstantInt(160),
+ new LinearInt(-10, 120, new SmoothTiming(500, 1000))))),
+
+ new ColorSprite(new ConstantColor(Color.white),
+ new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 45)),
+ new ShadowedSprite(new ConstantInt(3),
+ new ConstantInt(3),
+ new ConstantDouble(0.4),
+ new ConstantInt(1),
+ new CompositeSprite(new Sprite[]
+ {
+ new TextSprite(new ConstantString(msg("shrinking")),
+ new LinearInt(1000, 60, new SmoothTiming(1000, 2000)),
+ new ConstantInt(70)),
+ new TextSprite(new ConstantString(msg("optimization")),
+ new LinearInt(1000, 400, new SmoothTiming(1500, 2500)),
+ new ConstantInt(60)),
+ new TextSprite(new ConstantString(msg("obfuscation")),
+ new LinearInt(1000, 10, new SmoothTiming(2000, 3000)),
+ new ConstantInt(145)),
+ new TextSprite(new ConstantString(msg("preverification")),
+ new LinearInt(1000, 350, new SmoothTiming(2500, 3500)),
+ new ConstantInt(140)),
+ new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 30)),
+ new TextSprite(new TypeWriterString(msg("developed"), new LinearTiming(3500, 5500)),
+ new ConstantInt(250),
+ new ConstantInt(200))),
+ })))),
+ });
+ splashPanel = new SplashPanel(splash, 0.5, 5500L);
+ splashPanel.setPreferredSize(new Dimension(0, 200));
+
+ JTextArea welcomeTextArea = new JTextArea(msg("proGuardInfo"), 18, 50);
+ welcomeTextArea.setOpaque(false);
+ welcomeTextArea.setEditable(false);
+ welcomeTextArea.setLineWrap(true);
+ welcomeTextArea.setWrapStyleWord(true);
+ welcomeTextArea.setPreferredSize(new Dimension(0, 0));
+ welcomeTextArea.setBorder(new EmptyBorder(20, 20, 20, 20));
+ addBorder(welcomeTextArea, "welcome");
+
+ JPanel proGuardPanel = new JPanel(layout);
+ proGuardPanel.add(splashPanel, splashPanelConstraints);
+ proGuardPanel.add(welcomeTextArea, welcomeTextAreaConstraints);
+
+ // Create the input panel.
+ // TODO: properly clone the ClassPath objects.
+ // This is awkward to implement in the generic ListPanel.addElements(...)
+ // method, since the Object.clone() method is not public.
+ programPanel.addCopyToPanelButton("moveToLibraries", "moveToLibrariesTip", libraryPanel);
+ libraryPanel.addCopyToPanelButton("moveToProgram", "moveToProgramTip", programPanel);
+
+ // Collect all buttons of these panels and make sure they are equally
+ // sized.
+ List panelButtons = new ArrayList();
+ panelButtons.addAll(programPanel.getButtons());
+ panelButtons.addAll(libraryPanel.getButtons());
+ setCommonPreferredSize(panelButtons);
+
+ addBorder(programPanel, "programJars" );
+ addBorder(libraryPanel, "libraryJars" );
+
+ JPanel inputOutputPanel = new JPanel(layout);
+ inputOutputPanel.add(tip(programPanel, "programJarsTip"), stretchPanelConstraints);
+ inputOutputPanel.add(tip(libraryPanel, "libraryJarsTip"), stretchPanelConstraints);
+
+ // Load the boiler plate options.
+ loadBoilerplateConfiguration();
+
+ // Create the boiler plate keep panels.
+ boilerplateKeepCheckBoxes = new JCheckBox[boilerplateKeep.length];
+ boilerplateKeepTextFields = new JTextField[boilerplateKeep.length];
+
+ JButton printUsageBrowseButton = createBrowseButton(printUsageTextField,
+ msg("selectUsageFile"));
+
+ JPanel shrinkingOptionsPanel = new JPanel(layout);
+ addBorder(shrinkingOptionsPanel, "options");
+
+ shrinkingOptionsPanel.add(tip(shrinkCheckBox, "shrinkTip"), constraintsLastStretch);
+ shrinkingOptionsPanel.add(tip(printUsageCheckBox, "printUsageTip"), constraints);
+ shrinkingOptionsPanel.add(tip(printUsageTextField, "outputFileTip"), constraintsStretch);
+ shrinkingOptionsPanel.add(tip(printUsageBrowseButton, "selectUsageFile"), constraintsLast);
+
+ JPanel shrinkingPanel = new JPanel(layout);
+
+ shrinkingPanel.add(shrinkingOptionsPanel, panelConstraints);
+ addClassSpecifications(extractClassSpecifications(boilerplateKeep),
+ shrinkingPanel,
+ boilerplateKeepCheckBoxes,
+ boilerplateKeepTextFields);
+
+ addBorder(additionalKeepPanel, "keepAdditional");
+ shrinkingPanel.add(tip(additionalKeepPanel, "keepAdditionalTip"), stretchPanelConstraints);
+
+ // Create the boiler plate keep names panels.
+ boilerplateKeepNamesCheckBoxes = new JCheckBox[boilerplateKeepNames.length];
+ boilerplateKeepNamesTextFields = new JTextField[boilerplateKeepNames.length];
+
+ JButton printMappingBrowseButton = createBrowseButton(printMappingTextField,
+ msg("selectPrintMappingFile"));
+ JButton applyMappingBrowseButton = createBrowseButton(applyMappingTextField,
+ msg("selectApplyMappingFile"));
+ JButton obfucationDictionaryBrowseButton = createBrowseButton(obfuscationDictionaryTextField,
+ msg("selectObfuscationDictionaryFile"));
+ JButton classObfucationDictionaryBrowseButton = createBrowseButton(classObfuscationDictionaryTextField,
+ msg("selectObfuscationDictionaryFile"));
+ JButton packageObfucationDictionaryBrowseButton = createBrowseButton(packageObfuscationDictionaryTextField,
+ msg("selectObfuscationDictionaryFile"));
+
+ JPanel obfuscationOptionsPanel = new JPanel(layout);
+ addBorder(obfuscationOptionsPanel, "options");
+
+ obfuscationOptionsPanel.add(tip(obfuscateCheckBox, "obfuscateTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(printMappingCheckBox, "printMappingTip"), constraints);
+ obfuscationOptionsPanel.add(tip(printMappingTextField, "outputFileTip"), constraintsStretch);
+ obfuscationOptionsPanel.add(tip(printMappingBrowseButton, "selectPrintMappingFile"), constraintsLast);
+ obfuscationOptionsPanel.add(tip(applyMappingCheckBox, "applyMappingTip"), constraints);
+ obfuscationOptionsPanel.add(tip(applyMappingTextField, "inputFileTip"), constraintsStretch);
+ obfuscationOptionsPanel.add(tip(applyMappingBrowseButton, "selectApplyMappingFile"), constraintsLast);
+ obfuscationOptionsPanel.add(tip(obfuscationDictionaryCheckBox, "obfuscationDictionaryTip"), constraints);
+ obfuscationOptionsPanel.add(tip(obfuscationDictionaryTextField, "inputFileTip"), constraintsStretch);
+ obfuscationOptionsPanel.add(tip(obfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast);
+ obfuscationOptionsPanel.add(tip(classObfuscationDictionaryCheckBox, "classObfuscationDictionaryTip"), constraints);
+ obfuscationOptionsPanel.add(tip(classObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch);
+ obfuscationOptionsPanel.add(tip(classObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast);
+ obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryCheckBox, "packageObfuscationDictionaryTip"), constraints);
+ obfuscationOptionsPanel.add(tip(packageObfuscationDictionaryTextField, "inputFileTip"), constraintsStretch);
+ obfuscationOptionsPanel.add(tip(packageObfucationDictionaryBrowseButton, "selectObfuscationDictionaryFile"), constraintsLast);
+ obfuscationOptionsPanel.add(tip(overloadAggressivelyCheckBox, "overloadAggressivelyTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(useUniqueClassMemberNamesCheckBox, "useUniqueClassMemberNamesTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(useMixedCaseClassNamesCheckBox, "useMixedCaseClassNamesTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(keepPackageNamesCheckBox, "keepPackageNamesTip"), constraints);
+ obfuscationOptionsPanel.add(tip(keepPackageNamesTextField, "packageNamesTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(flattenPackageHierarchyCheckBox, "flattenPackageHierarchyTip"), constraints);
+ obfuscationOptionsPanel.add(tip(flattenPackageHierarchyTextField, "packageTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(repackageClassesCheckBox, "repackageClassesTip"), constraints);
+ obfuscationOptionsPanel.add(tip(repackageClassesTextField, "packageTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(keepAttributesCheckBox, "keepAttributesTip"), constraints);
+ obfuscationOptionsPanel.add(tip(keepAttributesTextField, "attributesTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(newSourceFileAttributeCheckBox, "renameSourceFileAttributeTip"), constraints);
+ obfuscationOptionsPanel.add(tip(newSourceFileAttributeTextField, "sourceFileAttributeTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(adaptClassStringsCheckBox, "adaptClassStringsTip"), constraints);
+ obfuscationOptionsPanel.add(tip(adaptClassStringsTextField, "classNamesTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(adaptResourceFileNamesCheckBox, "adaptResourceFileNamesTip"), constraints);
+ obfuscationOptionsPanel.add(tip(adaptResourceFileNamesTextField, "fileNameFilterTip"), constraintsLastStretch);
+ obfuscationOptionsPanel.add(tip(adaptResourceFileContentsCheckBox, "adaptResourceFileContentsTip"), constraints);
+ obfuscationOptionsPanel.add(tip(adaptResourceFileContentsTextField, "fileNameFilterTip"), constraintsLastStretch);
+
+ JPanel obfuscationPanel = new JPanel(layout);
+
+ obfuscationPanel.add(obfuscationOptionsPanel, panelConstraints);
+ addClassSpecifications(extractClassSpecifications(boilerplateKeepNames),
+ obfuscationPanel,
+ boilerplateKeepNamesCheckBoxes,
+ boilerplateKeepNamesTextFields);
+
+ addBorder(additionalKeepNamesPanel, "keepNamesAdditional");
+ obfuscationPanel.add(tip(additionalKeepNamesPanel, "keepNamesAdditionalTip"), stretchPanelConstraints);
+
+ // Create the boiler plate "no side effect methods" panels.
+ boilerplateNoSideEffectMethodCheckBoxes = new JCheckBox[boilerplateNoSideEffectMethods.length];
+
+ JPanel optimizationOptionsPanel = new JPanel(layout);
+ addBorder(optimizationOptionsPanel, "options");
+
+ JButton optimizationsButton =
+ createOptimizationsButton(optimizationsTextField);
+
+ optimizationOptionsPanel.add(tip(optimizeCheckBox, "optimizeTip"), constraintsLastStretch);
+ optimizationOptionsPanel.add(tip(allowAccessModificationCheckBox, "allowAccessModificationTip"), constraintsLastStretch);
+ optimizationOptionsPanel.add(tip(mergeInterfacesAggressivelyCheckBox, "mergeInterfacesAggressivelyTip"), constraintsLastStretch);
+ optimizationOptionsPanel.add(tip(optimizationsLabel, "optimizationsTip"), constraints);
+ optimizationOptionsPanel.add(tip(optimizationsTextField, "optimizationsFilterTip"), constraintsStretch);
+ optimizationOptionsPanel.add(tip(optimizationsButton, "optimizationsSelectTip"), constraintsLast);
+ optimizationOptionsPanel.add(tip(optimizationPassesLabel, "optimizationPassesTip"), constraints);
+ optimizationOptionsPanel.add(tip(optimizationPassesSpinner, "optimizationPassesTip"), constraintsLast);
+
+ JPanel optimizationPanel = new JPanel(layout);
+
+ optimizationPanel.add(optimizationOptionsPanel, panelConstraints);
+ addClassSpecifications(boilerplateNoSideEffectMethods,
+ optimizationPanel,
+ boilerplateNoSideEffectMethodCheckBoxes,
+ null);
+
+ addBorder(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditional");
+ optimizationPanel.add(tip(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditionalTip"), stretchPanelConstraints);
+
+ // Create the options panel.
+ JPanel preverificationOptionsPanel = new JPanel(layout);
+ addBorder(preverificationOptionsPanel, "preverificationAndTargeting");
+
+ preverificationOptionsPanel.add(tip(preverifyCheckBox, "preverifyTip"), constraintsLastStretch);
+ preverificationOptionsPanel.add(tip(microEditionCheckBox, "microEditionTip"), constraintsLastStretch);
+ preverificationOptionsPanel.add(tip(targetCheckBox, "targetTip"), constraints);
+ preverificationOptionsPanel.add(tip(targetComboBox, "targetTip"), constraintsLast);
+
+ JButton printSeedsBrowseButton =
+ createBrowseButton(printSeedsTextField, msg("selectSeedsFile"));
+
+ JButton printConfigurationBrowseButton =
+ createBrowseButton(printConfigurationTextField, msg( "selectConfigurationFile"));
+
+ JButton dumpBrowseButton =
+ createBrowseButton(dumpTextField, msg("selectDumpFile"));
+
+ // Select the most recent target by default.
+ targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1);
+
+ JPanel consistencyPanel = new JPanel(layout);
+ addBorder(consistencyPanel, "consistencyAndCorrectness");
+
+ consistencyPanel.add(tip(verboseCheckBox, "verboseTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(noteCheckBox, "noteTip"), constraints);
+ consistencyPanel.add(tip(noteTextField, "noteFilterTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(warnCheckBox, "warnTip"), constraints);
+ consistencyPanel.add(tip(warnTextField, "warnFilterTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(ignoreWarningsCheckBox, "ignoreWarningsTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(skipNonPublicLibraryClassesCheckBox, "skipNonPublicLibraryClassesTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(skipNonPublicLibraryClassMembersCheckBox, "skipNonPublicLibraryClassMembersTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(keepDirectoriesCheckBox, "keepDirectoriesTip"), constraints);
+ consistencyPanel.add(tip(keepDirectoriesTextField, "directoriesTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(forceProcessingCheckBox, "forceProcessingTip"), constraintsLastStretch);
+ consistencyPanel.add(tip(printSeedsCheckBox, "printSeedsTip"), constraints);
+ consistencyPanel.add(tip(printSeedsTextField, "outputFileTip"), constraintsStretch);
+ consistencyPanel.add(tip(printSeedsBrowseButton, "selectSeedsFile"), constraintsLast);
+ consistencyPanel.add(tip(printConfigurationCheckBox, "printConfigurationTip"), constraints);
+ consistencyPanel.add(tip(printConfigurationTextField, "outputFileTip"), constraintsStretch);
+ consistencyPanel.add(tip(printConfigurationBrowseButton, "selectConfigurationFile"), constraintsLast);
+ consistencyPanel.add(tip(dumpCheckBox, "dumpTip"), constraints);
+ consistencyPanel.add(tip(dumpTextField, "outputFileTip"), constraintsStretch);
+ consistencyPanel.add(tip(dumpBrowseButton, "selectDumpFile"), constraintsLast);
+
+ // Collect all components that are followed by text fields and make
+ // sure they are equally sized. That way the text fields start at the
+ // same horizontal position.
+ setCommonPreferredSize(Arrays.asList(new JComponent[] {
+ printMappingCheckBox,
+ applyMappingCheckBox,
+ flattenPackageHierarchyCheckBox,
+ repackageClassesCheckBox,
+ newSourceFileAttributeCheckBox,
+ }));
+
+ JPanel optionsPanel = new JPanel(layout);
+
+ optionsPanel.add(preverificationOptionsPanel, panelConstraints);
+ optionsPanel.add(consistencyPanel, panelConstraints);
+
+ addBorder(whyAreYouKeepingPanel, "whyAreYouKeeping");
+ optionsPanel.add(tip(whyAreYouKeepingPanel, "whyAreYouKeepingTip"), stretchPanelConstraints);
+
+ // Create the process panel.
+ consoleTextArea.setOpaque(false);
+ consoleTextArea.setEditable(false);
+ consoleTextArea.setLineWrap(false);
+ consoleTextArea.setWrapStyleWord(false);
+ JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea);
+ consoleScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
+ addBorder(consoleScrollPane, "processingConsole");
+
+ JPanel processPanel = new JPanel(layout);
+ processPanel.add(consoleScrollPane, stretchPanelConstraints);
+
+ // Create the load, save, and process buttons.
+ JButton loadButton = new JButton(msg("loadConfiguration"));
+ loadButton.addActionListener(new MyLoadConfigurationActionListener());
+
+ JButton viewButton = new JButton(msg("viewConfiguration"));
+ viewButton.addActionListener(new MyViewConfigurationActionListener());
+
+ JButton saveButton = new JButton(msg("saveConfiguration"));
+ saveButton.addActionListener(new MySaveConfigurationActionListener());
+
+ JButton processButton = new JButton(msg("process"));
+ processButton.addActionListener(new MyProcessActionListener());
+
+ // Create the ReTrace panel.
+ JPanel reTraceSettingsPanel = new JPanel(layout);
+ addBorder(reTraceSettingsPanel, "reTraceSettings");
+
+ JButton reTraceMappingBrowseButton = createBrowseButton(reTraceMappingTextField,
+ msg("selectApplyMappingFile"));
+
+ JLabel reTraceMappingLabel = new JLabel(msg("mappingFile"));
+ reTraceMappingLabel.setForeground(reTraceVerboseCheckBox.getForeground());
+
+ reTraceSettingsPanel.add(tip(reTraceVerboseCheckBox, "verboseTip"), constraintsLastStretch);
+ reTraceSettingsPanel.add(tip(reTraceMappingLabel, "mappingFileTip"), constraints);
+ reTraceSettingsPanel.add(tip(reTraceMappingTextField, "inputFileTip"), constraintsStretch);
+ reTraceSettingsPanel.add(tip(reTraceMappingBrowseButton, "selectApplyMappingFile"), constraintsLast);
+
+ stackTraceTextArea.setOpaque(true);
+ stackTraceTextArea.setEditable(true);
+ stackTraceTextArea.setLineWrap(false);
+ stackTraceTextArea.setWrapStyleWord(true);
+ JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceTextArea);
+ addBorder(stackTraceScrollPane, "obfuscatedStackTrace");
+
+ reTraceTextArea.setOpaque(false);
+ reTraceTextArea.setEditable(false);
+ reTraceTextArea.setLineWrap(true);
+ reTraceTextArea.setWrapStyleWord(true);
+ JScrollPane reTraceScrollPane = new JScrollPane(reTraceTextArea);
+ reTraceScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
+ addBorder(reTraceScrollPane, "deobfuscatedStackTrace");
+
+ JPanel reTracePanel = new JPanel(layout);
+ reTracePanel.add(reTraceSettingsPanel, panelConstraints);
+ reTracePanel.add(tip(stackTraceScrollPane, "obfuscatedStackTraceTip"), panelConstraints);
+ reTracePanel.add(reTraceScrollPane, stretchPanelConstraints);
+
+ // Create the load button.
+ JButton loadStackTraceButton = new JButton(msg("loadStackTrace"));
+ loadStackTraceButton.addActionListener(new MyLoadStackTraceActionListener());
+
+ JButton reTraceButton = new JButton(msg("reTrace"));
+ reTraceButton.addActionListener(new MyReTraceActionListener());
+
+ // Create the main tabbed pane.
+ TabbedPane tabs = new TabbedPane();
+ tabs.add(msg("proGuardTab"), proGuardPanel);
+ tabs.add(msg("inputOutputTab"), inputOutputPanel);
+ tabs.add(msg("shrinkingTab"), shrinkingPanel);
+ tabs.add(msg("obfuscationTab"), obfuscationPanel);
+ tabs.add(msg("optimizationTab"), optimizationPanel);
+ tabs.add(msg("informationTab"), optionsPanel);
+ tabs.add(msg("processTab"), processPanel);
+ tabs.add(msg("reTraceTab"), reTracePanel);
+ tabs.addImage(Toolkit.getDefaultToolkit().getImage(
+ this.getClass().getResource(TITLE_IMAGE_FILE)));
+
+ // Add the bottom buttons to each panel.
+ proGuardPanel .add(Box.createGlue(), glueConstraints);
+ proGuardPanel .add(tip(loadButton, "loadConfigurationTip"), bottomButtonConstraints);
+ proGuardPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ inputOutputPanel .add(Box.createGlue(), glueConstraints);
+ inputOutputPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ inputOutputPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ shrinkingPanel .add(Box.createGlue(), glueConstraints);
+ shrinkingPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ shrinkingPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ obfuscationPanel .add(Box.createGlue(), glueConstraints);
+ obfuscationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ obfuscationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ optimizationPanel .add(Box.createGlue(), glueConstraints);
+ optimizationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ optimizationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ optionsPanel .add(Box.createGlue(), glueConstraints);
+ optionsPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ optionsPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
+
+ processPanel .add(Box.createGlue(), glueConstraints);
+ processPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
+ processPanel .add(tip(viewButton, "viewConfigurationTip"), bottomButtonConstraints);
+ processPanel .add(tip(saveButton, "saveConfigurationTip"), bottomButtonConstraints);
+ processPanel .add(tip(processButton, "processTip"), lastBottomButtonConstraints);
+
+ reTracePanel .add(Box.createGlue(), glueConstraints);
+ reTracePanel .add(tip(loadStackTraceButton, "loadStackTraceTip"), bottomButtonConstraints);
+ reTracePanel .add(tip(reTraceButton, "reTraceTip"), lastBottomButtonConstraints);
+
+ // Initialize the GUI settings to reasonable defaults.
+ loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION));
+
+ // Add the main tabs to the frame and pack it.
+ getContentPane().add(tabs);
+ }
+
+
+ public void startSplash()
+ {
+ splashPanel.start();
+ }
+
+
+ public void skipSplash()
+ {
+ splashPanel.stop();
+ }
+
+
+ /**
+ * Loads the boilerplate keep class options from the boilerplate file
+ * into the boilerplate array.
+ */
+ private void loadBoilerplateConfiguration()
+ {
+ try
+ {
+ // Parse the boilerplate configuration file.
+ ConfigurationParser parser = new ConfigurationParser(
+ this.getClass().getResource(BOILERPLATE_CONFIGURATION));
+ Configuration configuration = new Configuration();
+
+ try
+ {
+ parser.parse(configuration);
+
+ // We're interested in the keep options.
+ boilerplateKeep =
+ extractKeepSpecifications(configuration.keep, false, false);
+
+ // We're interested in the keep options.
+ boilerplateKeepNames =
+ extractKeepSpecifications(configuration.keep, true, false);
+
+ // We're interested in the side effects options.
+ boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()];
+ configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods);
+ }
+ finally
+ {
+ parser.close();
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+
+ /**
+ * Returns an array containing the ClassSpecifications instances with
+ * matching flags.
+ */
+ private KeepClassSpecification[] extractKeepSpecifications(List keepSpecifications,
+ boolean allowShrinking,
+ boolean allowObfuscation)
+ {
+ List matches = new ArrayList();
+
+ for (int index = 0; index < keepSpecifications.size(); index++)
+ {
+ KeepClassSpecification keepClassSpecification = (KeepClassSpecification)keepSpecifications.get(index);
+ if (keepClassSpecification.allowShrinking == allowShrinking &&
+ keepClassSpecification.allowObfuscation == allowObfuscation)
+ {
+ matches.add(keepClassSpecification);
+ }
+ }
+
+ KeepClassSpecification[] matchingKeepClassSpecifications = new KeepClassSpecification[matches.size()];
+ matches.toArray(matchingKeepClassSpecifications);
+
+ return matchingKeepClassSpecifications;
+ }
+
+
+ /**
+ * Returns an array containing the ClassSpecification instances of the
+ * given array of KeepClassSpecification instances.
+ */
+ private ClassSpecification[] extractClassSpecifications(KeepClassSpecification[] keepClassSpecifications)
+ {
+ ClassSpecification[] classSpecifications = new ClassSpecification[keepClassSpecifications.length];
+
+ for (int index = 0; index < classSpecifications.length; index++)
+ {
+ classSpecifications[index] = keepClassSpecifications[index];
+ }
+
+ return classSpecifications;
+ }
+
+
+ /**
+ * Creates a panel with the given boiler plate class specifications.
+ */
+ private void addClassSpecifications(ClassSpecification[] boilerplateClassSpecifications,
+ JPanel classSpecificationsPanel,
+ JCheckBox[] boilerplateCheckBoxes,
+ JTextField[] boilerplateTextFields)
+ {
+ // Create some constraints that can be reused.
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 4, 0, 4);
+
+ GridBagConstraints constraintsLastStretch = new GridBagConstraints();
+ constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
+ constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
+ constraintsLastStretch.weightx = 1.0;
+ constraintsLastStretch.anchor = GridBagConstraints.WEST;
+ constraintsLastStretch.insets = constraints.insets;
+
+ GridBagConstraints panelConstraints = new GridBagConstraints();
+ panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
+ panelConstraints.fill = GridBagConstraints.HORIZONTAL;
+ panelConstraints.weightx = 1.0;
+ panelConstraints.anchor = GridBagConstraints.NORTHWEST;
+ panelConstraints.insets = constraints.insets;
+
+ GridBagLayout layout = new GridBagLayout();
+
+ String lastPanelName = null;
+ JPanel keepSubpanel = null;
+ for (int index = 0; index < boilerplateClassSpecifications.length; index++)
+ {
+ // The panel structure is derived from the comments.
+ String comments = boilerplateClassSpecifications[index].comments;
+ int dashIndex = comments.indexOf('-');
+ int periodIndex = comments.indexOf('.', dashIndex);
+ String panelName = comments.substring(0, dashIndex).trim();
+ String optionName = comments.substring(dashIndex + 1, periodIndex).replace('_', '.').trim();
+ String toolTip = comments.substring(periodIndex + 1);
+ if (keepSubpanel == null || !panelName.equals(lastPanelName))
+ {
+ // Create a new keep subpanel and add it.
+ keepSubpanel = new JPanel(layout);
+ keepSubpanel.setBorder(BorderFactory.createTitledBorder(BORDER, panelName));
+ classSpecificationsPanel.add(keepSubpanel, panelConstraints);
+
+ lastPanelName = panelName;
+ }
+
+ // Add the check box to the subpanel.
+ JCheckBox boilerplateCheckBox = new JCheckBox(optionName);
+ boilerplateCheckBox.setToolTipText(toolTip);
+ boilerplateCheckBoxes[index] = boilerplateCheckBox;
+ keepSubpanel.add(boilerplateCheckBox,
+ boilerplateTextFields != null ?
+ constraints :
+ constraintsLastStretch);
+
+ if (boilerplateTextFields != null)
+ {
+ // Add the text field to the subpanel.
+ boilerplateTextFields[index] = new JTextField(40);
+ keepSubpanel.add(tip(boilerplateTextFields[index], "classNamesTip"), constraintsLastStretch);
+ }
+ }
+ }
+
+
+ /**
+ * Adds a standard border with the title that corresponds to the given key
+ * in the GUI resources.
+ */
+ private void addBorder(JComponent component, String titleKey)
+ {
+ Border oldBorder = component.getBorder();
+ Border newBorder = BorderFactory.createTitledBorder(BORDER, msg(titleKey));
+
+ component.setBorder(oldBorder == null ?
+ newBorder :
+ new CompoundBorder(newBorder, oldBorder));
+ }
+
+
+ /**
+ * Creates a Previous button for the given tabbed pane.
+ */
+ private JButton createPreviousButton(final TabbedPane tabbedPane)
+ {
+ JButton browseButton = new JButton(msg("previous"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ tabbedPane.previous();
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ /**
+ * Creates a Next button for the given tabbed pane.
+ */
+ private JButton createNextButton(final TabbedPane tabbedPane)
+ {
+ JButton browseButton = new JButton(msg("next"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ tabbedPane.next();
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ /**
+ * Creates a browse button that opens a file browser for the given text field.
+ */
+ private JButton createBrowseButton(final JTextField textField,
+ final String title)
+ {
+ JButton browseButton = new JButton(msg("browse"));
+ browseButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Update the file chooser.
+ fileChooser.setDialogTitle(title);
+ fileChooser.setSelectedFile(new File(textField.getText()));
+
+ int returnVal = fileChooser.showDialog(ProGuardGUI.this, msg("ok"));
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
+ // Update the text field.
+ textField.setText(fileChooser.getSelectedFile().getPath());
+ }
+ }
+ });
+
+ return browseButton;
+ }
+
+
+ protected JButton createOptimizationsButton(final JTextField textField)
+ {
+ final OptimizationsDialog optimizationsDialog = new OptimizationsDialog(ProGuardGUI.this);
+
+ JButton optimizationsButton = new JButton(msg("select"));
+ optimizationsButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Update the dialog.
+ optimizationsDialog.setFilter(textField.getText());
+
+ int returnValue = optimizationsDialog.showDialog();
+ if (returnValue == OptimizationsDialog.APPROVE_OPTION)
+ {
+ // Update the text field.
+ textField.setText(optimizationsDialog.getFilter());
+ }
+ }
+ });
+
+ return optimizationsButton;
+ }
+
+
+ /**
+ * Sets the preferred sizes of the given components to the maximum of their
+ * current preferred sizes.
+ */
+ private void setCommonPreferredSize(List components)
+ {
+ // Find the maximum preferred size.
+ Dimension maximumSize = null;
+ for (int index = 0; index < components.size(); index++)
+ {
+ JComponent component = (JComponent)components.get(index);
+ Dimension size = component.getPreferredSize();
+ if (maximumSize == null ||
+ size.getWidth() > maximumSize.getWidth())
+ {
+ maximumSize = size;
+ }
+ }
+
+ // Set the size that we found as the preferred size for all components.
+ for (int index = 0; index < components.size(); index++)
+ {
+ JComponent component = (JComponent)components.get(index);
+ component.setPreferredSize(maximumSize);
+ }
+ }
+
+
+ /**
+ * Updates to GUI settings to reflect the given ProGuard configuration.
+ */
+ private void setProGuardConfiguration(Configuration configuration)
+ {
+ // Set up the input and output jars and directories.
+ programPanel.setClassPath(configuration.programJars);
+ libraryPanel.setClassPath(configuration.libraryJars);
+
+ // Set up the boilerplate keep options.
+ for (int index = 0; index < boilerplateKeep.length; index++)
+ {
+ String classNames =
+ findMatchingKeepSpecifications(boilerplateKeep[index],
+ configuration.keep);
+
+ boilerplateKeepCheckBoxes[index].setSelected(classNames != null);
+ boilerplateKeepTextFields[index].setText(classNames == null ? "*" : classNames);
+ }
+
+
+ // Set up the boilerplate keep names options.
+ for (int index = 0; index < boilerplateKeepNames.length; index++)
+ {
+ String classNames =
+ findMatchingKeepSpecifications(boilerplateKeepNames[index],
+ configuration.keep);
+
+ boilerplateKeepNamesCheckBoxes[index].setSelected(classNames != null);
+ boilerplateKeepNamesTextFields[index].setText(classNames == null ? "*" : classNames);
+ }
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalKeepPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep,
+ false));
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalKeepNamesPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep,
+ true));
+
+
+ // Set up the boilerplate "no side effect methods" options.
+ for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
+ {
+ boolean found =
+ findClassSpecification(boilerplateNoSideEffectMethods[index],
+ configuration.assumeNoSideEffects);
+
+ boilerplateNoSideEffectMethodCheckBoxes[index].setSelected(found);
+ }
+
+ // Set up the additional keep options. Note that the matched boilerplate
+ // options have been removed from the list.
+ additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects);
+
+ // Set up the "why are you keeping" options.
+ whyAreYouKeepingPanel.setClassSpecifications(configuration.whyAreYouKeeping);
+
+ // Set up the other options.
+ shrinkCheckBox .setSelected(configuration.shrink);
+ printUsageCheckBox .setSelected(configuration.printUsage != null);
+
+ optimizeCheckBox .setSelected(configuration.optimize);
+ allowAccessModificationCheckBox .setSelected(configuration.allowAccessModification);
+ mergeInterfacesAggressivelyCheckBox .setSelected(configuration.mergeInterfacesAggressively);
+ optimizationPassesSpinner.getModel() .setValue(new Integer(configuration.optimizationPasses));
+
+ obfuscateCheckBox .setSelected(configuration.obfuscate);
+ printMappingCheckBox .setSelected(configuration.printMapping != null);
+ applyMappingCheckBox .setSelected(configuration.applyMapping != null);
+ obfuscationDictionaryCheckBox .setSelected(configuration.obfuscationDictionary != null);
+ classObfuscationDictionaryCheckBox .setSelected(configuration.classObfuscationDictionary != null);
+ packageObfuscationDictionaryCheckBox .setSelected(configuration.packageObfuscationDictionary != null);
+ overloadAggressivelyCheckBox .setSelected(configuration.overloadAggressively);
+ useUniqueClassMemberNamesCheckBox .setSelected(configuration.useUniqueClassMemberNames);
+ useMixedCaseClassNamesCheckBox .setSelected(configuration.useMixedCaseClassNames);
+ keepPackageNamesCheckBox .setSelected(configuration.keepPackageNames != null);
+ flattenPackageHierarchyCheckBox .setSelected(configuration.flattenPackageHierarchy != null);
+ repackageClassesCheckBox .setSelected(configuration.repackageClasses != null);
+ keepAttributesCheckBox .setSelected(configuration.keepAttributes != null);
+ newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null);
+ adaptClassStringsCheckBox .setSelected(configuration.adaptClassStrings != null);
+ adaptResourceFileNamesCheckBox .setSelected(configuration.adaptResourceFileNames != null);
+ adaptResourceFileContentsCheckBox .setSelected(configuration.adaptResourceFileContents != null);
+
+ preverifyCheckBox .setSelected(configuration.preverify);
+ microEditionCheckBox .setSelected(configuration.microEdition);
+ targetCheckBox .setSelected(configuration.targetClassVersion != 0);
+
+ verboseCheckBox .setSelected(configuration.verbose);
+ noteCheckBox .setSelected(configuration.note == null || !configuration.note.isEmpty());
+ warnCheckBox .setSelected(configuration.warn == null || !configuration.warn.isEmpty());
+ ignoreWarningsCheckBox .setSelected(configuration.ignoreWarnings);
+ skipNonPublicLibraryClassesCheckBox .setSelected(configuration.skipNonPublicLibraryClasses);
+ skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers);
+ keepDirectoriesCheckBox .setSelected(configuration.keepDirectories != null);
+ forceProcessingCheckBox .setSelected(configuration.lastModified == Long.MAX_VALUE);
+ printSeedsCheckBox .setSelected(configuration.printSeeds != null);
+ printConfigurationCheckBox .setSelected(configuration.printConfiguration != null);
+ dumpCheckBox .setSelected(configuration.dump != null);
+
+ printUsageTextField .setText(fileName(configuration.printUsage));
+ optimizationsTextField .setText(configuration.optimizations == null ? OPTIMIZATIONS_DEFAULT : ListUtil.commaSeparatedString(configuration.optimizations));
+ printMappingTextField .setText(fileName(configuration.printMapping));
+ applyMappingTextField .setText(fileName(configuration.applyMapping));
+ obfuscationDictionaryTextField .setText(fileName(configuration.obfuscationDictionary));
+ keepPackageNamesTextField .setText(configuration.keepPackageNames == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.keepPackageNames)));
+ flattenPackageHierarchyTextField .setText(configuration.flattenPackageHierarchy);
+ repackageClassesTextField .setText(configuration.repackageClasses);
+ keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes));
+ newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute);
+ adaptClassStringsTextField .setText(configuration.adaptClassStrings == null ? "" : ClassUtil.externalClassName(ListUtil.commaSeparatedString(configuration.adaptClassStrings)));
+ adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames));
+ adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents));
+ noteTextField .setText(ListUtil.commaSeparatedString(configuration.note));
+ warnTextField .setText(ListUtil.commaSeparatedString(configuration.warn));
+ keepDirectoriesTextField .setText(ListUtil.commaSeparatedString(configuration.keepDirectories));
+ printSeedsTextField .setText(fileName(configuration.printSeeds));
+ printConfigurationTextField .setText(fileName(configuration.printConfiguration));
+ dumpTextField .setText(fileName(configuration.dump));
+
+ if (configuration.targetClassVersion != 0)
+ {
+ targetComboBox.setSelectedItem(ClassUtil.externalClassVersion(configuration.targetClassVersion));
+ }
+ else
+ {
+ targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1);
+ }
+
+ if (configuration.printMapping != null)
+ {
+ reTraceMappingTextField.setText(fileName(configuration.printMapping));
+ }
+ }
+
+
+ /**
+ * Returns the ProGuard configuration that reflects the current GUI settings.
+ */
+ private Configuration getProGuardConfiguration()
+ {
+ Configuration configuration = new Configuration();
+
+ // Get the input and output jars and directories.
+ configuration.programJars = programPanel.getClassPath();
+ configuration.libraryJars = libraryPanel.getClassPath();
+
+ List keep = new ArrayList();
+
+ // Collect the additional keep options.
+ List additionalKeep = additionalKeepPanel.getClassSpecifications();
+ if (additionalKeep != null)
+ {
+ keep.addAll(additionalKeep);
+ }
+
+ // Collect the additional keep names options.
+ List additionalKeepNames = additionalKeepNamesPanel.getClassSpecifications();
+ if (additionalKeepNames != null)
+ {
+ keep.addAll(additionalKeepNames);
+ }
+
+ // Collect the boilerplate keep options.
+ for (int index = 0; index < boilerplateKeep.length; index++)
+ {
+ if (boilerplateKeepCheckBoxes[index].isSelected())
+ {
+ keep.add(classSpecification(boilerplateKeep[index],
+ boilerplateKeepTextFields[index].getText()));
+ }
+ }
+
+ // Collect the boilerplate keep names options.
+ for (int index = 0; index < boilerplateKeepNames.length; index++)
+ {
+ if (boilerplateKeepNamesCheckBoxes[index].isSelected())
+ {
+ keep.add(classSpecification(boilerplateKeepNames[index],
+ boilerplateKeepNamesTextFields[index].getText()));
+ }
+ }
+
+ // Put the list of keep specifications in the configuration.
+ if (keep.size() > 0)
+ {
+ configuration.keep = keep;
+ }
+
+
+ // Collect the boilerplate "no side effect methods" options.
+ List noSideEffectMethods = new ArrayList();
+
+ for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
+ {
+ if (boilerplateNoSideEffectMethodCheckBoxes[index].isSelected())
+ {
+ noSideEffectMethods.add(boilerplateNoSideEffectMethods[index]);
+ }
+ }
+
+ // Collect the additional "no side effect methods" options.
+ List additionalNoSideEffectOptions = additionalNoSideEffectsPanel.getClassSpecifications();
+ if (additionalNoSideEffectOptions != null)
+ {
+ noSideEffectMethods.addAll(additionalNoSideEffectOptions);
+ }
+
+ // Put the list of "no side effect methods" options in the configuration.
+ if (noSideEffectMethods.size() > 0)
+ {
+ configuration.assumeNoSideEffects = noSideEffectMethods;
+ }
+
+
+ // Collect the "why are you keeping" options.
+ configuration.whyAreYouKeeping = whyAreYouKeepingPanel.getClassSpecifications();
+
+
+ // Get the other options.
+ configuration.shrink = shrinkCheckBox .isSelected();
+ configuration.printUsage = printUsageCheckBox .isSelected() ? new File(printUsageTextField .getText()) : null;
+
+ configuration.optimize = optimizeCheckBox .isSelected();
+ configuration.allowAccessModification = allowAccessModificationCheckBox .isSelected();
+ configuration.mergeInterfacesAggressively = mergeInterfacesAggressivelyCheckBox .isSelected();
+ configuration.optimizations = optimizationsTextField.getText().length() > 1 ? ListUtil.commaSeparatedList(optimizationsTextField .getText()) : null;
+ configuration.optimizationPasses = ((SpinnerNumberModel)optimizationPassesSpinner.getModel()).getNumber().intValue();
+
+ configuration.obfuscate = obfuscateCheckBox .isSelected();
+ configuration.printMapping = printMappingCheckBox .isSelected() ? new File(printMappingTextField .getText()) : null;
+ configuration.applyMapping = applyMappingCheckBox .isSelected() ? new File(applyMappingTextField .getText()) : null;
+ configuration.obfuscationDictionary = obfuscationDictionaryCheckBox .isSelected() ? new File(obfuscationDictionaryTextField .getText()) : null;
+ configuration.classObfuscationDictionary = classObfuscationDictionaryCheckBox .isSelected() ? new File(classObfuscationDictionaryTextField .getText()) : null;
+ configuration.packageObfuscationDictionary = packageObfuscationDictionaryCheckBox .isSelected() ? new File(packageObfuscationDictionaryTextField .getText()) : null;
+ configuration.overloadAggressively = overloadAggressivelyCheckBox .isSelected();
+ configuration.useUniqueClassMemberNames = useUniqueClassMemberNamesCheckBox .isSelected();
+ configuration.useMixedCaseClassNames = useMixedCaseClassNamesCheckBox .isSelected();
+ configuration.keepPackageNames = keepPackageNamesCheckBox .isSelected() ? keepPackageNamesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepPackageNamesTextField.getText())) : new ArrayList() : null;
+ configuration.flattenPackageHierarchy = flattenPackageHierarchyCheckBox .isSelected() ? ClassUtil.internalClassName(flattenPackageHierarchyTextField .getText()) : null;
+ configuration.repackageClasses = repackageClassesCheckBox .isSelected() ? ClassUtil.internalClassName(repackageClassesTextField .getText()) : null;
+ configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField .getText()) : null;
+ configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null;
+ configuration.adaptClassStrings = adaptClassStringsCheckBox .isSelected() ? adaptClassStringsTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(adaptClassStringsTextField.getText())) : new ArrayList() : null;
+ configuration.adaptResourceFileNames = adaptResourceFileNamesCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileNamesTextField .getText()) : null;
+ configuration.adaptResourceFileContents = adaptResourceFileContentsCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileContentsTextField .getText()) : null;
+
+ configuration.preverify = preverifyCheckBox .isSelected();
+ configuration.microEdition = microEditionCheckBox .isSelected();
+ configuration.targetClassVersion = targetCheckBox .isSelected() ? ClassUtil.internalClassVersion(targetComboBox.getSelectedItem().toString()) : 0;
+
+ configuration.verbose = verboseCheckBox .isSelected();
+ configuration.note = noteCheckBox .isSelected() ? noteTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(noteTextField.getText())) : null : new ArrayList();
+ configuration.warn = warnCheckBox .isSelected() ? warnTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(warnTextField.getText())) : null : new ArrayList();
+ configuration.ignoreWarnings = ignoreWarningsCheckBox .isSelected();
+ configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClassesCheckBox .isSelected();
+ configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembersCheckBox.isSelected();
+ configuration.keepDirectories = keepDirectoriesCheckBox .isSelected() ? keepDirectoriesTextField.getText().length() > 0 ? ListUtil.commaSeparatedList(ClassUtil.internalClassName(keepDirectoriesTextField.getText())) : new ArrayList() : null;
+ configuration.lastModified = forceProcessingCheckBox .isSelected() ? Long.MAX_VALUE : System.currentTimeMillis();
+ configuration.printSeeds = printSeedsCheckBox .isSelected() ? new File(printSeedsTextField .getText()) : null;
+ configuration.printConfiguration = printConfigurationCheckBox .isSelected() ? new File(printConfigurationTextField .getText()) : null;
+ configuration.dump = dumpCheckBox .isSelected() ? new File(dumpTextField .getText()) : null;
+
+ return configuration;
+ }
+
+
+ /**
+ * Looks in the given list for a class specification that is identical to
+ * the given template. Returns true if it is found, and removes the matching
+ * class specification as a side effect.
+ */
+ private boolean findClassSpecification(ClassSpecification classSpecificationTemplate,
+ List classSpecifications)
+ {
+ if (classSpecifications == null)
+ {
+ return false;
+ }
+
+ for (int index = 0; index < classSpecifications.size(); index++)
+ {
+ if (classSpecificationTemplate.equals(classSpecifications.get(index)))
+ {
+ // Remove the matching option as a side effect.
+ classSpecifications.remove(index);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Returns the subset of the given list of keep specifications, with
+ * matching shrinking flag.
+ */
+ private List filteredKeepSpecifications(List keepSpecifications,
+ boolean allowShrinking)
+ {
+ List filteredKeepSpecifications = new ArrayList();
+
+ for (int index = 0; index < keepSpecifications.size(); index++)
+ {
+ KeepClassSpecification keepClassSpecification =
+ (KeepClassSpecification)keepSpecifications.get(index);
+
+ if (keepClassSpecification.allowShrinking == allowShrinking)
+ {
+ filteredKeepSpecifications.add(keepClassSpecification);
+ }
+ }
+
+ return filteredKeepSpecifications;
+ }
+
+
+ /**
+ * Looks in the given list for keep specifications that match the given
+ * template. Returns a comma-separated string of class names from
+ * matching keep specifications, and removes the matching keep
+ * specifications as a side effect.
+ */
+ private String findMatchingKeepSpecifications(KeepClassSpecification keepClassSpecificationTemplate,
+ List keepSpecifications)
+ {
+ if (keepSpecifications == null)
+ {
+ return null;
+ }
+
+ StringBuffer buffer = null;
+
+ for (int index = 0; index < keepSpecifications.size(); index++)
+ {
+ KeepClassSpecification listedKeepClassSpecification =
+ (KeepClassSpecification)keepSpecifications.get(index);
+ String className = listedKeepClassSpecification.className;
+ keepClassSpecificationTemplate.className = className;
+ if (keepClassSpecificationTemplate.equals(listedKeepClassSpecification))
+ {
+ if (buffer == null)
+ {
+ buffer = new StringBuffer();
+ }
+ else
+ {
+ buffer.append(',');
+ }
+ buffer.append(className == null ? "*" : ClassUtil.externalClassName(className));
+
+ // Remove the matching option as a side effect.
+ keepSpecifications.remove(index--);
+ }
+ }
+
+ return buffer == null ? null : buffer.toString();
+ }
+
+
+ /**
+ * Returns a class specification or keep specification, based on the given
+ * template and the class name to be filled in.
+ */
+ private ClassSpecification classSpecification(ClassSpecification classSpecificationTemplate,
+ String className)
+ {
+ // Create a copy of the template.
+ ClassSpecification classSpecification =
+ (ClassSpecification)classSpecificationTemplate.clone();
+
+ // Set the class name in the copy.
+ classSpecification.className =
+ className.equals("") ||
+ className.equals("*") ?
+ null :
+ ClassUtil.internalClassName(className);
+
+ // Return the modified copy.
+ return classSpecification;
+ }
+
+
+ // Methods and internal classes related to actions.
+
+ /**
+ * Loads the given ProGuard configuration into the GUI.
+ */
+ private void loadConfiguration(File file)
+ {
+ // Set the default directory and file in the file choosers.
+ configurationChooser.setSelectedFile(file.getAbsoluteFile());
+ fileChooser.setCurrentDirectory(file.getAbsoluteFile().getParentFile());
+
+ try
+ {
+ // Parse the configuration file.
+ ConfigurationParser parser = new ConfigurationParser(file);
+ Configuration configuration = new Configuration();
+
+ try
+ {
+ parser.parse(configuration);
+
+ // Let the GUI reflect the configuration.
+ setProGuardConfiguration(configuration);
+ }
+ catch (ParseException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantParseConfigurationFile", file.getPath()),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ finally
+ {
+ parser.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenConfigurationFile", file.getPath()),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Loads the given ProGuard configuration into the GUI.
+ */
+ private void loadConfiguration(URL url)
+ {
+ try
+ {
+ // Parse the configuration file.
+ ConfigurationParser parser = new ConfigurationParser(url);
+ Configuration configuration = new Configuration();
+
+ try
+ {
+ parser.parse(configuration);
+
+ // Let the GUI reflect the configuration.
+ setProGuardConfiguration(configuration);
+ }
+ catch (ParseException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantParseConfigurationFile", url),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ finally
+ {
+ parser.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenConfigurationFile", url),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Saves the current ProGuard configuration to the given file.
+ */
+ private void saveConfiguration(File file)
+ {
+ try
+ {
+ // Save the configuration file.
+ ConfigurationWriter writer = new ConfigurationWriter(file);
+ writer.write(getProGuardConfiguration());
+ writer.close();
+ }
+ catch (Exception ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantSaveConfigurationFile", file.getPath()),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * Loads the given stack trace into the GUI.
+ */
+ private void loadStackTrace(String fileName)
+ {
+ try
+ {
+ StringBuffer buffer = new StringBuffer(1024);
+
+ Reader reader = new BufferedReader(new FileReader(fileName));
+ try
+ {
+ while (true)
+ {
+ int c = reader.read();
+ if (c < 0)
+ {
+ break;
+ }
+
+ buffer.append(c);
+ }
+ }
+ finally
+ {
+ reader.close();
+ }
+
+ // Put the stack trace in the text area.
+ stackTraceTextArea.setText(buffer.toString());
+ }
+ catch (IOException ex)
+ {
+ JOptionPane.showMessageDialog(getContentPane(),
+ msg("cantOpenStackTraceFile", fileName),
+ msg("warning"),
+ JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+
+ /**
+ * This ActionListener loads a ProGuard configuration file and initializes
+ * the GUI accordingly.
+ */
+ private class MyLoadConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ configurationChooser.setDialogTitle(msg("selectConfigurationFile"));
+
+ int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ loadConfiguration(configurationChooser.getSelectedFile());
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener saves a ProGuard configuration file based on the
+ * current GUI settings.
+ */
+ private class MySaveConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ configurationChooser.setDialogTitle(msg("saveConfigurationFile"));
+
+ int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this);
+ if (returnVal == JFileChooser.APPROVE_OPTION)
+ {
+ saveConfiguration(configurationChooser.getSelectedFile());
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener displays the ProGuard configuration specified by the
+ * current GUI settings.
+ */
+ private class MyViewConfigurationActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ consoleTextArea.setText("");
+
+ TextAreaOutputStream outputStream =
+ new TextAreaOutputStream(consoleTextArea);
+
+ try
+ {
+ // TODO: write out relative path names and path names with system properties.
+
+ // Write the configuration.
+ ConfigurationWriter writer = new ConfigurationWriter(outputStream);
+ try
+ {
+ writer.write(getProGuardConfiguration());
+ }
+ finally
+ {
+ writer.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ // This shouldn't happen.
+ }
+
+ // Scroll to the top of the configuration.
+ consoleTextArea.setCaretPosition(0);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener executes ProGuard based on the current GUI settings.
+ */
+ private class MyProcessActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ systemOutRedirected = true;
+
+ // Get the informational configuration file name.
+ File configurationFile = configurationChooser.getSelectedFile();
+ String configurationFileName = configurationFile != null ?
+ configurationFile.getName() :
+ msg("sampleConfigurationFileName");
+
+ // Create the ProGuard thread.
+ Thread proGuardThread =
+ new Thread(new ProGuardRunnable(consoleTextArea,
+ getProGuardConfiguration(),
+ configurationFileName));
+
+ // Run it.
+ proGuardThread.start();
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener loads an obfuscated stack trace from a file and puts
+ * it in the proper text area.
+ */
+ private class MyLoadStackTraceActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ fileChooser.setDialogTitle(msg("selectStackTraceFile"));
+ fileChooser.setSelectedFile(null);
+
+ int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this);
+ if (returnValue == JFileChooser.APPROVE_OPTION)
+ {
+ File selectedFile = fileChooser.getSelectedFile();
+ String fileName = selectedFile.getPath();
+
+ loadStackTrace(fileName);
+ }
+ }
+ }
+
+
+ /**
+ * This ActionListener executes ReTrace based on the current GUI settings.
+ */
+ private class MyReTraceActionListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ // Make sure System.out has not been redirected yet.
+ if (!systemOutRedirected)
+ {
+ systemOutRedirected = true;
+
+ boolean verbose = reTraceVerboseCheckBox.isSelected();
+ File retraceMappingFile = new File(reTraceMappingTextField.getText());
+ String stackTrace = stackTraceTextArea.getText();
+
+ // Create the ReTrace runnable.
+ Runnable reTraceRunnable = new ReTraceRunnable(reTraceTextArea,
+ verbose,
+ retraceMappingFile,
+ stackTrace);
+
+ // Run it in this thread, because it won't take long anyway.
+ reTraceRunnable.run();
+ }
+ }
+ }
+
+
+ // Small utility methods.
+
+ /**
+ * Returns the file name of the given file, if any.
+ */
+ private static String fileName(File file)
+ {
+ return file == null ? "" : file.getAbsolutePath();
+ }
+
+
+ /**
+ * Attaches the tool tip from the GUI resources that corresponds to the
+ * given key, to the given component.
+ */
+ private static JComponent tip(JComponent component, String messageKey)
+ {
+ component.setToolTipText(msg(messageKey));
+
+ return component;
+ }
+
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key.
+ */
+ private static String msg(String messageKey)
+ {
+ return GUIResources.getMessage(messageKey);
+ }
+
+
+ /**
+ * Returns the message from the GUI resources that corresponds to the given
+ * key and argument.
+ */
+ private String msg(String messageKey,
+ Object messageArgument)
+ {
+ return GUIResources.getMessage(messageKey, new Object[] {messageArgument});
+ }
+
+
+ /**
+ * The main method for the ProGuard GUI.
+ */
+ public static void main(final String[] args)
+ {
+ try
+ {
+ SwingUtil.invokeAndWait(new Runnable()
+ {
+ public void run()
+ {
+ ProGuardGUI gui = new ProGuardGUI();
+ gui.pack();
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ Dimension guiSize = gui.getSize();
+ gui.setLocation((screenSize.width - guiSize.width) / 2,
+ (screenSize.height - guiSize.height) / 2);
+ gui.show();
+
+ // Start the splash animation, unless specified otherwise.
+ int argIndex = 0;
+ if (argIndex < args.length &&
+ NO_SPLASH_OPTION.startsWith(args[argIndex]))
+ {
+ gui.skipSplash();
+ argIndex++;
+ }
+ else
+ {
+ gui.startSplash();
+ }
+
+ // Load an initial configuration, if specified.
+ if (argIndex < args.length)
+ {
+ gui.loadConfiguration(new File(args[argIndex]));
+ argIndex++;
+ }
+
+ if (argIndex < args.length)
+ {
+ System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]");
+ }
+
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ // Nothing.
+ }
+ }
+}