diff options
Diffstat (limited to 'src/proguard/gui/MemberSpecificationDialog.java')
-rw-r--r-- | src/proguard/gui/MemberSpecificationDialog.java | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/src/proguard/gui/MemberSpecificationDialog.java b/src/proguard/gui/MemberSpecificationDialog.java new file mode 100644 index 0000000..46a3f6f --- /dev/null +++ b/src/proguard/gui/MemberSpecificationDialog.java @@ -0,0 +1,497 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.gui; + +import proguard.MemberSpecification; +import proguard.classfile.ClassConstants; +import proguard.classfile.util.ClassUtil; +import proguard.util.ListUtil; + +import javax.swing.*; +import javax.swing.border.*; +import java.awt.*; +import java.awt.event.*; + +/** + * This <code>JDialog</code> allows the user to enter a String. + * + * @author Eric Lafortune + */ +final class MemberSpecificationDialog extends JDialog +{ + /** + * Return value if the dialog is canceled (with the Cancel button or by + * closing the dialog window). + */ + public static final int CANCEL_OPTION = 1; + + /** + * Return value if the dialog is approved (with the Ok button). + */ + public static final int APPROVE_OPTION = 0; + + + private final boolean isField; + + private final JRadioButton[] publicRadioButtons; + private final JRadioButton[] privateRadioButtons; + private final JRadioButton[] protectedRadioButtons; + private final JRadioButton[] staticRadioButtons; + private final JRadioButton[] finalRadioButtons; + + private JRadioButton[] volatileRadioButtons; + private JRadioButton[] transientRadioButtons; + + private JRadioButton[] synchronizedRadioButtons; + private JRadioButton[] nativeRadioButtons; + private JRadioButton[] abstractRadioButtons; + private JRadioButton[] strictRadioButtons; + + private final JTextField annotationTypeTextField = new JTextField(20); + private final JTextField nameTextField = new JTextField(20); + private final JTextField typeTextField = new JTextField(20); + private final JTextField argumentTypesTextField = new JTextField(20); + + private int returnValue; + + + public MemberSpecificationDialog(JDialog owner, boolean isField) + { + super(owner, msg(isField ? "specifyFields" : "specifyMethods"), true); + setResizable(true); + + // Create some constraints that can be reused. + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.WEST; + constraints.insets = new Insets(1, 2, 1, 2); + + GridBagConstraints constraintsStretch = new GridBagConstraints(); + constraintsStretch.fill = GridBagConstraints.HORIZONTAL; + constraintsStretch.weightx = 1.0; + constraintsStretch.anchor = GridBagConstraints.WEST; + constraintsStretch.insets = constraints.insets; + + GridBagConstraints constraintsLast = new GridBagConstraints(); + constraintsLast.gridwidth = GridBagConstraints.REMAINDER; + constraintsLast.anchor = GridBagConstraints.WEST; + constraintsLast.insets = constraints.insets; + + GridBagConstraints constraintsLastStretch = new GridBagConstraints(); + constraintsLastStretch.gridwidth = GridBagConstraints.REMAINDER; + constraintsLastStretch.fill = GridBagConstraints.HORIZONTAL; + constraintsLastStretch.weightx = 1.0; + constraintsLastStretch.anchor = GridBagConstraints.WEST; + constraintsLastStretch.insets = constraints.insets; + + GridBagConstraints panelConstraints = new GridBagConstraints(); + panelConstraints.gridwidth = GridBagConstraints.REMAINDER; + panelConstraints.fill = GridBagConstraints.HORIZONTAL; + panelConstraints.weightx = 1.0; + panelConstraints.weighty = 0.0; + panelConstraints.anchor = GridBagConstraints.NORTHWEST; + panelConstraints.insets = constraints.insets; + + GridBagConstraints stretchPanelConstraints = new GridBagConstraints(); + stretchPanelConstraints.gridwidth = GridBagConstraints.REMAINDER; + stretchPanelConstraints.fill = GridBagConstraints.BOTH; + stretchPanelConstraints.weightx = 1.0; + stretchPanelConstraints.weighty = 1.0; + stretchPanelConstraints.anchor = GridBagConstraints.NORTHWEST; + stretchPanelConstraints.insets = constraints.insets; + + GridBagConstraints labelConstraints = new GridBagConstraints(); + labelConstraints.anchor = GridBagConstraints.CENTER; + labelConstraints.insets = new Insets(2, 10, 2, 10); + + GridBagConstraints lastLabelConstraints = new GridBagConstraints(); + lastLabelConstraints.gridwidth = GridBagConstraints.REMAINDER; + lastLabelConstraints.anchor = GridBagConstraints.CENTER; + lastLabelConstraints.insets = labelConstraints.insets; + + GridBagConstraints advancedButtonConstraints = new GridBagConstraints(); + advancedButtonConstraints.weightx = 1.0; + advancedButtonConstraints.weighty = 1.0; + advancedButtonConstraints.anchor = GridBagConstraints.SOUTHWEST; + advancedButtonConstraints.insets = new Insets(4, 4, 8, 4); + + GridBagConstraints okButtonConstraints = new GridBagConstraints(); + okButtonConstraints.weightx = 1.0; + okButtonConstraints.weighty = 1.0; + okButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; + okButtonConstraints.insets = advancedButtonConstraints.insets; + + GridBagConstraints cancelButtonConstraints = new GridBagConstraints(); + cancelButtonConstraints.gridwidth = GridBagConstraints.REMAINDER; + cancelButtonConstraints.weighty = 1.0; + cancelButtonConstraints.anchor = GridBagConstraints.SOUTHEAST; + cancelButtonConstraints.insets = okButtonConstraints.insets; + + GridBagLayout layout = new GridBagLayout(); + + Border etchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.RAISED); + + this.isField = isField; + + // Create the access panel. + JPanel accessPanel = new JPanel(layout); + accessPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, + msg("access"))); + + accessPanel.add(Box.createGlue(), labelConstraints); + accessPanel.add(tip(new JLabel(msg("required")), "requiredTip"), labelConstraints); + accessPanel.add(tip(new JLabel(msg("not")), "notTip"), labelConstraints); + accessPanel.add(tip(new JLabel(msg("dontCare")), "dontCareTip"), labelConstraints); + accessPanel.add(Box.createGlue(), constraintsLastStretch); + + publicRadioButtons = addRadioButtonTriplet("Public", accessPanel); + privateRadioButtons = addRadioButtonTriplet("Private", accessPanel); + protectedRadioButtons = addRadioButtonTriplet("Protected", accessPanel); + staticRadioButtons = addRadioButtonTriplet("Static", accessPanel); + finalRadioButtons = addRadioButtonTriplet("Final", accessPanel); + + if (isField) + { + volatileRadioButtons = addRadioButtonTriplet("Volatile", accessPanel); + transientRadioButtons = addRadioButtonTriplet("Transient", accessPanel); + } + else + { + synchronizedRadioButtons = addRadioButtonTriplet("Synchronized", accessPanel); + nativeRadioButtons = addRadioButtonTriplet("Native", accessPanel); + abstractRadioButtons = addRadioButtonTriplet("Abstract", accessPanel); + strictRadioButtons = addRadioButtonTriplet("Strict", accessPanel); + } + + // Create the type panel. + JPanel typePanel = new JPanel(layout); + typePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, + msg(isField ? "fieldType" : + "returnType"))); + + typePanel.add(tip(typeTextField, "typeTip"), constraintsLastStretch); + + // Create the annotation type panel. + final JPanel annotationTypePanel = new JPanel(layout); + annotationTypePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, + msg("annotation"))); + + annotationTypePanel.add(tip(annotationTypeTextField, "classNameTip"), constraintsLastStretch); + + // Create the name panel. + JPanel namePanel = new JPanel(layout); + namePanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, + msg("name"))); + + namePanel.add(tip(nameTextField, isField ? "fieldNameTip" : + "methodNameTip"), constraintsLastStretch); + + // Create the arguments panel. + JPanel argumentsPanel = new JPanel(layout); + argumentsPanel.setBorder(BorderFactory.createTitledBorder(etchedBorder, + msg("argumentTypes"))); + + argumentsPanel.add(tip(argumentTypesTextField, "argumentTypes2Tip"), constraintsLastStretch); + + // Create the Advanced button. + final JButton advancedButton = new JButton(msg("basic")); + advancedButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + boolean visible = !annotationTypePanel.isVisible(); + + annotationTypePanel.setVisible(visible); + + advancedButton.setText(msg(visible ? "basic" : "advanced")); + + pack(); + } + }); + advancedButton.doClick(); + + // Create the Ok button. + JButton okButton = new JButton(msg("ok")); + okButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + returnValue = APPROVE_OPTION; + hide(); + } + }); + + // Create the Cancel button. + JButton cancelButton = new JButton(msg("cancel")); + cancelButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + hide(); + } + }); + + // Add all panels to the main panel. + JPanel mainPanel = new JPanel(layout); + mainPanel.add(tip(accessPanel, "accessTip"), panelConstraints); + mainPanel.add(tip(annotationTypePanel, "annotationTip"), panelConstraints); + mainPanel.add(tip(typePanel, isField ? "fieldTypeTip" : + "returnTypeTip"), panelConstraints); + mainPanel.add(tip(namePanel, "nameTip"), panelConstraints); + + if (!isField) + { + mainPanel.add(tip(argumentsPanel, "argumentTypesTip"), panelConstraints); + } + + mainPanel.add(tip(advancedButton, "advancedTip"), advancedButtonConstraints); + mainPanel.add(okButton, okButtonConstraints); + mainPanel.add(cancelButton, cancelButtonConstraints); + + getContentPane().add(new JScrollPane(mainPanel)); + } + + + /** + * Adds a JLabel and three JRadioButton instances in a ButtonGroup to the + * given panel with a GridBagLayout, and returns the buttons in an array. + */ + private JRadioButton[] addRadioButtonTriplet(String labelText, + JPanel panel) + { + GridBagConstraints labelConstraints = new GridBagConstraints(); + labelConstraints.anchor = GridBagConstraints.WEST; + labelConstraints.insets = new Insets(2, 10, 2, 10); + + GridBagConstraints buttonConstraints = new GridBagConstraints(); + buttonConstraints.insets = labelConstraints.insets; + + GridBagConstraints lastGlueConstraints = new GridBagConstraints(); + lastGlueConstraints.gridwidth = GridBagConstraints.REMAINDER; + lastGlueConstraints.weightx = 1.0; + + // Create the radio buttons. + JRadioButton radioButton0 = new JRadioButton(); + JRadioButton radioButton1 = new JRadioButton(); + JRadioButton radioButton2 = new JRadioButton(); + + // Put them in a button group. + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(radioButton0); + buttonGroup.add(radioButton1); + buttonGroup.add(radioButton2); + + // Add the label and the buttons to the panel. + panel.add(new JLabel(labelText), labelConstraints); + panel.add(radioButton0, buttonConstraints); + panel.add(radioButton1, buttonConstraints); + panel.add(radioButton2, buttonConstraints); + panel.add(Box.createGlue(), lastGlueConstraints); + + return new JRadioButton[] + { + radioButton0, + radioButton1, + radioButton2 + }; + } + + + /** + * Sets the MemberSpecification to be represented in this dialog. + */ + public void setMemberSpecification(MemberSpecification memberSpecification) + { + String annotationType = memberSpecification.annotationType; + String name = memberSpecification.name; + String descriptor = memberSpecification.descriptor; + + // Set the class name text fields. + annotationTypeTextField.setText(annotationType == null ? "" : ClassUtil.externalType(annotationType)); + + // Set the access radio buttons. + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); + setMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); + + // Set the class name text fields. + nameTextField.setText(name == null ? "*" : name); + + if (isField) + { + typeTextField .setText(descriptor == null ? "***" : ClassUtil.externalType(descriptor)); + } + else + { + typeTextField .setText(descriptor == null ? "***" : ClassUtil.externalMethodReturnType(descriptor)); + argumentTypesTextField.setText(descriptor == null ? "..." : ClassUtil.externalMethodArguments(descriptor)); + } + } + + + /** + * Returns the MemberSpecification currently represented in this dialog. + */ + public MemberSpecification getMemberSpecification() + { + String annotationType = annotationTypeTextField.getText(); + String name = nameTextField.getText(); + String type = typeTextField.getText(); + String arguments = argumentTypesTextField.getText(); + + // Convert all class member specifications into the internal format. + annotationType = + annotationType.equals("") || + annotationType.equals("***") ? null : ClassUtil.internalType(annotationType); + + if (name.equals("") || + name.equals("*")) + { + name = null; + } + + if (isField) + { + type = + type.equals("") || + type.equals("***") ? null : ClassUtil.internalType(type); + } + else + { + if (type.equals("")) + { + type = ClassConstants.EXTERNAL_TYPE_VOID; + } + + type = + type .equals("***") && + arguments.equals("...") ? null : + ClassUtil.internalMethodDescriptor(type, ListUtil.commaSeparatedList(arguments)); + } + + MemberSpecification memberSpecification = + new MemberSpecification(0, 0, annotationType, name, type); + + // Also get the access radio button settings. + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PUBLIC, publicRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PRIVATE, privateRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_PROTECTED, protectedRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STATIC, staticRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_FINAL, finalRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_VOLATILE, volatileRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_TRANSIENT, transientRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_SYNCHRONIZED, synchronizedRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_NATIVE, nativeRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_ABSTRACT, abstractRadioButtons); + getMemberSpecificationRadioButtons(memberSpecification, ClassConstants.INTERNAL_ACC_STRICT, strictRadioButtons); + + return memberSpecification; + } + + + /** + * Shows this dialog. This method only returns when the dialog is closed. + * + * @return <code>CANCEL_OPTION</code> or <code>APPROVE_OPTION</code>, + * depending on the choice of the user. + */ + public int showDialog() + { + returnValue = CANCEL_OPTION; + + // Open the dialog in the right place, then wait for it to be closed, + // one way or another. + pack(); + setLocationRelativeTo(getOwner()); + show(); + + return returnValue; + } + + + /** + * Sets the appropriate radio button of a given triplet, based on the access + * flags of the given keep option. + */ + private void setMemberSpecificationRadioButtons(MemberSpecification memberSpecification, + int flag, + JRadioButton[] radioButtons) + { + if (radioButtons != null) + { + int index = (memberSpecification.requiredSetAccessFlags & flag) != 0 ? 0 : + (memberSpecification.requiredUnsetAccessFlags & flag) != 0 ? 1 : + 2; + radioButtons[index].setSelected(true); + } + } + + + /** + * Updates the access flag of the given keep option, based on the given radio + * button triplet. + */ + private void getMemberSpecificationRadioButtons(MemberSpecification memberSpecification, + int flag, + JRadioButton[] radioButtons) + { + if (radioButtons != null) + { + if (radioButtons[0].isSelected()) + { + memberSpecification.requiredSetAccessFlags |= flag; + } + else if (radioButtons[1].isSelected()) + { + memberSpecification.requiredUnsetAccessFlags |= flag; + } + } + } + + + /** + * Attaches the tool tip from the GUI resources that corresponds to the + * given key, to the given component. + */ + private static JComponent tip(JComponent component, String messageKey) + { + component.setToolTipText(msg(messageKey)); + + return component; + } + + + /** + * Returns the message from the GUI resources that corresponds to the given + * key. + */ + private static String msg(String messageKey) + { + return GUIResources.getMessage(messageKey); + } +} |