aboutsummaryrefslogtreecommitdiffstats
path: root/src/proguard/gui/MemberSpecificationDialog.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/gui/MemberSpecificationDialog.java')
-rw-r--r--src/proguard/gui/MemberSpecificationDialog.java497
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);
+ }
+}