KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > gui > ProGuardGUI


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.gui;
22
23 import proguard.*;
24 import proguard.classfile.util.ClassUtil;
25 import proguard.gui.splash.*;
26 import proguard.util.ListUtil;
27
28 import javax.swing.*;
29 import javax.swing.border.*;
30 import java.awt.*;
31 import java.awt.image.BufferedImage JavaDoc;
32 import java.awt.event.*;
33 import java.io.*;
34 import java.net.URL JavaDoc;
35 import java.util.*;
36 import java.util.List JavaDoc;
37
38
39 /**
40  * GUI for configuring and executing ProGuard and ReTrace.
41  *
42  * @author Eric Lafortune
43  */

44 public class ProGuardGUI extends JFrame
45 {
46     private static final String JavaDoc NO_SPLASH_OPTION = "-nosplash";
47
48     private static final String JavaDoc TITLE_IMAGE_FILE = "vtitle.gif";
49     private static final String JavaDoc BOILERPLATE_CONFIGURATION = "boilerplate.pro";
50     private static final String JavaDoc DEFAULT_CONFIGURATION = "default.pro";
51
52     private static final String JavaDoc KEEP_ATTRIBUTE_DEFAULT = "InnerClasses,SourceFile,ExceptionsLineNumberTable,Deprecated,Signature,*Annotation*,EnclosingMethod";
53     private static final String JavaDoc SOURCE_FILE_ATTRIBUTE_DEFAULT = "SourceFile";
54     private static final String JavaDoc ADAPT_RESOURCE_FILE_NAMES_DEFAULT = "**.properties";
55     private static final String JavaDoc 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 JFileChooser configurationChooser = new JFileChooser("");
62     private JFileChooser fileChooser = new JFileChooser("");
63
64     private SplashPanel splashPanel;
65
66     private ClassPathPanel programPanel = new ClassPathPanel(this, true);
67     private ClassPathPanel libraryPanel = new ClassPathPanel(this, false);
68
69     private KeepSpecification[] boilerplateKeep;
70     private JCheckBox[] boilerplateKeepCheckBoxes;
71     private JTextField[] boilerplateKeepTextFields;
72
73     private KeepSpecificationsPanel additionalKeepPanel = new KeepSpecificationsPanel(this, true, false, false, false, false);
74
75     private KeepSpecification[] boilerplateKeepNames;
76     private JCheckBox[] boilerplateKeepNamesCheckBoxes;
77     private JTextField[] boilerplateKeepNamesTextFields;
78
79     private KeepSpecificationsPanel additionalKeepNamesPanel = new KeepSpecificationsPanel(this, true, false, true, false, false);
80
81     private ClassSpecification[] boilerplateNoSideEffectMethods;
82     private JCheckBox[] boilerplateNoSideEffectMethodCheckBoxes;
83
84     private ClassSpecificationsPanel additionalNoSideEffectsPanel = new ClassSpecificationsPanel(this, false);
85
86     private ClassSpecificationsPanel whyAreYouKeepingPanel = new ClassSpecificationsPanel(this, false);
87
88     private JCheckBox shrinkCheckBox = new JCheckBox(msg("shrink"));
89     private JCheckBox printUsageCheckBox = new JCheckBox(msg("printUsage"));
90
91     private JCheckBox optimizeCheckBox = new JCheckBox(msg("optimize"));
92     private JCheckBox allowAccessModificationCheckBox = new JCheckBox(msg("allowAccessModification"));
93     private JLabel optimizationPassesLabel = new JLabel(msg("optimizationPasses"));
94     private JSpinner optimizationPassesSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 9, 1));
95
96     private JCheckBox obfuscateCheckBox = new JCheckBox(msg("obfuscate"));
97     private JCheckBox printMappingCheckBox = new JCheckBox(msg("printMapping"));
98     private JCheckBox applyMappingCheckBox = new JCheckBox(msg("applyMapping"));
99     private JCheckBox obfuscationDictionaryCheckBox = new JCheckBox(msg("obfuscationDictionary"));
100     private JCheckBox overloadAggressivelyCheckBox = new JCheckBox(msg("overloadAggressively"));
101     private JCheckBox useUniqueClassMemberNamesCheckBox = new JCheckBox(msg("useUniqueClassMemberNames"));
102     private JCheckBox useMixedCaseClassNamesCheckBox = new JCheckBox(msg("useMixedCaseClassNames"));
103     private JCheckBox flattenPackageHierarchyCheckBox = new JCheckBox(msg("flattenPackageHierarchy"));
104     private JCheckBox repackageClassesCheckBox = new JCheckBox(msg("repackageClasses"));
105     private JCheckBox keepAttributesCheckBox = new JCheckBox(msg("keepAttributes"));
106     private JCheckBox newSourceFileAttributeCheckBox = new JCheckBox(msg("renameSourceFileAttribute"));
107     private JCheckBox adaptResourceFileNamesCheckBox = new JCheckBox(msg("adaptResourceFileNames"));
108     private JCheckBox adaptResourceFileContentsCheckBox = new JCheckBox(msg("adaptResourceFileContents"));
109
110     private JCheckBox preverifyCheckBox = new JCheckBox(msg("preverify"));
111     private JCheckBox microEditionCheckBox = new JCheckBox(msg("microEdition"));
112     private JCheckBox targetCheckBox = new JCheckBox(msg("target"));
113
114     private JComboBox targetComboBox = new JComboBox(ListUtil.commaSeparatedList(msg("targets")).toArray());
115
116     private JCheckBox verboseCheckBox = new JCheckBox(msg("verbose"));
117     private JCheckBox ignoreWarningsCheckBox = new JCheckBox(msg("ignoreWarnings"));
118     private JCheckBox warnCheckBox = new JCheckBox(msg("warn"));
119     private JCheckBox noteCheckBox = new JCheckBox(msg("note"));
120     private JCheckBox skipNonPublicLibraryClassesCheckBox = new JCheckBox(msg("skipNonPublicLibraryClasses"));
121     private JCheckBox skipNonPublicLibraryClassMembersCheckBox = new JCheckBox(msg("skipNonPublicLibraryClassMembers"));
122     private JCheckBox forceProcessingCheckBox = new JCheckBox(msg("forceProcessing"));
123     private JCheckBox printSeedsCheckBox = new JCheckBox(msg("printSeeds"));
124     private JCheckBox printConfigurationCheckBox = new JCheckBox(msg("printConfiguration"));
125     private JCheckBox dumpCheckBox = new JCheckBox(msg("dump"));
126
127     private JTextField printUsageTextField = new JTextField(40);
128     private JTextField printMappingTextField = new JTextField(40);
129     private JTextField applyMappingTextField = new JTextField(40);
130     private JTextField obfuscationDictionaryTextField = new JTextField(40);
131     private JTextField flattenPackageHierarchyTextField = new JTextField(40);
132     private JTextField repackageClassesTextField = new JTextField(40);
133     private JTextField keepAttributesTextField = new JTextField(40);
134     private JTextField newSourceFileAttributeTextField = new JTextField(40);
135     private JTextField adaptResourceFileNamesTextField = new JTextField(40);
136     private JTextField adaptResourceFileContentsTextField = new JTextField(40);
137     private JTextField printSeedsTextField = new JTextField(40);
138     private JTextField printConfigurationTextField = new JTextField(40);
139     private JTextField dumpTextField = new JTextField(40);
140
141     private JTextArea consoleTextArea = new JTextArea(msg("processingInfo"), 3, 40);
142
143     private JCheckBox reTraceVerboseCheckBox = new JCheckBox(msg("verbose"));
144     private JTextField reTraceMappingTextField = new JTextField(40);
145     private JTextArea stackTraceTextArea = new JTextArea(3, 40);
146     private JTextArea reTraceTextArea = new JTextArea(msg("reTraceInfo"), 3, 40);
147
148
149     /**
150      * Creates a new ProGuardGUI.
151      */

152     public ProGuardGUI()
153     {
154         setTitle("ProGuard");
155         setDefaultCloseOperation(EXIT_ON_CLOSE);
156
157         // Create some constraints that can be reused.
158
GridBagConstraints constraints = new GridBagConstraints();
159         constraints.anchor = GridBagConstraints.WEST;
160         constraints.insets = new Insets(0, 4, 0, 4);
161
162         GridBagConstraints constraintsStretch = new GridBagConstraints();
163         constraintsStretch.fill = GridBagConstraints.HORIZONTAL;
164         constraintsStretch.weightx = 1.0;
165         constraintsStretch.anchor = GridBagConstraints.WEST;
166         constraintsStretch.insets = constraints.insets;
167
168         GridBagConstraints constraintsLast = new GridBagConstraints();
169         constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
170         constraintsLast.anchor = GridBagConstraints.WEST;
171         constraintsLast.insets = constraints.insets;
172
173         GridBagConstraints constraintsLastStretch = new GridBagConstraints();
174         constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
175         constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
176         constraintsLastStretch.weightx = 1.0;
177         constraintsLastStretch.anchor = GridBagConstraints.WEST;
178         constraintsLastStretch.insets = constraints.insets;
179
180         GridBagConstraints splashPanelConstraints = new GridBagConstraints();
181         splashPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
182         splashPanelConstraints.fill = GridBagConstraints.BOTH;
183         splashPanelConstraints.weightx = 1.0;
184         splashPanelConstraints.weighty = 0.02;
185         splashPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
186         //splashPanelConstraints.insets = constraints.insets;
187

188         GridBagConstraints welcomeTextAreaConstraints = new GridBagConstraints();
189         welcomeTextAreaConstraints.gridwidth = GridBagConstraints.REMAINDER;
190         welcomeTextAreaConstraints.fill = GridBagConstraints.NONE;
191         welcomeTextAreaConstraints.weightx = 1.0;
192         welcomeTextAreaConstraints.weighty = 0.01;
193         welcomeTextAreaConstraints.anchor = GridBagConstraints.CENTER;//NORTHWEST;
194
welcomeTextAreaConstraints.insets = new Insets(20, 40, 20, 40);
195
196         GridBagConstraints panelConstraints = new GridBagConstraints();
197         panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
198         panelConstraints.fill = GridBagConstraints.HORIZONTAL;
199         panelConstraints.weightx = 1.0;
200         panelConstraints.anchor = GridBagConstraints.NORTHWEST;
201         panelConstraints.insets = constraints.insets;
202
203         GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
204         stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
205         stretchPanelConstraints.fill = GridBagConstraints.BOTH;
206         stretchPanelConstraints.weightx = 1.0;
207         stretchPanelConstraints.weighty = 1.0;
208         stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST;
209         stretchPanelConstraints.insets = constraints.insets;
210
211         GridBagConstraints glueConstraints = new GridBagConstraints();
212         glueConstraints.fill = GridBagConstraints.BOTH;
213         glueConstraints.weightx = 0.01;
214         glueConstraints.weighty = 0.01;
215         glueConstraints.anchor = GridBagConstraints.NORTHWEST;
216         glueConstraints.insets = constraints.insets;
217
218         GridBagConstraints bottomButtonConstraints = new GridBagConstraints();
219         bottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
220         bottomButtonConstraints.insets = new Insets(2, 2, 4, 6);
221         bottomButtonConstraints.ipadx = 10;
222         bottomButtonConstraints.ipady = 2;
223
224         GridBagConstraints lastBottomButtonConstraints = new GridBagConstraints();
225         lastBottomButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
226         lastBottomButtonConstraints.anchor = GridBagConstraints.SOUTHEAST;
227         lastBottomButtonConstraints.insets = bottomButtonConstraints.insets;
228         lastBottomButtonConstraints.ipadx = bottomButtonConstraints.ipadx;
229         lastBottomButtonConstraints.ipady = bottomButtonConstraints.ipady;
230
231         // Leave room for a growBox on Mac OS X.
232
if (System.getProperty("os.name").toLowerCase().startsWith("mac os x"))
233         {
234             lastBottomButtonConstraints.insets = new Insets(2, 2, 4, 6 + 16);
235         }
236
237         GridBagLayout layout = new GridBagLayout();
238
239         configurationChooser.addChoosableFileFilter(
240             new ExtensionFileFilter(msg("proExtension"), new String JavaDoc[] { ".pro" }));
241
242         // Create the opening panel.
243
Sprite splash =
244             new CompositeSprite(new Sprite[]
245         {
246             new ColorSprite(new ConstantColor(Color.gray),
247             new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 90)),
248             new TextSprite(new ConstantString("ProGuard"),
249                            new ConstantInt(160),
250                            new LinearInt(-10, 120, new SmoothTiming(500, 1000))))),
251
252             new ColorSprite(new ConstantColor(Color.white),
253             new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 45)),
254             new ShadowedSprite(new ConstantInt(3),
255                                new ConstantInt(3),
256                                new ConstantDouble(0.4),
257                                new ConstantInt(1),
258                                new CompositeSprite(new Sprite[]
259             {
260                 new TextSprite(new ConstantString(msg("shrinking")),
261                                new LinearInt(1000, 60, new SmoothTiming(1000, 2000)),
262                                new ConstantInt(70)),
263                 new TextSprite(new ConstantString(msg("optimization")),
264                                new LinearInt(1000, 400, new SmoothTiming(1500, 2500)),
265                                new ConstantInt(60)),
266                 new TextSprite(new ConstantString(msg("obfuscation")),
267                                new LinearInt(1000, 10, new SmoothTiming(2000, 3000)),
268                                new ConstantInt(145)),
269                 new TextSprite(new ConstantString(msg("preverification")),
270                                new LinearInt(1000, 350, new SmoothTiming(2500, 3500)),
271                                new ConstantInt(140)),
272                 new FontSprite(new ConstantFont(new Font("sansserif", Font.BOLD, 30)),
273                 new TextSprite(new TypeWriterString(msg("developed"), new LinearTiming(3500, 5500)),
274                                new ConstantInt(250),
275                                new ConstantInt(200))),
276             })))),
277         });
278         splashPanel = new SplashPanel(splash, 0.5, 5500L);
279         splashPanel.setPreferredSize(new Dimension(0, 200));
280
281         JTextArea welcomeTextArea = new JTextArea(msg("proGuardInfo"), 18, 50);
282         welcomeTextArea.setOpaque(false);
283         welcomeTextArea.setEditable(false);
284         welcomeTextArea.setLineWrap(true);
285         welcomeTextArea.setWrapStyleWord(true);
286         welcomeTextArea.setPreferredSize(new Dimension(0, 0));
287         welcomeTextArea.setBorder(new EmptyBorder(20, 20, 20, 20));
288         addBorder(welcomeTextArea, "welcome");
289
290         JPanel proGuardPanel = new JPanel(layout);
291         proGuardPanel.add(splashPanel, splashPanelConstraints);
292         proGuardPanel.add(welcomeTextArea, welcomeTextAreaConstraints);
293
294         // Create the input panel.
295
// TODO: properly clone the ClassPath objects.
296
// This is awkward to implement in the generic ListPanel.addElements(...)
297
// method, since the Object.clone() method is not public.
298
programPanel.addCopyToPanelButton(msg("moveToLibraries"), libraryPanel);
299         libraryPanel.addCopyToPanelButton(msg("moveToProgram"), programPanel);
300
301         // Collect all buttons of these panels and make sure they are equally
302
// sized.
303
List JavaDoc panelButtons = new ArrayList();
304         panelButtons.addAll(programPanel.getButtons());
305         panelButtons.addAll(libraryPanel.getButtons());
306         setCommonPreferredSize(panelButtons);
307         panelButtons = null;
308
309         addBorder(programPanel, "programJars" );
310         addBorder(libraryPanel, "libraryJars" );
311
312         JPanel inputOutputPanel = new JPanel(layout);
313         inputOutputPanel.add(programPanel, stretchPanelConstraints);
314         inputOutputPanel.add(libraryPanel, stretchPanelConstraints);
315
316         // Load the boiler plate options.
317
loadBoilerplateConfiguration();
318
319         // Create the boiler plate keep panels.
320
boilerplateKeepCheckBoxes = new JCheckBox[boilerplateKeep.length];
321         boilerplateKeepTextFields = new JTextField[boilerplateKeep.length];
322
323         JButton printUsageBrowseButton = createBrowseButton(printUsageTextField,
324                                                               msg("selectUsageFile"));
325
326         JPanel shrinkingOptionsPanel = new JPanel(layout);
327         addBorder(shrinkingOptionsPanel, "options");
328
329         shrinkingOptionsPanel.add(shrinkCheckBox, constraintsLastStretch);
330         shrinkingOptionsPanel.add(printUsageCheckBox, constraints);
331         shrinkingOptionsPanel.add(printUsageTextField, constraintsStretch);
332         shrinkingOptionsPanel.add(printUsageBrowseButton, constraintsLast);
333
334         JPanel shrinkingPanel = new JPanel(layout);
335
336         shrinkingPanel.add(shrinkingOptionsPanel, panelConstraints);
337         addClassSpecifications(extractClassSpecifications(boilerplateKeep),
338                                shrinkingPanel,
339                                boilerplateKeepCheckBoxes,
340                                boilerplateKeepTextFields);
341
342         addBorder(additionalKeepPanel, "keepAdditional");
343         shrinkingPanel.add(additionalKeepPanel, stretchPanelConstraints);
344
345         // Create the boiler plate keep names panels.
346
boilerplateKeepNamesCheckBoxes = new JCheckBox[boilerplateKeepNames.length];
347         boilerplateKeepNamesTextFields = new JTextField[boilerplateKeepNames.length];
348
349         JButton printMappingBrowseButton = createBrowseButton(printMappingTextField,
350                                                               msg("selectPrintMappingFile"));
351         JButton applyMappingBrowseButton = createBrowseButton(applyMappingTextField,
352                                                               msg("selectApplyMappingFile"));
353         JButton obfucationDictionaryBrowseButton = createBrowseButton(obfuscationDictionaryTextField,
354                                                                       msg("selectObfuscationDictionaryFile"));
355
356         JPanel obfuscationOptionsPanel = new JPanel(layout);
357         addBorder(obfuscationOptionsPanel, "options");
358
359         obfuscationOptionsPanel.add(obfuscateCheckBox, constraintsLastStretch);
360         obfuscationOptionsPanel.add(printMappingCheckBox, constraints);
361         obfuscationOptionsPanel.add(printMappingTextField, constraintsStretch);
362         obfuscationOptionsPanel.add(printMappingBrowseButton, constraintsLast);
363         obfuscationOptionsPanel.add(applyMappingCheckBox, constraints);
364         obfuscationOptionsPanel.add(applyMappingTextField, constraintsStretch);
365         obfuscationOptionsPanel.add(applyMappingBrowseButton, constraintsLast);
366         obfuscationOptionsPanel.add(obfuscationDictionaryCheckBox, constraints);
367         obfuscationOptionsPanel.add(obfuscationDictionaryTextField, constraintsStretch);
368         obfuscationOptionsPanel.add(obfucationDictionaryBrowseButton, constraintsLast);
369         obfuscationOptionsPanel.add(overloadAggressivelyCheckBox, constraintsLastStretch);
370         obfuscationOptionsPanel.add(useUniqueClassMemberNamesCheckBox, constraintsLastStretch);
371         obfuscationOptionsPanel.add(useMixedCaseClassNamesCheckBox, constraintsLastStretch);
372         obfuscationOptionsPanel.add(flattenPackageHierarchyCheckBox, constraints);
373         obfuscationOptionsPanel.add(flattenPackageHierarchyTextField, constraintsLastStretch);
374         obfuscationOptionsPanel.add(repackageClassesCheckBox, constraints);
375         obfuscationOptionsPanel.add(repackageClassesTextField, constraintsLastStretch);
376         obfuscationOptionsPanel.add(keepAttributesCheckBox, constraints);
377         obfuscationOptionsPanel.add(keepAttributesTextField, constraintsLastStretch);
378         obfuscationOptionsPanel.add(newSourceFileAttributeCheckBox, constraints);
379         obfuscationOptionsPanel.add(newSourceFileAttributeTextField, constraintsLastStretch);
380         obfuscationOptionsPanel.add(adaptResourceFileNamesCheckBox, constraints);
381         obfuscationOptionsPanel.add(adaptResourceFileNamesTextField, constraintsLastStretch);
382         obfuscationOptionsPanel.add(adaptResourceFileContentsCheckBox, constraints);
383         obfuscationOptionsPanel.add(adaptResourceFileContentsTextField, constraintsLastStretch);
384
385         JPanel obfuscationPanel = new JPanel(layout);
386
387         obfuscationPanel.add(obfuscationOptionsPanel, panelConstraints);
388         addClassSpecifications(extractClassSpecifications(boilerplateKeepNames),
389                                obfuscationPanel,
390                                boilerplateKeepNamesCheckBoxes,
391                                boilerplateKeepNamesTextFields);
392
393         addBorder(additionalKeepNamesPanel, "keepNamesAdditional");
394         obfuscationPanel.add(additionalKeepNamesPanel, stretchPanelConstraints);
395
396         // Create the boiler plate "no side effect methods" panels.
397
boilerplateNoSideEffectMethodCheckBoxes = new JCheckBox[boilerplateNoSideEffectMethods.length];
398
399         JPanel optimizationOptionsPanel = new JPanel(layout);
400         addBorder(optimizationOptionsPanel, "options");
401
402         optimizationOptionsPanel.add(optimizeCheckBox, constraintsLastStretch);
403         optimizationOptionsPanel.add(allowAccessModificationCheckBox, constraintsLastStretch);
404         optimizationOptionsPanel.add(optimizationPassesLabel, constraints);
405         optimizationOptionsPanel.add(optimizationPassesSpinner, constraintsLast);
406
407         JPanel optimizationPanel = new JPanel(layout);
408
409         optimizationPanel.add(optimizationOptionsPanel, panelConstraints);
410         addClassSpecifications(boilerplateNoSideEffectMethods,
411                                optimizationPanel,
412                                boilerplateNoSideEffectMethodCheckBoxes,
413                                null);
414
415         addBorder(additionalNoSideEffectsPanel, "assumeNoSideEffectsAdditional");
416         optimizationPanel.add(additionalNoSideEffectsPanel, stretchPanelConstraints);
417
418         // Create the options panel.
419
JPanel preverificationOptionsPanel = new JPanel(layout);
420         addBorder(preverificationOptionsPanel, "preverificationAndTargeting");
421
422         preverificationOptionsPanel.add(preverifyCheckBox, constraintsLastStretch);
423         preverificationOptionsPanel.add(microEditionCheckBox, constraintsLastStretch);
424         preverificationOptionsPanel.add(targetCheckBox, constraints);
425         preverificationOptionsPanel.add(targetComboBox, constraintsLast);
426
427         JButton printSeedsBrowseButton =
428             createBrowseButton(printSeedsTextField, msg("selectSeedsFile"));
429
430         JButton printConfigurationBrowseButton =
431             createBrowseButton(printConfigurationTextField, msg( "selectConfigurationFile"));
432
433         JButton dumpBrowseButton =
434             createBrowseButton(dumpTextField, msg("selectDumpFile"));
435
436         // Select the most recent target by default.
437
targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1);
438
439         JPanel consistencyPanel = new JPanel(layout);
440         addBorder(consistencyPanel, "consistencyAndCorrectness");
441
442         consistencyPanel.add(verboseCheckBox, constraintsLastStretch);
443         consistencyPanel.add(noteCheckBox, constraintsLastStretch);
444         consistencyPanel.add(warnCheckBox, constraintsLastStretch);
445         consistencyPanel.add(ignoreWarningsCheckBox, constraintsLastStretch);
446         consistencyPanel.add(skipNonPublicLibraryClassesCheckBox, constraintsLastStretch);
447         consistencyPanel.add(skipNonPublicLibraryClassMembersCheckBox, constraintsLastStretch);
448         consistencyPanel.add(forceProcessingCheckBox, constraintsLastStretch);
449         consistencyPanel.add(printSeedsCheckBox, constraints);
450         consistencyPanel.add(printSeedsTextField, constraintsStretch);
451         consistencyPanel.add(printSeedsBrowseButton, constraintsLast);
452         consistencyPanel.add(printConfigurationCheckBox, constraints);
453         consistencyPanel.add(printConfigurationTextField, constraintsStretch);
454         consistencyPanel.add(printConfigurationBrowseButton, constraintsLast);
455         consistencyPanel.add(dumpCheckBox, constraints);
456         consistencyPanel.add(dumpTextField, constraintsStretch);
457         consistencyPanel.add(dumpBrowseButton, constraintsLast);
458
459         // Collect all components that are followed by text fields and make
460
// sure they are equally sized. That way the text fields start at the
461
// same horizontal position.
462
setCommonPreferredSize(Arrays.asList(new JComponent[] {
463             printMappingCheckBox,
464             applyMappingCheckBox,
465             flattenPackageHierarchyCheckBox,
466             repackageClassesCheckBox,
467             newSourceFileAttributeCheckBox,
468         }));
469
470         JPanel optionsPanel = new JPanel(layout);
471
472         optionsPanel.add(preverificationOptionsPanel, panelConstraints);
473         optionsPanel.add(consistencyPanel, panelConstraints);
474
475         addBorder(whyAreYouKeepingPanel, "whyAreYouKeeping");
476         optionsPanel.add(whyAreYouKeepingPanel, stretchPanelConstraints);
477
478         // Create the process panel.
479
consoleTextArea.setOpaque(false);
480         consoleTextArea.setEditable(false);
481         consoleTextArea.setLineWrap(false);
482         consoleTextArea.setWrapStyleWord(false);
483         JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea);
484         consoleScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
485         addBorder(consoleScrollPane, "processingConsole");
486
487         JPanel processPanel = new JPanel(layout);
488         processPanel.add(consoleScrollPane, stretchPanelConstraints);
489
490         // Create the load, save, and process buttons.
491
JButton loadButton = new JButton(msg("loadConfiguration"));
492         loadButton.addActionListener(new MyLoadConfigurationActionListener());
493
494         JButton viewButton = new JButton(msg("viewConfiguration"));
495         viewButton.addActionListener(new MyViewConfigurationActionListener());
496
497         JButton saveButton = new JButton(msg("saveConfiguration"));
498         saveButton.addActionListener(new MySaveConfigurationActionListener());
499
500         JButton processButton = new JButton(msg("process"));
501         processButton.addActionListener(new MyProcessActionListener());
502
503         // Create the ReTrace panel.
504
JPanel reTraceSettingsPanel = new JPanel(layout);
505         addBorder(reTraceSettingsPanel, "reTraceSettings");
506
507         JButton reTraceMappingBrowseButton = createBrowseButton(reTraceMappingTextField,
508                                                                 msg("selectApplyMappingFile"));
509
510         JLabel reTraceMappingLabel = new JLabel(msg("mappingFile"));
511         reTraceMappingLabel.setForeground(reTraceVerboseCheckBox.getForeground());
512
513         reTraceSettingsPanel.add(reTraceVerboseCheckBox, constraintsLastStretch);
514         reTraceSettingsPanel.add(reTraceMappingLabel, constraints);
515         reTraceSettingsPanel.add(reTraceMappingTextField, constraintsStretch);
516         reTraceSettingsPanel.add(reTraceMappingBrowseButton, constraintsLast);
517
518         stackTraceTextArea.setOpaque(true);
519         stackTraceTextArea.setEditable(true);
520         stackTraceTextArea.setLineWrap(false);
521         stackTraceTextArea.setWrapStyleWord(true);
522         JScrollPane stackTraceScrollPane = new JScrollPane(stackTraceTextArea);
523         addBorder(stackTraceScrollPane, "obfuscatedStackTrace");
524
525         reTraceTextArea.setOpaque(false);
526         reTraceTextArea.setEditable(false);
527         reTraceTextArea.setLineWrap(true);
528         reTraceTextArea.setWrapStyleWord(true);
529         JScrollPane reTraceScrollPane = new JScrollPane(reTraceTextArea);
530         reTraceScrollPane.setBorder(new EmptyBorder(1, 1, 1, 1));
531         addBorder(reTraceScrollPane, "deobfuscatedStackTrace");
532
533         JPanel reTracePanel = new JPanel(layout);
534         reTracePanel.add(reTraceSettingsPanel, panelConstraints);
535         reTracePanel.add(stackTraceScrollPane, panelConstraints);
536         reTracePanel.add(reTraceScrollPane, stretchPanelConstraints);
537
538         // Create the load button.
539
JButton loadStackTraceButton = new JButton(msg("loadStackTrace"));
540         loadStackTraceButton.addActionListener(new MyLoadStackTraceActionListener());
541
542         JButton reTraceButton = new JButton(msg("reTrace"));
543         reTraceButton.addActionListener(new MyReTraceActionListener());
544
545         // Create the main tabbed pane.
546
TabbedPane tabs = new TabbedPane();
547         tabs.add(msg("proGuardTab"), proGuardPanel);
548         tabs.add(msg("inputOutputTab"), inputOutputPanel);
549         tabs.add(msg("shrinkingTab"), shrinkingPanel);
550         tabs.add(msg("obfuscationTab"), obfuscationPanel);
551         tabs.add(msg("optimizationTab"), optimizationPanel);
552         tabs.add(msg("informationTab"), optionsPanel);
553         tabs.add(msg("processTab"), processPanel);
554         tabs.add(msg("reTraceTab"), reTracePanel);
555         tabs.addImage(Toolkit.getDefaultToolkit().getImage(
556             this.getClass().getResource(TITLE_IMAGE_FILE)));
557
558         // Add the bottom buttons to each panel.
559
proGuardPanel .add(Box.createGlue(), glueConstraints);
560         proGuardPanel .add(loadButton, bottomButtonConstraints);
561         proGuardPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
562
563         inputOutputPanel .add(Box.createGlue(), glueConstraints);
564         inputOutputPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
565         inputOutputPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
566
567         shrinkingPanel .add(Box.createGlue(), glueConstraints);
568         shrinkingPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
569         shrinkingPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
570
571         obfuscationPanel .add(Box.createGlue(), glueConstraints);
572         obfuscationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
573         obfuscationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
574
575         optimizationPanel .add(Box.createGlue(), glueConstraints);
576         optimizationPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
577         optimizationPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
578
579         optionsPanel .add(Box.createGlue(), glueConstraints);
580         optionsPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
581         optionsPanel .add(createNextButton(tabs), lastBottomButtonConstraints);
582
583         processPanel .add(Box.createGlue(), glueConstraints);
584         processPanel .add(createPreviousButton(tabs), bottomButtonConstraints);
585         processPanel .add(viewButton, bottomButtonConstraints);
586         processPanel .add(saveButton, bottomButtonConstraints);
587         processPanel .add(processButton, lastBottomButtonConstraints);
588
589         reTracePanel .add(Box.createGlue(), glueConstraints);
590         reTracePanel .add(loadStackTraceButton, bottomButtonConstraints);
591         reTracePanel .add(reTraceButton, lastBottomButtonConstraints);
592
593         // Initialize the GUI settings to reasonable defaults.
594
loadConfiguration(this.getClass().getResource(DEFAULT_CONFIGURATION));
595
596         // Add the main tabs to the frame and pack it.
597
getContentPane().add(tabs);
598     }
599
600
601     public void startSplash()
602     {
603         splashPanel.start();
604     }
605
606
607     public void skipSplash()
608     {
609         splashPanel.stop();
610     }
611
612
613     /**
614      * Loads the boilerplate keep class options from the boilerplate file
615      * into the boilerplate array.
616      */

617     private void loadBoilerplateConfiguration()
618     {
619         try
620         {
621             // Parse the boilerplate configuration file.
622
ConfigurationParser parser = new ConfigurationParser(
623                 this.getClass().getResource(BOILERPLATE_CONFIGURATION));
624             Configuration configuration = new Configuration();
625
626             try
627             {
628                 parser.parse(configuration);
629
630                 // We're interested in the keep options.
631
boilerplateKeep =
632                     extractKeepSpecifications(configuration.keep, false, false);
633
634                 // We're interested in the keep options.
635
boilerplateKeepNames =
636                     extractKeepSpecifications(configuration.keep, true, false);
637
638                 // We're interested in the side effects options.
639
boilerplateNoSideEffectMethods = new ClassSpecification[configuration.assumeNoSideEffects.size()];
640                 configuration.assumeNoSideEffects.toArray(boilerplateNoSideEffectMethods);
641             }
642             finally
643             {
644                 parser.close();
645             }
646         }
647         catch (Exception JavaDoc ex)
648         {
649             ex.printStackTrace();
650         }
651     }
652
653
654     /**
655      * Returns an array containing the ClassSpecifications instances with
656      * matching flags.
657      */

658     private KeepSpecification[] extractKeepSpecifications(List JavaDoc keepSpecifications,
659                                                           boolean allowShrinking,
660                                                           boolean allowObfuscation)
661     {
662         List JavaDoc matches = new ArrayList();
663
664         for (int index = 0; index < keepSpecifications.size(); index++)
665         {
666             KeepSpecification keepSpecification = (KeepSpecification)keepSpecifications.get(index);
667             if (keepSpecification.allowShrinking == allowShrinking &&
668                 keepSpecification.allowObfuscation == allowObfuscation)
669             {
670                  matches.add(keepSpecification);
671             }
672         }
673
674         KeepSpecification[] matchingKeepSpecifications = new KeepSpecification[matches.size()];
675         matches.toArray(matchingKeepSpecifications);
676
677         return matchingKeepSpecifications;
678     }
679
680
681     /**
682      * Returns an array containing the ClassSpecification instances of the
683      * given array of KeepSpecification instances.
684      */

685     private ClassSpecification[] extractClassSpecifications(KeepSpecification[] keepSpecifications)
686     {
687         ClassSpecification[] classSpecifications = new ClassSpecification[keepSpecifications.length];
688
689         for (int index = 0; index < classSpecifications.length; index++)
690         {
691             classSpecifications[index] = keepSpecifications[index];
692         }
693
694         return classSpecifications;
695     }
696
697
698     /**
699      * Creates a panel with the given boiler plate class specifications.
700      */

701     private void addClassSpecifications(ClassSpecification[] boilerplateClassSpecifications,
702                                         JPanel classSpecificationsPanel,
703                                         JCheckBox[] boilerplateCheckBoxes,
704                                         JTextField[] boilerplateTextFields)
705     {
706         // Create some constraints that can be reused.
707
GridBagConstraints constraints = new GridBagConstraints();
708         constraints.anchor = GridBagConstraints.WEST;
709         constraints.insets = new Insets(0, 4, 0, 4);
710
711         GridBagConstraints constraintsLastStretch = new GridBagConstraints();
712         constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
713         constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL;
714         constraintsLastStretch.weightx = 1.0;
715         constraintsLastStretch.anchor = GridBagConstraints.WEST;
716         constraintsLastStretch.insets = constraints.insets;
717
718         GridBagConstraints panelConstraints = new GridBagConstraints();
719         panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
720         panelConstraints.fill = GridBagConstraints.HORIZONTAL;
721         panelConstraints.weightx = 1.0;
722         panelConstraints.anchor = GridBagConstraints.NORTHWEST;
723         panelConstraints.insets = constraints.insets;
724
725         GridBagLayout layout = new GridBagLayout();
726
727         String JavaDoc lastPanelName = null;
728         JPanel keepSubpanel = null;
729         for (int index = 0; index < boilerplateClassSpecifications.length; index++)
730         {
731             // The panel structure is derived from the comments.
732
String JavaDoc comments = boilerplateClassSpecifications[index].comments;
733             int dashIndex = comments.indexOf('-');
734             int periodIndex = comments.indexOf('.', dashIndex);
735             String JavaDoc panelName = comments.substring(0, dashIndex).trim();
736             String JavaDoc optionName = comments.substring(dashIndex + 1, periodIndex).trim();
737             if (!panelName.equals(lastPanelName))
738             {
739                 // Create a new keep subpanel and add it.
740
keepSubpanel = new JPanel(layout);
741                 String JavaDoc titleKey = "boilerplate_" + panelName.toLowerCase().replace(' ', '_');
742                 addBorder(keepSubpanel, titleKey);
743                 classSpecificationsPanel.add(keepSubpanel, panelConstraints);
744
745                 lastPanelName = panelName;
746             }
747
748             // Add the check box to the subpanel.
749
String JavaDoc messageKey = "boilerplate_" + optionName.toLowerCase().replace(' ', '_');
750             boilerplateCheckBoxes[index] = new JCheckBox(msg(messageKey));
751             keepSubpanel.add(boilerplateCheckBoxes[index],
752                              boilerplateTextFields != null ?
753                                  constraints :
754                                  constraintsLastStretch);
755
756             if (boilerplateTextFields != null)
757             {
758                 // Add the text field to the subpanel.
759
boilerplateTextFields[index] = new JTextField(40);
760                 keepSubpanel.add(boilerplateTextFields[index], constraintsLastStretch);
761             }
762         }
763     }
764
765
766     /**
767      * Adds a standard border with the title that corresponds to the given key
768      * in the GUI resources.
769      */

770     private void addBorder(JComponent component, String JavaDoc titleKey)
771     {
772         Border oldBorder = component.getBorder();
773         Border newBorder = BorderFactory.createTitledBorder(BORDER, msg(titleKey));
774
775         component.setBorder(oldBorder == null ?
776             newBorder :
777             new CompoundBorder(newBorder, oldBorder));
778     }
779
780
781     /**
782      * Creates a Previous button for the given tabbed pane.
783      */

784     private JButton createPreviousButton(final TabbedPane tabbedPane)
785     {
786         JButton browseButton = new JButton(msg("previous"));
787         browseButton.addActionListener(new ActionListener()
788         {
789             public void actionPerformed(ActionEvent e)
790             {
791                 tabbedPane.previous();
792             }
793         });
794
795         return browseButton;
796     }
797
798
799     /**
800      * Creates a Next button for the given tabbed pane.
801      */

802     private JButton createNextButton(final TabbedPane tabbedPane)
803     {
804         JButton browseButton = new JButton(msg("next"));
805         browseButton.addActionListener(new ActionListener()
806         {
807             public void actionPerformed(ActionEvent e)
808             {
809                 tabbedPane.next();
810             }
811         });
812
813         return browseButton;
814     }
815
816
817     /**
818      * Creates a browse button that opens a file browser for the given text field.
819      */

820     private JButton createBrowseButton(final JTextField textField,
821                                        final String JavaDoc title)
822     {
823         JButton browseButton = new JButton(msg("browse"));
824         browseButton.addActionListener(new ActionListener()
825         {
826             public void actionPerformed(ActionEvent e)
827             {
828                 fileChooser.setDialogTitle(title);
829                 fileChooser.setSelectedFile(new File(textField.getText()));
830
831                 int returnVal = fileChooser.showDialog(ProGuardGUI.this, msg("ok"));
832                 if (returnVal == JFileChooser.APPROVE_OPTION)
833                 {
834                     textField.setText(fileChooser.getSelectedFile().getPath());
835                 }
836             }
837         });
838
839         return browseButton;
840     }
841
842
843     /**
844      * Sets the preferred sizes of the given components to the maximum of their
845      * current preferred sizes.
846      */

847     private void setCommonPreferredSize(List JavaDoc components)
848     {
849         // Find the maximum preferred size.
850
Dimension maximumSize = null;
851         for (int index = 0; index < components.size(); index++)
852         {
853             JComponent component = (JComponent)components.get(index);
854             Dimension size = component.getPreferredSize();
855             if (maximumSize == null ||
856                 size.getWidth() > maximumSize.getWidth())
857             {
858                 maximumSize = size;
859             }
860         }
861
862         // Set the size that we found as the preferred size for all components.
863
for (int index = 0; index < components.size(); index++)
864         {
865             JComponent component = (JComponent)components.get(index);
866             component.setPreferredSize(maximumSize);
867         }
868     }
869
870
871     /**
872      * Updates to GUI settings to reflect the given ProGuard configuration.
873      */

874     private void setProGuardConfiguration(Configuration configuration)
875     {
876         // Set up the input and output jars and directories.
877
programPanel.setClassPath(configuration.programJars);
878         libraryPanel.setClassPath(configuration.libraryJars);
879
880         // Set up the boilerplate keep options.
881
for (int index = 0; index < boilerplateKeep.length; index++)
882         {
883             String JavaDoc classNames =
884                 findMatchingKeepSpecifications(boilerplateKeep[index],
885                                                configuration.keep);
886
887             boilerplateKeepCheckBoxes[index].setSelected(classNames != null);
888             boilerplateKeepTextFields[index].setText(classNames == null ? "*" : classNames);
889         }
890
891
892         // Set up the boilerplate keep names options.
893
for (int index = 0; index < boilerplateKeepNames.length; index++)
894         {
895             String JavaDoc classNames =
896                 findMatchingKeepSpecifications(boilerplateKeepNames[index],
897                                                configuration.keep);
898
899             boilerplateKeepNamesCheckBoxes[index].setSelected(classNames != null);
900             boilerplateKeepNamesTextFields[index].setText(classNames == null ? "*" : classNames);
901         }
902
903         // Set up the additional keep options. Note that the matched boilerplate
904
// options have been removed from the list.
905
additionalKeepPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep,
906                                                                               false));
907
908         // Set up the additional keep options. Note that the matched boilerplate
909
// options have been removed from the list.
910
additionalKeepNamesPanel.setClassSpecifications(filteredKeepSpecifications(configuration.keep,
911                                                                                    true));
912
913
914         // Set up the boilerplate "no side effect methods" options.
915
for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
916         {
917             boolean found =
918                 findClassSpecification(boilerplateNoSideEffectMethods[index],
919                                        configuration.assumeNoSideEffects);
920
921             boilerplateNoSideEffectMethodCheckBoxes[index].setSelected(found);
922         }
923
924         // Set up the additional keep options. Note that the matched boilerplate
925
// options have been removed from the list.
926
additionalNoSideEffectsPanel.setClassSpecifications(configuration.assumeNoSideEffects);
927
928         // Set up the "why are you keeping" options.
929
whyAreYouKeepingPanel.setClassSpecifications(configuration.whyAreYouKeeping);
930
931         // Set up the other options.
932
shrinkCheckBox .setSelected(configuration.shrink);
933         printUsageCheckBox .setSelected(configuration.printUsage != null);
934
935         optimizeCheckBox .setSelected(configuration.optimize);
936         optimizationPassesSpinner.getModel() .setValue(new Integer JavaDoc(configuration.optimizationPasses));
937         allowAccessModificationCheckBox .setSelected(configuration.allowAccessModification);
938
939         obfuscateCheckBox .setSelected(configuration.obfuscate);
940         printMappingCheckBox .setSelected(configuration.printMapping != null);
941         applyMappingCheckBox .setSelected(configuration.applyMapping != null);
942         obfuscationDictionaryCheckBox .setSelected(configuration.obfuscationDictionary != null);
943         overloadAggressivelyCheckBox .setSelected(configuration.overloadAggressively);
944         useUniqueClassMemberNamesCheckBox .setSelected(configuration.useUniqueClassMemberNames);
945         useMixedCaseClassNamesCheckBox .setSelected(configuration.useMixedCaseClassNames);
946         flattenPackageHierarchyCheckBox .setSelected(configuration.flattenPackageHierarchy != null);
947         repackageClassesCheckBox .setSelected(configuration.repackageClasses != null);
948         keepAttributesCheckBox .setSelected(configuration.keepAttributes != null);
949         newSourceFileAttributeCheckBox .setSelected(configuration.newSourceFileAttribute != null);
950         adaptResourceFileNamesCheckBox .setSelected(configuration.adaptResourceFileNames != null);
951         adaptResourceFileContentsCheckBox .setSelected(configuration.adaptResourceFileContents != null);
952
953         preverifyCheckBox .setSelected(configuration.preverify);
954         microEditionCheckBox .setSelected(configuration.microEdition);
955         targetCheckBox .setSelected(configuration.targetClassVersion != 0);
956
957         verboseCheckBox .setSelected(configuration.verbose);
958         noteCheckBox .setSelected(configuration.note);
959         warnCheckBox .setSelected(configuration.warn);
960         ignoreWarningsCheckBox .setSelected(configuration.ignoreWarnings);
961         skipNonPublicLibraryClassesCheckBox .setSelected(configuration.skipNonPublicLibraryClasses);
962         skipNonPublicLibraryClassMembersCheckBox.setSelected(configuration.skipNonPublicLibraryClassMembers);
963         forceProcessingCheckBox .setSelected(configuration.lastModified == Long.MAX_VALUE);
964         printSeedsCheckBox .setSelected(configuration.printSeeds != null);
965         printConfigurationCheckBox .setSelected(configuration.printConfiguration != null);
966         dumpCheckBox .setSelected(configuration.dump != null);
967
968         printUsageTextField .setText(fileName(configuration.printUsage));
969         printMappingTextField .setText(fileName(configuration.printMapping));
970         applyMappingTextField .setText(fileName(configuration.applyMapping));
971         obfuscationDictionaryTextField .setText(fileName(configuration.obfuscationDictionary));
972         flattenPackageHierarchyTextField .setText(configuration.flattenPackageHierarchy);
973         repackageClassesTextField .setText(configuration.repackageClasses);
974         keepAttributesTextField .setText(configuration.keepAttributes == null ? KEEP_ATTRIBUTE_DEFAULT : ListUtil.commaSeparatedString(configuration.keepAttributes));
975         newSourceFileAttributeTextField .setText(configuration.newSourceFileAttribute == null ? SOURCE_FILE_ATTRIBUTE_DEFAULT : configuration.newSourceFileAttribute);
976         adaptResourceFileNamesTextField .setText(configuration.adaptResourceFileNames == null ? ADAPT_RESOURCE_FILE_NAMES_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileNames));
977         adaptResourceFileContentsTextField .setText(configuration.adaptResourceFileContents == null ? ADAPT_RESOURCE_FILE_CONTENTS_DEFAULT : ListUtil.commaSeparatedString(configuration.adaptResourceFileContents));
978         printSeedsTextField .setText(fileName(configuration.printSeeds));
979         printConfigurationTextField .setText(fileName(configuration.printConfiguration));
980         dumpTextField .setText(fileName(configuration.dump));
981
982         if (configuration.targetClassVersion != 0)
983         {
984             targetComboBox.setSelectedItem(ClassUtil.externalClassVersion(configuration.targetClassVersion));
985         }
986         else
987         {
988             targetComboBox.setSelectedIndex(targetComboBox.getItemCount() - 1);
989         }
990
991         if (configuration.printMapping != null)
992         {
993             reTraceMappingTextField.setText(fileName(configuration.printMapping));
994         }
995     }
996
997
998     /**
999      * Returns the ProGuard configuration that reflects the current GUI settings.
1000     */

1001    private Configuration getProGuardConfiguration()
1002    {
1003        Configuration configuration = new Configuration();
1004
1005        // Get the input and output jars and directories.
1006
configuration.programJars = programPanel.getClassPath();
1007        configuration.libraryJars = libraryPanel.getClassPath();
1008
1009        List JavaDoc keep = new ArrayList();
1010
1011        // Collect the additional keep options.
1012
List JavaDoc additionalKeep = additionalKeepPanel.getClassSpecifications();
1013        if (additionalKeep != null)
1014        {
1015            keep.addAll(additionalKeep);
1016        }
1017
1018        // Collect the additional keep names options.
1019
List JavaDoc additionalKeepNames = additionalKeepNamesPanel.getClassSpecifications();
1020        if (additionalKeepNames != null)
1021        {
1022            keep.addAll(additionalKeepNames);
1023        }
1024
1025        // Collect the boilerplate keep options.
1026
for (int index = 0; index < boilerplateKeep.length; index++)
1027        {
1028            if (boilerplateKeepCheckBoxes[index].isSelected())
1029            {
1030                keep.add(classSpecification(boilerplateKeep[index],
1031                                            boilerplateKeepTextFields[index].getText()));
1032            }
1033        }
1034
1035        // Collect the boilerplate keep names options.
1036
for (int index = 0; index < boilerplateKeepNames.length; index++)
1037        {
1038            if (boilerplateKeepNamesCheckBoxes[index].isSelected())
1039            {
1040                keep.add(classSpecification(boilerplateKeepNames[index],
1041                                            boilerplateKeepNamesTextFields[index].getText()));
1042            }
1043        }
1044
1045        // Put the list of keep specifications in the configuration.
1046
if (keep.size() > 0)
1047        {
1048            configuration.keep = keep;
1049        }
1050
1051
1052        // Collect the boilerplate "no side effect methods" options.
1053
List JavaDoc noSideEffectMethods = new ArrayList();
1054
1055        for (int index = 0; index < boilerplateNoSideEffectMethods.length; index++)
1056        {
1057            if (boilerplateNoSideEffectMethodCheckBoxes[index].isSelected())
1058            {
1059                noSideEffectMethods.add(boilerplateNoSideEffectMethods[index]);
1060            }
1061        }
1062
1063        // Collect the additional "no side effect methods" options.
1064
List JavaDoc additionalNoSideEffectOptions = additionalNoSideEffectsPanel.getClassSpecifications();
1065        if (additionalNoSideEffectOptions != null)
1066        {
1067            noSideEffectMethods.addAll(additionalNoSideEffectOptions);
1068        }
1069
1070        // Put the list of "no side effect methods" options in the configuration.
1071
if (noSideEffectMethods.size() > 0)
1072        {
1073            configuration.assumeNoSideEffects = noSideEffectMethods;
1074        }
1075
1076
1077        // Collect the "why are you keeping" options.
1078
configuration.whyAreYouKeeping = whyAreYouKeepingPanel.getClassSpecifications();
1079
1080
1081        // Get the other options.
1082
configuration.shrink = shrinkCheckBox .isSelected();
1083        configuration.printUsage = printUsageCheckBox .isSelected() ? new File(printUsageTextField .getText()) : null;
1084
1085        configuration.optimize = optimizeCheckBox .isSelected();
1086        configuration.optimizationPasses = ((SpinnerNumberModel)optimizationPassesSpinner.getModel()).getNumber().intValue();
1087        configuration.allowAccessModification = allowAccessModificationCheckBox .isSelected();
1088
1089        configuration.obfuscate = obfuscateCheckBox .isSelected();
1090        configuration.printMapping = printMappingCheckBox .isSelected() ? new File(printMappingTextField .getText()) : null;
1091        configuration.applyMapping = applyMappingCheckBox .isSelected() ? new File(applyMappingTextField .getText()) : null;
1092        configuration.obfuscationDictionary = obfuscationDictionaryCheckBox .isSelected() ? new File(obfuscationDictionaryTextField .getText()) : null;
1093        configuration.overloadAggressively = overloadAggressivelyCheckBox .isSelected();
1094        configuration.useUniqueClassMemberNames = useUniqueClassMemberNamesCheckBox .isSelected();
1095        configuration.useMixedCaseClassNames = useMixedCaseClassNamesCheckBox .isSelected();
1096        configuration.flattenPackageHierarchy = flattenPackageHierarchyCheckBox .isSelected() ? ClassUtil.externalClassName(flattenPackageHierarchyTextField .getText()) : null;
1097        configuration.repackageClasses = repackageClassesCheckBox .isSelected() ? ClassUtil.externalClassName(repackageClassesTextField .getText()) : null;
1098        configuration.keepAttributes = keepAttributesCheckBox .isSelected() ? ListUtil.commaSeparatedList(keepAttributesTextField .getText()) : null;
1099        configuration.newSourceFileAttribute = newSourceFileAttributeCheckBox .isSelected() ? newSourceFileAttributeTextField .getText() : null;
1100        configuration.adaptResourceFileNames = adaptResourceFileNamesCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileNamesTextField .getText()) : null;
1101        configuration.adaptResourceFileContents = adaptResourceFileContentsCheckBox .isSelected() ? ListUtil.commaSeparatedList(adaptResourceFileContentsTextField.getText()) : null;
1102
1103        configuration.preverify = preverifyCheckBox .isSelected();
1104        configuration.microEdition = microEditionCheckBox .isSelected();
1105        configuration.targetClassVersion = targetCheckBox .isSelected() ? ClassUtil.internalClassVersion(targetComboBox.getSelectedItem().toString()) : 0;
1106
1107        configuration.verbose = verboseCheckBox .isSelected();
1108        configuration.note = noteCheckBox .isSelected();
1109        configuration.warn = warnCheckBox .isSelected();
1110        configuration.ignoreWarnings = ignoreWarningsCheckBox .isSelected();
1111        configuration.skipNonPublicLibraryClasses = skipNonPublicLibraryClassesCheckBox .isSelected();
1112        configuration.skipNonPublicLibraryClassMembers = skipNonPublicLibraryClassMembersCheckBox.isSelected();
1113        configuration.lastModified = forceProcessingCheckBox .isSelected() ? Long.MAX_VALUE : System.currentTimeMillis();
1114        configuration.printSeeds = printSeedsCheckBox .isSelected() ? new File(printSeedsTextField .getText()) : null;
1115        configuration.printConfiguration = printConfigurationCheckBox .isSelected() ? new File(printConfigurationTextField .getText()) : null;
1116        configuration.dump = dumpCheckBox .isSelected() ? new File(dumpTextField .getText()) : null;
1117
1118        return configuration;
1119    }
1120
1121
1122    /**
1123     * Looks in the given list for a class specification that is identical to
1124     * the given template. Returns true if it is found, and removes the matching
1125     * class specification as a side effect.
1126     */

1127    private boolean findClassSpecification(ClassSpecification classSpecificationTemplate,
1128                                           List JavaDoc classSpecifications)
1129    {
1130        if (classSpecifications == null)
1131        {
1132            return false;
1133        }
1134
1135        for (int index = 0; index < classSpecifications.size(); index++)
1136        {
1137            if (classSpecificationTemplate.equals(classSpecifications.get(index)))
1138            {
1139                // Remove the matching option as a side effect.
1140
classSpecifications.remove(index);
1141
1142                return true;
1143            }
1144        }
1145
1146        return false;
1147    }
1148
1149
1150    /**
1151     * Returns the subset of the given list of keep specifications, with
1152     * matching shrinking flag.
1153     */

1154    private List JavaDoc filteredKeepSpecifications(List JavaDoc keepSpecifications,
1155                                            boolean allowShrinking)
1156    {
1157        List JavaDoc filteredKeepSpecifications = new ArrayList();
1158
1159        for (int index = 0; index < keepSpecifications.size(); index++)
1160        {
1161            KeepSpecification keepSpecification =
1162                (KeepSpecification)keepSpecifications.get(index);
1163
1164            if (keepSpecification.allowShrinking == allowShrinking)
1165            {
1166                filteredKeepSpecifications.add(keepSpecification);
1167            }
1168        }
1169
1170        return filteredKeepSpecifications;
1171    }
1172
1173
1174    /**
1175     * Looks in the given list for keep specifications that match the given
1176     * template. Returns a comma-separated string of class names from
1177     * matching keep specifications, and removes the matching keep
1178     * specifications as a side effect.
1179     */

1180    private String JavaDoc findMatchingKeepSpecifications(KeepSpecification keepSpecificationTemplate,
1181                                                  List JavaDoc keepSpecifications)
1182    {
1183        if (keepSpecifications == null)
1184        {
1185            return null;
1186        }
1187
1188        StringBuffer JavaDoc buffer = null;
1189
1190        for (int index = 0; index < keepSpecifications.size(); index++)
1191        {
1192            KeepSpecification listedKeepSpecification =
1193                (KeepSpecification)keepSpecifications.get(index);
1194            String JavaDoc className = listedKeepSpecification.className;
1195            keepSpecificationTemplate.className = className;
1196            if (keepSpecificationTemplate.equals(listedKeepSpecification))
1197            {
1198                if (buffer == null)
1199                {
1200                    buffer = new StringBuffer JavaDoc();
1201                }
1202                else
1203                {
1204                    buffer.append(',');
1205                }
1206                buffer.append(className == null ? "*" : ClassUtil.externalClassName(className));
1207
1208                // Remove the matching option as a side effect.
1209
keepSpecifications.remove(index--);
1210            }
1211        }
1212
1213        return buffer == null ? null : buffer.toString();
1214    }
1215
1216
1217    /**
1218     * Returns a class specification or keep specification, based on the given
1219     * template and the class name to be filled in.
1220     */

1221    private ClassSpecification classSpecification(ClassSpecification classSpecificationTemplate,
1222                                                  String JavaDoc className)
1223    {
1224        // Create a copy of the template.
1225
ClassSpecification classSpecification =
1226            (ClassSpecification)classSpecificationTemplate.clone();
1227
1228        // Set the class name in the copy.
1229
classSpecification.className =
1230            className.equals("") ||
1231            className.equals("*") ?
1232                null :
1233                ClassUtil.internalClassName(className);
1234
1235        // Return the modified copy.
1236
return classSpecification;
1237    }
1238
1239
1240    // Methods and internal classes related to actions.
1241

1242    /**
1243     * Loads the given ProGuard configuration into the GUI.
1244     */

1245    private void loadConfiguration(File file)
1246    {
1247        // Set the default directory and file in the file choosers.
1248
configurationChooser.setSelectedFile(file.getAbsoluteFile());
1249        fileChooser.setCurrentDirectory(file.getAbsoluteFile().getParentFile());
1250
1251        try
1252        {
1253            // Parse the configuration file.
1254
ConfigurationParser parser = new ConfigurationParser(file);
1255            Configuration configuration = new Configuration();
1256
1257            try
1258            {
1259                parser.parse(configuration);
1260
1261                // Let the GUI reflect the configuration.
1262
setProGuardConfiguration(configuration);
1263            }
1264            catch (ParseException ex)
1265            {
1266                JOptionPane.showMessageDialog(getContentPane(),
1267                                              msg("cantParseConfigurationFile", file.getPath()),
1268                                              msg("warning"),
1269                                              JOptionPane.ERROR_MESSAGE);
1270            }
1271            finally
1272            {
1273                parser.close();
1274            }
1275        }
1276        catch (IOException ex)
1277        {
1278            JOptionPane.showMessageDialog(getContentPane(),
1279                                          msg("cantOpenConfigurationFile", file.getPath()),
1280                                          msg("warning"),
1281                                          JOptionPane.ERROR_MESSAGE);
1282        }
1283    }
1284
1285
1286    /**
1287     * Loads the given ProGuard configuration into the GUI.
1288     */

1289    private void loadConfiguration(URL JavaDoc url)
1290    {
1291        try
1292        {
1293            // Parse the configuration file.
1294
ConfigurationParser parser = new ConfigurationParser(url);
1295            Configuration configuration = new Configuration();
1296
1297            try
1298            {
1299                parser.parse(configuration);
1300
1301                // Let the GUI reflect the configuration.
1302
setProGuardConfiguration(configuration);
1303            }
1304            catch (ParseException ex)
1305            {
1306                JOptionPane.showMessageDialog(getContentPane(),
1307                                              msg("cantParseConfigurationFile", url),
1308                                              msg("warning"),
1309                                              JOptionPane.ERROR_MESSAGE);
1310            }
1311            finally
1312            {
1313                parser.close();
1314            }
1315        }
1316        catch (IOException ex)
1317        {
1318            JOptionPane.showMessageDialog(getContentPane(),
1319                                          msg("cantOpenConfigurationFile", url),
1320                                          msg("warning"),
1321                                          JOptionPane.ERROR_MESSAGE);
1322        }
1323    }
1324
1325
1326    /**
1327     * Saves the current ProGuard configuration to the given file.
1328     */

1329    private void saveConfiguration(File file)
1330    {
1331        try
1332        {
1333            // Save the configuration file.
1334
ConfigurationWriter writer = new ConfigurationWriter(file);
1335            writer.write(getProGuardConfiguration());
1336            writer.close();
1337        }
1338        catch (Exception JavaDoc ex)
1339        {
1340            JOptionPane.showMessageDialog(getContentPane(),
1341                                          msg("cantSaveConfigurationFile", file.getPath()),
1342                                          msg("warning"),
1343                                          JOptionPane.ERROR_MESSAGE);
1344        }
1345    }
1346
1347
1348    /**
1349     * Loads the given stack trace into the GUI.
1350     */

1351    private void loadStackTrace(String JavaDoc fileName)
1352    {
1353        try
1354        {
1355            // Read the entire stack trace file into a buffer.
1356
File file = new File(fileName);
1357            byte[] buffer = new byte[(int)file.length()];
1358            InputStream inputStream = new FileInputStream(file);
1359            inputStream.read(buffer);
1360            inputStream.close();
1361
1362            // Put the stack trace in the text area.
1363
stackTraceTextArea.setText(new String JavaDoc(buffer));
1364        }
1365        catch (IOException ex)
1366        {
1367            JOptionPane.showMessageDialog(getContentPane(),
1368                                          msg("cantOpenStackTraceFile", fileName),
1369                                          msg("warning"),
1370                                          JOptionPane.ERROR_MESSAGE);
1371        }
1372    }
1373
1374
1375    /**
1376     * This ActionListener loads a ProGuard configuration file and initializes
1377     * the GUI accordingly.
1378     */

1379    private class MyLoadConfigurationActionListener implements ActionListener
1380    {
1381        public void actionPerformed(ActionEvent e)
1382        {
1383            configurationChooser.setDialogTitle(msg("selectConfigurationFile"));
1384
1385            int returnValue = configurationChooser.showOpenDialog(ProGuardGUI.this);
1386            if (returnValue == JFileChooser.APPROVE_OPTION)
1387            {
1388                loadConfiguration(configurationChooser.getSelectedFile());
1389            }
1390        }
1391    }
1392
1393
1394    /**
1395     * This ActionListener saves a ProGuard configuration file based on the
1396     * current GUI settings.
1397     */

1398    private class MySaveConfigurationActionListener implements ActionListener
1399    {
1400        public void actionPerformed(ActionEvent e)
1401        {
1402            configurationChooser.setDialogTitle(msg("saveConfigurationFile"));
1403
1404            int returnVal = configurationChooser.showSaveDialog(ProGuardGUI.this);
1405            if (returnVal == JFileChooser.APPROVE_OPTION)
1406            {
1407                saveConfiguration(configurationChooser.getSelectedFile());
1408            }
1409        }
1410    }
1411
1412
1413    /**
1414     * This ActionListener displays the ProGuard configuration specified by the
1415     * current GUI settings.
1416     */

1417    private class MyViewConfigurationActionListener implements ActionListener
1418    {
1419        public void actionPerformed(ActionEvent e)
1420        {
1421            // Make sure System.out has not been redirected yet.
1422
if (!systemOutRedirected)
1423            {
1424                consoleTextArea.setText("");
1425
1426                TextAreaOutputStream outputStream =
1427                    new TextAreaOutputStream(consoleTextArea);
1428
1429                try
1430                {
1431                    // TODO: write out relative path names and path names with system properties.
1432

1433                    // Write the configuration.
1434
ConfigurationWriter writer = new ConfigurationWriter(outputStream);
1435                    writer.write(getProGuardConfiguration());
1436                    writer.close();
1437                }
1438                catch (IOException ex)
1439                {
1440                }
1441
1442                // Scroll to the top of the configuration.
1443
consoleTextArea.setCaretPosition(0);
1444            }
1445        }
1446    }
1447
1448
1449    /**
1450     * This ActionListener executes ProGuard based on the current GUI settings.
1451     */

1452    private class MyProcessActionListener implements ActionListener
1453    {
1454        public void actionPerformed(ActionEvent e)
1455        {
1456            // Make sure System.out has not been redirected yet.
1457
if (!systemOutRedirected)
1458            {
1459                systemOutRedirected = true;
1460
1461                // Get the informational configuration file name.
1462
File configurationFile = configurationChooser.getSelectedFile();
1463                String JavaDoc configurationFileName = configurationFile != null ?
1464                    configurationFile.getName() :
1465                    msg("sampleConfigurationFileName");
1466
1467                // Create the ProGuard thread.
1468
Thread JavaDoc proGuardThread =
1469                    new Thread JavaDoc(new ProGuardRunnable(consoleTextArea,
1470                                                    getProGuardConfiguration(),
1471                                                    configurationFileName));
1472
1473                // Run it.
1474
proGuardThread.start();
1475            }
1476        }
1477    }
1478
1479
1480    /**
1481     * This ActionListener loads an obfuscated stack trace from a file and puts
1482     * it in the proper text area.
1483     */

1484    private class MyLoadStackTraceActionListener implements ActionListener
1485    {
1486        public void actionPerformed(ActionEvent e)
1487        {
1488            fileChooser.setDialogTitle(msg("selectStackTraceFile"));
1489            fileChooser.setSelectedFile(null);
1490
1491            int returnValue = fileChooser.showOpenDialog(ProGuardGUI.this);
1492            if (returnValue == JFileChooser.APPROVE_OPTION)
1493            {
1494                File selectedFile = fileChooser.getSelectedFile();
1495                String JavaDoc fileName = selectedFile.getPath();
1496
1497                loadStackTrace(fileName);
1498            }
1499        }
1500    }
1501
1502
1503    /**
1504     * This ActionListener executes ReTrace based on the current GUI settings.
1505     */

1506    private class MyReTraceActionListener implements ActionListener
1507    {
1508        public void actionPerformed(ActionEvent e)
1509        {
1510            // Make sure System.out has not been redirected yet.
1511
if (!systemOutRedirected)
1512            {
1513                systemOutRedirected = true;
1514
1515                boolean verbose = reTraceVerboseCheckBox.isSelected();
1516                File retraceMappingFile = new File(reTraceMappingTextField.getText());
1517                String JavaDoc stackTrace = stackTraceTextArea.getText();
1518
1519                // Create the ReTrace runnable.
1520
Runnable JavaDoc reTraceRunnable = new ReTraceRunnable(reTraceTextArea,
1521                                                               verbose,
1522                                                               retraceMappingFile,
1523                                                               stackTrace);
1524
1525                // Run it in this thread, because it won't take long anyway.
1526
reTraceRunnable.run();
1527            }
1528        }
1529    }
1530
1531
1532    // Small utility methods.
1533

1534    /**
1535     * Returns the file name of the given file, if any.
1536     */

1537    private String JavaDoc fileName(File file)
1538    {
1539        return file == null ? "" : file.getAbsolutePath();
1540    }
1541
1542    /**
1543     * Returns the message from the GUI resources that corresponds to the given
1544     * key.
1545     */

1546    private String JavaDoc msg(String JavaDoc messageKey)
1547    {
1548         return GUIResources.getMessage(messageKey);
1549    }
1550
1551
1552    /**
1553     * Returns the message from the GUI resources that corresponds to the given
1554     * key and argument.
1555     */

1556    private String JavaDoc msg(String JavaDoc messageKey,
1557                       Object JavaDoc messageArgument)
1558    {
1559         return GUIResources.getMessage(messageKey, new Object JavaDoc[] {messageArgument});
1560    }
1561
1562
1563    /**
1564     * The main method for the ProGuard GUI.
1565     */

1566    public static void main(final String JavaDoc[] args)
1567    {
1568// SwingUtil.invokeAndWait(new Runnable()
1569
// {
1570
// public void run()
1571
{
1572                ProGuardGUI gui = new ProGuardGUI();
1573                gui.pack();
1574
1575                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
1576                Dimension guiSize = gui.getSize();
1577                gui.setLocation((screenSize.width - guiSize.width) / 2,
1578                                (screenSize.height - guiSize.height) / 2);
1579                gui.show();
1580
1581                // Start the splash animation, unless specified otherwise.
1582
int argIndex = 0;
1583                if (argIndex < args.length &&
1584                    NO_SPLASH_OPTION.startsWith(args[argIndex]))
1585                {
1586                    gui.skipSplash();
1587                    argIndex++;
1588                }
1589                else
1590                {
1591                    gui.startSplash();
1592                }
1593
1594                // Load an initial configuration, if specified.
1595
if (argIndex < args.length)
1596                {
1597                    gui.loadConfiguration(new File(args[argIndex]));
1598                    argIndex++;
1599                }
1600
1601                if (argIndex < args.length)
1602                {
1603                    System.out.println(gui.getClass().getName() + ": ignoring extra arguments [" + args[argIndex] + "...]");
1604                }
1605
1606            }
1607// });
1608
}
1609}
1610
Popular Tags