1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.gui;
22
23import proguard.*;
24import proguard.classfile.ClassConstants;
25import proguard.classfile.util.ClassUtil;
26
27import javax.swing.*;
28import javax.swing.border.*;
29import java.awt.*;
30import java.awt.event.*;
31import java.util.List;
32
33/**
34 * This <code>JDialog</code> allows the user to enter a String.
35 *
36 * @author Eric Lafortune
37 */
38final class ClassSpecificationDialog extends JDialog
39{
40    /**
41     * Return value if the dialog is canceled (with the Cancel button or by
42     * closing the dialog window).
43     */
44    public static final int CANCEL_OPTION = 1;
45
46    /**
47     * Return value if the dialog is approved (with the Ok button).
48     */
49    public static final int APPROVE_OPTION = 0;
50
51
52    private final JTextArea commentsTextArea = new JTextArea(4, 20);
53
54    private final JRadioButton keepClassesAndMembersRadioButton  = new JRadioButton(msg("keep"));
55    private final JRadioButton keepClassMembersRadioButton       = new JRadioButton(msg("keepClassMembers"));
56    private final JRadioButton keepClassesWithMembersRadioButton = new JRadioButton(msg("keepClassesWithMembers"));
57
58    private final JCheckBox keepDescriptorClassesCheckBox = new JCheckBox(msg("keepDescriptorClasses"));
59
60    private final JCheckBox allowShrinkingCheckBox    = new JCheckBox(msg("allowShrinking"));
61    private final JCheckBox allowOptimizationCheckBox = new JCheckBox(msg("allowOptimization"));
62    private final JCheckBox allowObfuscationCheckBox  = new JCheckBox(msg("allowObfuscation"));
63
64
65    private final JRadioButton[] publicRadioButtons;
66    private final JRadioButton[] finalRadioButtons;
67    private final JRadioButton[] abstractRadioButtons;
68    private final JRadioButton[] interfaceRadioButtons;
69    private final JRadioButton[] annotationRadioButtons;
70    private final JRadioButton[] enumRadioButtons;
71    private final JRadioButton[] syntheticRadioButtons;
72
73    private final JTextField annotationTypeTextField        = new JTextField(20);
74    private final JTextField classNameTextField             = new JTextField(20);
75    private final JTextField extendsAnnotationTypeTextField = new JTextField(20);
76    private final JTextField extendsClassNameTextField      = new JTextField(20);
77
78    private final MemberSpecificationsPanel memberSpecificationsPanel;
79
80    private int returnValue;
81
82
83    public ClassSpecificationDialog(JFrame owner, boolean fullKeepOptions)
84    {
85        super(owner, msg("specifyClasses"), true);
86        setResizable(true);
87
88        // Create some constraints that can be reused.
89        GridBagConstraints constraints = new GridBagConstraints();
90        constraints.anchor = GridBagConstraints.WEST;
91        constraints.insets = new Insets(1, 2, 1, 2);
92
93        GridBagConstraints constraintsStretch = new GridBagConstraints();
94        constraintsStretch.fill    = GridBagConstraints.HORIZONTAL;
95        constraintsStretch.weightx = 1.0;
96        constraintsStretch.anchor  = GridBagConstraints.WEST;
97        constraintsStretch.insets  = constraints.insets;
98
99        GridBagConstraints constraintsLast = new GridBagConstraints();
100        constraintsLast.gridwidth = GridBagConstraints.REMAINDER;
101        constraintsLast.anchor    = GridBagConstraints.WEST;
102        constraintsLast.insets    = constraints.insets;
103
104        GridBagConstraints constraintsLastStretch = new GridBagConstraints();
105        constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER;
106        constraintsLastStretch.fill      = GridBagConstraints.HORIZONTAL;
107        constraintsLastStretch.weightx   = 1.0;
108        constraintsLastStretch.anchor    = GridBagConstraints.WEST;
109        constraintsLastStretch.insets    = constraints.insets;
110
111        GridBagConstraints panelConstraints = new GridBagConstraints();
112        panelConstraints.gridwidth = GridBagConstraints.REMAINDER;
113        panelConstraints.fill      = GridBagConstraints.HORIZONTAL;
114        panelConstraints.weightx   = 1.0;
115        panelConstraints.weighty   = 0.0;
116        panelConstraints.anchor    = GridBagConstraints.NORTHWEST;
117        panelConstraints.insets    = constraints.insets;
118
119        GridBagConstraints stretchPanelConstraints = new GridBagConstraints();
120        stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER;
121        stretchPanelConstraints.fill      = GridBagConstraints.BOTH;
122        stretchPanelConstraints.weightx   = 1.0;
123        stretchPanelConstraints.weighty   = 1.0;
124        stretchPanelConstraints.anchor    = GridBagConstraints.NORTHWEST;
125        stretchPanelConstraints.insets    = constraints.insets;
126
127        GridBagConstraints labelConstraints = new GridBagConstraints();
128        labelConstraints.anchor = GridBagConstraints.CENTER;
129        labelConstraints.insets = new Insets(2, 10, 2, 10);
130
131        GridBagConstraints lastLabelConstraints = new GridBagConstraints();
132        lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER;
133        lastLabelConstraints.anchor    = GridBagConstraints.CENTER;
134        lastLabelConstraints.insets    = labelConstraints.insets;
135
136        GridBagConstraints advancedButtonConstraints = new GridBagConstraints();
137        advancedButtonConstraints.weightx = 1.0;
138        advancedButtonConstraints.weighty = 1.0;
139        advancedButtonConstraints.anchor  = GridBagConstraints.SOUTHWEST;
140        advancedButtonConstraints.insets  = new Insets(4, 4, 8, 4);
141
142        GridBagConstraints okButtonConstraints = new GridBagConstraints();
143        okButtonConstraints.weightx = 1.0;
144        okButtonConstraints.weighty = 1.0;
145        okButtonConstraints.anchor  = GridBagConstraints.SOUTHEAST;
146        okButtonConstraints.insets  = advancedButtonConstraints.insets;
147
148        GridBagConstraints cancelButtonConstraints = new GridBagConstraints();
149        cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER;
150        cancelButtonConstraints.weighty   = 1.0;
151        cancelButtonConstraints.anchor    = GridBagConstraints.SOUTHEAST;
152        cancelButtonConstraints.insets    = advancedButtonConstraints.insets;
153
154        GridBagLayout layout = new GridBagLayout();
155
156        Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
157
158        // Create the comments panel.
159        JPanel commentsPanel = new JPanel(layout);
160        commentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
161                                                                 msg("comments")));
162
163        JScrollPane commentsScrollPane = new JScrollPane(commentsTextArea);
164        commentsScrollPane.setBorder(classNameTextField.getBorder());
165
166        commentsPanel.add(tip(commentsScrollPane, "commentsTip"), constraintsLastStretch);
167
168        // Create the keep option panel.
169        ButtonGroup keepButtonGroup = new ButtonGroup();
170        keepButtonGroup.add(keepClassesAndMembersRadioButton);
171        keepButtonGroup.add(keepClassMembersRadioButton);
172        keepButtonGroup.add(keepClassesWithMembersRadioButton);
173
174        JPanel keepOptionPanel = new JPanel(layout);
175        keepOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
176                                                                   msg("keepTitle")));
177
178        keepOptionPanel.add(tip(keepClassesAndMembersRadioButton,  "keepTip"),                   constraintsLastStretch);
179        keepOptionPanel.add(tip(keepClassMembersRadioButton,       "keepClassMembersTip"),       constraintsLastStretch);
180        keepOptionPanel.add(tip(keepClassesWithMembersRadioButton, "keepClassesWithMembersTip"), constraintsLastStretch);
181        keepOptionPanel.add(tip(keepDescriptorClassesCheckBox,  "keepDescriptorClassesTip"),  constraintsLastStretch);
182
183        // Create the also keep panel.
184        final JPanel alsoKeepOptionPanel = new JPanel(layout);
185        alsoKeepOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
186                                                                       msg("alsoKeepTitle")));
187
188        alsoKeepOptionPanel.add(tip(keepDescriptorClassesCheckBox, "keepDescriptorClassesTip"),    constraintsLastStretch);
189
190        // Create the allow option panel.
191        final JPanel allowOptionPanel = new JPanel(layout);
192        allowOptionPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
193                                                                    msg("allowTitle")));
194
195        allowOptionPanel.add(tip(allowShrinkingCheckBox,    "allowShrinkingTip"),    constraintsLastStretch);
196        allowOptionPanel.add(tip(allowOptimizationCheckBox, "allowOptimizationTip"), constraintsLastStretch);
197        allowOptionPanel.add(tip(allowObfuscationCheckBox,  "allowObfuscationTip"),  constraintsLastStretch);
198
199        // Create the access panel.
200        JPanel accessPanel = new JPanel(layout);
201        accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
202                                                               msg("access")));
203
204        accessPanel.add(Box.createGlue(),                                labelConstraints);
205        accessPanel.add(tip(new JLabel(msg("required")), "requiredTip"), labelConstraints);
206        accessPanel.add(tip(new JLabel(msg("not")),      "notTip"),      labelConstraints);
207        accessPanel.add(tip(new JLabel(msg("dontCare")), "dontCareTip"), labelConstraints);
208        accessPanel.add(Box.createGlue(),                                constraintsLastStretch);
209
210        publicRadioButtons     = addRadioButtonTriplet("Public",     accessPanel);
211        finalRadioButtons      = addRadioButtonTriplet("Final",      accessPanel);
212        abstractRadioButtons   = addRadioButtonTriplet("Abstract",   accessPanel);
213        interfaceRadioButtons  = addRadioButtonTriplet("Interface",  accessPanel);
214        annotationRadioButtons = addRadioButtonTriplet("Annotation", accessPanel);
215        enumRadioButtons       = addRadioButtonTriplet("Enum",       accessPanel);
216        syntheticRadioButtons  = addRadioButtonTriplet("Synthetic",  accessPanel);
217
218        // Create the annotation type panel.
219        final JPanel annotationTypePanel = new JPanel(layout);
220        annotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
221                                                                       msg("annotation")));
222
223        annotationTypePanel.add(tip(annotationTypeTextField, "classNameTip"), constraintsLastStretch);
224
225        // Create the class name panel.
226        JPanel classNamePanel = new JPanel(layout);
227        classNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
228                                                                  msg("class")));
229
230        classNamePanel.add(tip(classNameTextField, "classNameTip"), constraintsLastStretch);
231
232        // Create the extends annotation type panel.
233        final JPanel extendsAnnotationTypePanel = new JPanel(layout);
234        extendsAnnotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
235                                                                              msg("extendsImplementsAnnotation")));
236
237        extendsAnnotationTypePanel.add(tip(extendsAnnotationTypeTextField, "classNameTip"), constraintsLastStretch);
238
239        // Create the extends class name panel.
240        JPanel extendsClassNamePanel = new JPanel(layout);
241        extendsClassNamePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
242                                                                         msg("extendsImplementsClass")));
243
244        extendsClassNamePanel.add(tip(extendsClassNameTextField, "classNameTip"), constraintsLastStretch);
245
246
247        // Create the class member list panel.
248        memberSpecificationsPanel = new MemberSpecificationsPanel(this, fullKeepOptions);
249        memberSpecificationsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder,
250                                                                             msg("classMembers")));
251
252        // Create the Advanced button.
253        final JButton advancedButton = new JButton(msg("basic"));
254        advancedButton.addActionListener(new ActionListener()
255        {
256            public void actionPerformed(ActionEvent e)
257            {
258                boolean visible = !alsoKeepOptionPanel.isVisible();
259
260                alsoKeepOptionPanel       .setVisible(visible);
261                allowOptionPanel          .setVisible(visible);
262                annotationTypePanel       .setVisible(visible);
263                extendsAnnotationTypePanel.setVisible(visible);
264
265                advancedButton.setText(msg(visible ? "basic" : "advanced"));
266
267                pack();
268            }
269        });
270        advancedButton.doClick();
271
272        // Create the Ok button.
273        JButton okButton = new JButton(msg("ok"));
274        okButton.addActionListener(new ActionListener()
275        {
276            public void actionPerformed(ActionEvent e)
277            {
278                returnValue = APPROVE_OPTION;
279                hide();
280            }
281        });
282
283        // Create the Cancel button.
284        JButton cancelButton = new JButton(msg("cancel"));
285        cancelButton.addActionListener(new ActionListener()
286        {
287            public void actionPerformed(ActionEvent e)
288            {
289                hide();
290            }
291        });
292
293        // Add all panels to the main panel.
294        JPanel mainPanel = new JPanel(layout);
295        mainPanel.add(tip(commentsPanel,              "commentsTip"),                    panelConstraints);
296        if (fullKeepOptions)
297        {
298            mainPanel.add(tip(keepOptionPanel,        "keepTitleTip"),                   panelConstraints);
299            mainPanel.add(tip(alsoKeepOptionPanel,    "alsoKeepTitleTip"),               panelConstraints);
300            mainPanel.add(tip(allowOptionPanel,       "allowTitleTip"),                  panelConstraints);
301        }
302        mainPanel.add(tip(accessPanel,                "accessTip"),                      panelConstraints);
303        mainPanel.add(tip(annotationTypePanel,        "annotationTip"),                  panelConstraints);
304        mainPanel.add(tip(classNamePanel,             "classTip"),                       panelConstraints);
305        mainPanel.add(tip(extendsAnnotationTypePanel, "extendsImplementsAnnotationTip"), panelConstraints);
306        mainPanel.add(tip(extendsClassNamePanel,      "extendsImplementsClassTip"),      panelConstraints);
307        mainPanel.add(tip(memberSpecificationsPanel,  "classMembersTip"),                stretchPanelConstraints);
308
309        mainPanel.add(tip(advancedButton, "advancedTip"), advancedButtonConstraints);
310        mainPanel.add(okButton,                           okButtonConstraints);
311        mainPanel.add(cancelButton,                       cancelButtonConstraints);
312
313        getContentPane().add(new JScrollPane(mainPanel));
314    }
315
316
317    /**
318     * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the
319     * given panel with a GridBagLayout, and returns the buttons in an array.
320     */
321    private JRadioButton[] addRadioButtonTriplet(String labelText,
322                                                 JPanel panel)
323    {
324        GridBagConstraints labelConstraints = new GridBagConstraints();
325        labelConstraints.anchor = GridBagConstraints.WEST;
326        labelConstraints.insets = new Insets(2, 10, 2, 10);
327
328        GridBagConstraints buttonConstraints = new GridBagConstraints();
329        buttonConstraints.insets = labelConstraints.insets;
330
331        GridBagConstraints lastGlueConstraints = new GridBagConstraints();
332        lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER;
333        lastGlueConstraints.weightx   = 1.0;
334
335        // Create the radio buttons.
336        JRadioButton radioButton0 = new JRadioButton();
337        JRadioButton radioButton1 = new JRadioButton();
338        JRadioButton radioButton2 = new JRadioButton();
339
340        // Put them in a button group.
341        ButtonGroup buttonGroup = new ButtonGroup();
342        buttonGroup.add(radioButton0);
343        buttonGroup.add(radioButton1);
344        buttonGroup.add(radioButton2);
345
346        // Add the label and the buttons to the panel.
347        panel.add(new JLabel(labelText), labelConstraints);
348        panel.add(radioButton0,          buttonConstraints);
349        panel.add(radioButton1,          buttonConstraints);
350        panel.add(radioButton2,          buttonConstraints);
351        panel.add(Box.createGlue(),      lastGlueConstraints);
352
353        return new JRadioButton[]
354        {
355             radioButton0,
356             radioButton1,
357             radioButton2
358        };
359    }
360
361
362    /**
363     * Sets the KeepClassSpecification to be represented in this dialog.
364     */
365    public void setKeepSpecification(KeepClassSpecification keepClassSpecification)
366    {
367        boolean markClasses           = keepClassSpecification.markClasses;
368        boolean markConditionally     = keepClassSpecification.markConditionally;
369        boolean markDescriptorClasses = keepClassSpecification.markDescriptorClasses;
370        boolean allowShrinking        = keepClassSpecification.allowShrinking;
371        boolean allowOptimization     = keepClassSpecification.allowOptimization;
372        boolean allowObfuscation      = keepClassSpecification.allowObfuscation;
373
374        // Figure out the proper keep radio button and set it.
375        JRadioButton keepOptionRadioButton =
376            markConditionally ? keepClassesWithMembersRadioButton :
377            markClasses       ? keepClassesAndMembersRadioButton  :
378                                keepClassMembersRadioButton;
379
380        keepOptionRadioButton.setSelected(true);
381
382        // Set the other check boxes.
383        keepDescriptorClassesCheckBox.setSelected(markDescriptorClasses);
384        allowShrinkingCheckBox       .setSelected(allowShrinking);
385        allowOptimizationCheckBox    .setSelected(allowOptimization);
386        allowObfuscationCheckBox     .setSelected(allowObfuscation);
387
388        setClassSpecification(keepClassSpecification);
389    }
390
391
392    /**
393     * Sets the ClassSpecification to be represented in this dialog.
394     */
395    public void setClassSpecification(ClassSpecification classSpecification)
396    {
397        String comments              = classSpecification.comments;
398        String annotationType        = classSpecification.annotationType;
399        String className             = classSpecification.className;
400        String extendsAnnotationType = classSpecification.extendsAnnotationType;
401        String extendsClassName      = classSpecification.extendsClassName;
402        List   keepFieldOptions      = classSpecification.fieldSpecifications;
403        List   keepMethodOptions     = classSpecification.methodSpecifications;
404
405        // Set the comments text area.
406        commentsTextArea.setText(comments == null ? "" : comments);
407
408        // Set the access radio buttons.
409        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_PUBLIC,      publicRadioButtons);
410        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_FINAL,       finalRadioButtons);
411        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ABSTRACT,    abstractRadioButtons);
412        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_INTERFACE,   interfaceRadioButtons);
413        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ANNOTATTION, annotationRadioButtons);
414        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ENUM,        enumRadioButtons);
415        setClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_SYNTHETIC,   syntheticRadioButtons);
416
417        // Set the class and annotation text fields.
418        annotationTypeTextField       .setText(annotationType        == null ? ""  : ClassUtil.externalType(annotationType));
419        classNameTextField            .setText(className             == null ? "*" : ClassUtil.externalClassName(className));
420        extendsAnnotationTypeTextField.setText(extendsAnnotationType == null ? ""  : ClassUtil.externalType(extendsAnnotationType));
421        extendsClassNameTextField     .setText(extendsClassName      == null ? ""  : ClassUtil.externalClassName(extendsClassName));
422
423        // Set the keep class member option list.
424        memberSpecificationsPanel.setMemberSpecifications(keepFieldOptions, keepMethodOptions);
425    }
426
427
428    /**
429     * Returns the KeepClassSpecification currently represented in this dialog.
430     */
431    public KeepClassSpecification getKeepSpecification()
432    {
433        boolean markClasses           = !keepClassMembersRadioButton     .isSelected();
434        boolean markConditionally     = keepClassesWithMembersRadioButton.isSelected();
435        boolean markDescriptorClasses = keepDescriptorClassesCheckBox    .isSelected();
436        boolean allowShrinking        = allowShrinkingCheckBox           .isSelected();
437        boolean allowOptimization     = allowOptimizationCheckBox        .isSelected();
438        boolean allowObfuscation      = allowObfuscationCheckBox         .isSelected();
439
440        return new KeepClassSpecification(markClasses,
441                                          markConditionally,
442                                          markDescriptorClasses,
443                                          allowShrinking,
444                                          allowOptimization,
445                                          allowObfuscation,
446                                          getClassSpecification());
447    }
448
449
450    /**
451     * Returns the ClassSpecification currently represented in this dialog.
452     */
453    public ClassSpecification getClassSpecification()
454    {
455        String comments              = commentsTextArea.getText();
456        String annotationType        = annotationTypeTextField.getText();
457        String className             = classNameTextField.getText();
458        String extendsAnnotationType = extendsAnnotationTypeTextField.getText();
459        String extendsClassName      = extendsClassNameTextField.getText();
460
461        ClassSpecification classSpecification =
462            new ClassSpecification(comments.equals("")              ? null : comments,
463                                   0,
464                                   0,
465                                   annotationType.equals("")        ? null : ClassUtil.internalType(annotationType),
466                                   className.equals("") ||
467                                   className.equals("*")            ? null : ClassUtil.internalClassName(className),
468                                   extendsAnnotationType.equals("") ? null : ClassUtil.internalType(extendsAnnotationType),
469                                   extendsClassName.equals("")      ? null : ClassUtil.internalClassName(extendsClassName));
470
471        // Also get the access radio button settings.
472        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_PUBLIC,      publicRadioButtons);
473        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_FINAL,       finalRadioButtons);
474        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ABSTRACT,    abstractRadioButtons);
475        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_INTERFACE,   interfaceRadioButtons);
476        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ANNOTATTION, annotationRadioButtons);
477        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_ENUM,        enumRadioButtons);
478        getClassSpecificationRadioButtons(classSpecification, ClassConstants.ACC_SYNTHETIC,   syntheticRadioButtons);
479
480        // Get the keep class member option lists.
481        classSpecification.fieldSpecifications  = memberSpecificationsPanel.getMemberSpecifications(true);
482        classSpecification.methodSpecifications = memberSpecificationsPanel.getMemberSpecifications(false);
483
484        return classSpecification;
485    }
486
487
488    /**
489     * Shows this dialog. This method only returns when the dialog is closed.
490     *
491     * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>,
492     *         depending on the choice of the user.
493     */
494    public int showDialog()
495    {
496        returnValue = CANCEL_OPTION;
497
498        // Open the dialog in the right place, then wait for it to be closed,
499        // one way or another.
500        pack();
501        setLocationRelativeTo(getOwner());
502        show();
503
504        return returnValue;
505    }
506
507
508    /**
509     * Sets the appropriate radio button of a given triplet, based on the access
510     * flags of the given keep option.
511     */
512    private void setClassSpecificationRadioButtons(ClassSpecification classSpecification,
513                                                   int                flag,
514                                                   JRadioButton[]     radioButtons)
515    {
516        int index = (classSpecification.requiredSetAccessFlags   & flag) != 0 ? 0 :
517                    (classSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 :
518                                                                                 2;
519        radioButtons[index].setSelected(true);
520    }
521
522
523    /**
524     * Updates the access flag of the given keep option, based on the given radio
525     * button triplet.
526     */
527    private void getClassSpecificationRadioButtons(ClassSpecification classSpecification,
528                                                   int                flag,
529                                                   JRadioButton[]     radioButtons)
530    {
531        if      (radioButtons[0].isSelected())
532        {
533            classSpecification.requiredSetAccessFlags   |= flag;
534        }
535        else if (radioButtons[1].isSelected())
536        {
537            classSpecification.requiredUnsetAccessFlags |= flag;
538        }
539    }
540
541
542    /**
543     * Attaches the tool tip from the GUI resources that corresponds to the
544     * given key, to the given component.
545     */
546    private static JComponent tip(JComponent component, String messageKey)
547    {
548        component.setToolTipText(msg(messageKey));
549
550        return component;
551    }
552
553
554    /**
555     * Returns the message from the GUI resources that corresponds to the given
556     * key.
557     */
558    private static String msg(String messageKey)
559    {
560         return GUIResources.getMessage(messageKey);
561    }
562}
563