package net.sourceforge.pmd.eclipse.ui.preferences; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; import net.sourceforge.pmd.eclipse.plugin.UISettings; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; import net.sourceforge.pmd.eclipse.ui.preferences.br.RuleUtil; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.util.StringUtil; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWebBrowser; /** * Implements a dialog for adding or editing a rule. When editing, the rule is * automatically updated. The caller has no need to test if the dialog was OK or * not. * * @author Philippe Herlin * @deprecated */ public class RuleDialog extends Dialog { private static final int MODE_ADD = 1; private static final int MODE_EDIT = 2; private static final int MODE_VIEW = 3; protected Text implementationClassText; private int mode = MODE_ADD; private Rule editedRule; private Rule rule; private Text ruleSetNameText; private Button ruleReferenceButton; // private Text sinceText; private Text nameText; private Button xpathRuleButton; private Text messageText; private Combo priorityCombo; protected Button usesTypeResolutionButton; protected Button usesDfaButton; private Text descriptionText; private Text externalInfoUrlText; protected Button openExternalInfoUrlButton; private Text exampleText; protected Text xpathText; private Font courierFont; /** * Constructor for RuleDialog. * * @param parentdlgArea */ public RuleDialog(Shell parent) { super(parent); mode = MODE_ADD; } /** * Constructor for RuleDialog. * * @param parentdlgArea */ public RuleDialog(Shell parent, Rule editedRule) { super(parent); mode = MODE_EDIT; this.editedRule = editedRule; } /** * Constructor for RuleDialog. * * @param parentdlgArea */ public RuleDialog(Shell parent, Rule editedRule, boolean flEdit) { super(parent); mode = flEdit ? MODE_EDIT : MODE_VIEW; this.editedRule = editedRule; } /** * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(Composite) */ @Override protected Control createDialogArea(Composite parent) { courierFont = new Font(getShell().getDisplay(), "Courier New", 10, SWT.NORMAL); Composite dlgArea = new Composite(parent, SWT.NULL); GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 4; dlgArea.setLayout(gridLayout); Label ruleSetNameLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_RULESET_NAME); GridData data = new GridData(); data.horizontalSpan = 1; ruleSetNameLabel.setLayoutData(data); ruleSetNameText = buildRuleSetNameText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 2; data.grabExcessHorizontalSpace = true; ruleSetNameText.setLayoutData(data); ruleReferenceButton = buildRuleReferenceButton(dlgArea); // Label sinceLabel = buildLabel(dlgArea, StringKeys.MSGKEY_PREF_RULEEDIT_LABEL_SINCE); // data = new GridData(); // data.horizontalSpan = 1; // sinceLabel.setLayoutData(data); // sinceText = buildSinceText(dlgArea); // data = new GridData(); // data.horizontalSpan = 3; // data.grabExcessHorizontalSpace = false; // sinceText.setLayoutData(data); Label nameLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_NAME); data = new GridData(); data.horizontalSpan = 4; nameLabel.setLayoutData(data); nameText = buildNameText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 3; data.grabExcessHorizontalSpace = true; nameText.setLayoutData(data); xpathRuleButton = buildXPathRuleButton(dlgArea); Label implementationClassLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_IMPLEMENTATION_CLASS); data = new GridData(); data.horizontalSpan = 4; implementationClassLabel.setLayoutData(data); implementationClassText = buildImplementationClassText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; implementationClassText.setLayoutData(data); Label messageLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_MESSAGE); data = new GridData(); data.horizontalSpan = 4; messageLabel.setLayoutData(data); messageText = buildMessageText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; messageText.setLayoutData(data); Label priorityLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_PRIORITY); data = new GridData(); data.horizontalSpan = 1; priorityLabel.setLayoutData(data); priorityCombo = buildPriorityCombo(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 1; data.grabExcessHorizontalSpace = true; priorityCombo.setLayoutData(data); usesTypeResolutionButton = buildUsesTypeResolutionButton(dlgArea); usesDfaButton = buildUsesDfaButton(dlgArea); Label descriptionLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_DESCRIPTION); data = new GridData(); data.horizontalSpan = 4; descriptionLabel.setLayoutData(data); descriptionText = buildDescriptionText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = true; data.widthHint = 300; data.heightHint = 100; descriptionText.setLayoutData(data); Label externalInfoUrlLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_EXTERNAL_INFO_URL); data = new GridData(); data.horizontalSpan = 3; externalInfoUrlLabel.setLayoutData(data); openExternalInfoUrlButton = buildOpenExternalInfoUrlButton(dlgArea); externalInfoUrlText = buildExternalInfoUrlText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; externalInfoUrlText.setLayoutData(data); Label exampleLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_EXAMPLES); data = new GridData(); data.horizontalSpan = 4; exampleLabel.setLayoutData(data); exampleText = buildExampleText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = true; data.widthHint = 300; data.heightHint = 70; exampleText.setLayoutData(data); Label xpathLabel = buildLabel(dlgArea, StringKeys.PREF_RULEEDIT_LABEL_XPATH); data = new GridData(); data.horizontalSpan = 4; xpathLabel.setLayoutData(data); xpathText = buildXPathText(dlgArea); data = new GridData(); data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; data.horizontalSpan = 4; data.grabExcessHorizontalSpace = true; data.grabExcessVerticalSpace = true; data.widthHint = 300; data.heightHint = 100; xpathText.setLayoutData(data); // Set the window title getShell().setText(getMessage(StringKeys.PREF_RULESET_DIALOG_TITLE)); refreshOverridden(); return dlgArea; } /** * Build a label */ private Label buildLabel(Composite parent, String msgKey) { Label label = new Label(parent, SWT.NONE); label.setText(msgKey == null ? "" : getMessage(msgKey)); return label; } /** * Build the rule set name text */ private Text buildRuleSetNameText(Composite parent) { Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); if (mode == MODE_ADD) { text.setText("pmd-eclipse"); text.setEnabled(false); } if (mode == MODE_EDIT) { text.setText(editedRule.getRuleSetName()); text.setEnabled(false); } if (mode == MODE_VIEW) { text.setText(editedRule.getRuleSetName()); text.setEnabled(false); } return text; } /** * Build the rule reference button */ private Button buildRuleReferenceButton(Composite parent) { final Button button = new Button(parent, SWT.CHECK); button.setText(getMessage(StringKeys.PREF_RULEEDIT_BUTTON_RULE_REFERENCE)); button.setEnabled(false); button.setSelection(editedRule instanceof RuleReference); return button; } /** * Build the since text */ // private Text buildSinceText(Composite parent) { // Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); // text.setEnabled(false); // // String since = "n/a"; // if (editedRule != null && editedRule.getSince() != null) // { // since = editedRule.getSince(); // } // // if (mode == MODE_ADD) { // text.setText(since); // } // // if (mode == MODE_EDIT) { // text.setText(since); // } // // if (mode == MODE_VIEW) { // text.setText(since); // } // // return text; // } /** * Build the rule name text */ private Text buildNameText(Composite parent) { Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); if (mode == MODE_ADD) { text.setFocus(); } if (mode == MODE_EDIT) { text.setText(editedRule.getName()); text.setEnabled(false); } if (mode == MODE_VIEW) { text.setEditable(false); text.setText(editedRule.getName()); } return text; } /** * Build the XPath rule button */ private Button buildXPathRuleButton(Composite parent) { final Button button = new Button(parent, SWT.CHECK); button.setText(getMessage(StringKeys.PREF_RULEEDIT_BUTTON_XPATH_RULE)); if (mode == MODE_VIEW) { button.setVisible(false); } else { if (mode == MODE_EDIT) { button.setSelection(editedRule.getRuleClass().endsWith("XPathRule")); button.setEnabled(false); } else { button.setEnabled(true); button.setSelection(true); } button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { if (button.getSelection()) { implementationClassText.setText(XPathRule.class.getName()); implementationClassText.setEnabled(false); xpathText.setEnabled(true); usesTypeResolutionButton.setEnabled(false); usesTypeResolutionButton.setSelection(true); usesDfaButton.setEnabled(false); usesDfaButton.setSelection(false); } else { implementationClassText.setText(""); implementationClassText.setEnabled(true); xpathText.setText(""); xpathText.setEnabled(false); usesTypeResolutionButton.setEnabled(true); usesTypeResolutionButton.setSelection(true); usesDfaButton.setEnabled(true); usesDfaButton.setSelection(false); } } }); } return button; } /** * Build the implementation class text */ private Text buildImplementationClassText(Composite parent) { Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); if (mode == MODE_EDIT) { text.setText(editedRule.getRuleClass()); text.setEnabled(false); } if (mode == MODE_VIEW) { text.setEditable(false); text.setText(editedRule.getRuleClass()); } if (mode == MODE_ADD) { text.setText(XPathRule.class.getName()); text.setEnabled(false); } return text; } /** * Build the message text */ private Text buildMessageText(Composite parent) { Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); if (mode == MODE_EDIT) { text.setFocus(); text.setText(editedRule.getMessage().trim()); } if (mode == MODE_VIEW) { text.setEditable(false); text.setText(editedRule.getMessage().trim()); } return text; } /** * Build the priority combo */ private Combo buildPriorityCombo(Composite parent) { Combo combo = new Combo(parent, SWT.BORDER); String[] labels = UISettings.getPriorityLabels(); int index = 3-1; if (editedRule != null && editedRule.getPriority().getPriority() >= 0 && editedRule.getPriority().getPriority() <= labels.length) { index = editedRule.getPriority().getPriority() - 1; } for (String label : labels) { combo.add(label); } combo.select(index); if (mode == MODE_VIEW) { combo.setEnabled(false); } else if (mode == MODE_EDIT) { combo.setEnabled(true); } else if (mode == MODE_ADD) { combo.setEnabled(true); } return combo; } /** * Build the uses type resolution button */ private Button buildUsesTypeResolutionButton(Composite parent) { final Button button = new Button(parent, SWT.CHECK); button.setText(getMessage(StringKeys.PREF_RULEEDIT_BUTTON_USES_TYPE_RESOLUTION)); if (mode == MODE_VIEW) { button.setVisible(false); } else { if (mode == MODE_EDIT) { button.setEnabled(false); button.setSelection(editedRule.usesTypeResolution()); } else { button.setEnabled(false); button.setSelection(true); } } return button; } /** * Build the uses dfa button */ private Button buildUsesDfaButton(Composite parent) { final Button button = new Button(parent, SWT.CHECK); button.setText(getMessage(StringKeys.PREF_RULEEDIT_BUTTON_USES_DFA)); if (mode == MODE_VIEW) { button.setVisible(false); } else { if (mode == MODE_EDIT) { button.setEnabled(false); button.setSelection(editedRule.usesDFA()); } else { button.setEnabled(false); button.setSelection(false); } } return button; } /** * Build the description text */ private Text buildDescriptionText(Composite parent) { Text text = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.WRAP); String description = null; if (editedRule != null) { description = editedRule.getDescription(); } if (description == null) { description = ""; } text.setText(description.trim()); if (mode == MODE_VIEW) { text.setEditable(false); } return text; } /** * Build the external info url text */ private Text buildExternalInfoUrlText(Composite parent) { Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); String externalInfoUrl = null; if (editedRule != null) { externalInfoUrl = editedRule.getExternalInfoUrl(); } if (externalInfoUrl == null) { externalInfoUrl = ""; } text.setText(externalInfoUrl.trim()); if (mode == MODE_VIEW) { text.setEditable(false); } return text; } /** * Build the open external info url button */ private Button buildOpenExternalInfoUrlButton(Composite parent) { final Button button = new Button(parent, SWT.PUSH); button.setText(getMessage(StringKeys.PREF_RULEEDIT_BUTTON_OPEN_EXTERNAL_INFO_URL)); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { String url = externalInfoUrlText.getText().trim(); if (url.length() > 0) { try { IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser(); browser.openURL(new URL(url)); } catch (PartInitException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }); return button; } /** * Concatenate all the rule examples in one String. * * @return the concatenation of all example strings */ private String getExamplesString() { StringBuffer buffer = new StringBuffer(); Iterator<String> i = this.editedRule.getExamples().iterator(); boolean first = true; while (i.hasNext()) { if (first) { first = false; } else { buffer.append("\n\n"); } buffer.append(i.next().trim()); } return buffer.toString(); } /** * Build the example text */ private Text buildExampleText(Composite parent) { Text text = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); text.setFont(courierFont); if (mode == MODE_EDIT) { text.setText(getExamplesString()); } if (mode == MODE_VIEW) { text.setEditable(false); text.setText(getExamplesString()); } return text; } /** * Build the xpath text */ private Text buildXPathText(Composite parent) { Text text = new Text(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); text.setFont(courierFont); if (mode == MODE_ADD) { text.setEditable(true); text.setEnabled(true); } if (mode == MODE_EDIT) { //if (editedRule.hasDescriptor(XPathRule.XPATH_DESCRIPTOR)) { if (RuleUtil.isXPathRule(editedRule)) { text.setText(editedRule.getProperty(XPathRule.XPATH_DESCRIPTOR).trim()); text.setEditable(true); } } if (mode == MODE_VIEW) { text.setEditable(false); //if (editedRule.hasDescriptor(XPathRule.XPATH_DESCRIPTOR)) { if (RuleUtil.isXPathRule(editedRule)) { text.setText(editedRule.getProperty(XPathRule.XPATH_DESCRIPTOR).trim()); } } return text; } /** * Based on current settings of a RuleReference being edited, update the visual * indicators of whether an override of the underlying Rule is occurring * or not. */ protected void refreshOverridden() { if (mode == MODE_EDIT || mode == MODE_VIEW) { if (editedRule instanceof RuleReference) { RuleReference ruleReference = (RuleReference)editedRule; Color lightBlue = new Color(null, 196, 196, 255); nameText.setBackground(ruleReference.getOverriddenName() != null ? lightBlue: null); messageText.setBackground(ruleReference.getOverriddenMessage() != null ? lightBlue: null); priorityCombo.setBackground(ruleReference.getOverriddenPriority() != null ? lightBlue: null); descriptionText.setBackground(ruleReference.getOverriddenDescription() != null ? lightBlue: null); externalInfoUrlText.setBackground(ruleReference.getOverriddenExternalInfoUrl() != null ? lightBlue: null); exampleText.setBackground(ruleReference.getOverriddenExamples() != null ? lightBlue: null); xpathText.setBackground(ruleReference.hasOverriddenProperty(XPathRule.XPATH_DESCRIPTOR) ? lightBlue: null); } } } /** * Helper method to shorten message access * * @param key a message key * @return requested message */ private String getMessage(String key) { return PMDPlugin.getDefault().getStringTable().getString(key); } /** * @see org.eclipse.jface.dialogs.Dialog#okPressed() */ @Override protected void okPressed() { if (validateForm() && this.mode != MODE_VIEW) { super.okPressed(); } else if (this.mode == MODE_VIEW) { cancelPressed(); } } /** * Perform the form validation */ private boolean validateForm() { return validateName() && validatePriority() && validateMessage() && validateImplementationClass(); } /** * Perform the name validation */ private boolean validateName() { boolean flValid = true; String name = nameText.getText(); if (StringUtil.isEmpty(name)) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.WARNING_TITLE), getMessage(StringKeys.WARNING_NAME_MANDATORY)); nameText.setFocus(); flValid = false; } return flValid; } /** * Perform the priority validation */ private boolean validatePriority() { boolean flValid = true; if (priorityCombo.getSelectionIndex() < 0) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.WARNING_TITLE), getMessage(StringKeys.WARNING_PRIORITY_MANDATORY)); priorityCombo.setFocus(); flValid = false; } return flValid; } /** * Perform the messageValidation */ private boolean validateMessage() { boolean flValid = true; String message = messageText.getText(); if (StringUtil.isEmpty(message)) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.WARNING_TITLE), getMessage(StringKeys.WARNING_MESSAGE_MANDATORY)); messageText.setFocus(); flValid = false; } return flValid; } /** * Perform the implementation class validation */ private boolean validateImplementationClass() { boolean flValid = true; boolean flClassError = false; // Instantiate the rule (add mode) if (mode == MODE_ADD) { try { Class<?> ruleClass = Class.forName(implementationClassText.getText()); Object instance = ruleClass.newInstance(); if (instance instanceof Rule) { rule = (Rule) ruleClass.newInstance(); rule.setName(nameText.getText().trim()); rule.setRuleSetName("pmd-eclipse"); rule.setMessage(messageText.getText().trim()); rule.setDescription(descriptionText.getText()); rule.getExamples().add(exampleText.getText()); rule.setPriority(RulePriority.valueOf(priorityCombo.getSelectionIndex()+1)); rule.setExternalInfoUrl(externalInfoUrlText.getText()); if (usesTypeResolutionButton.getSelection()) { rule.setUsesTypeResolution(); } if (usesDfaButton.getSelection()) { rule.setUsesDFA(); } if (rule instanceof XPathRule) { String xpath = xpathText.getText().trim(); if (xpath.length() != 0) { rule.setProperty(XPathRule.XPATH_DESCRIPTOR, xpath); } else { MessageDialog.openWarning(getShell(), getMessage(StringKeys.WARNING_TITLE), getMessage(StringKeys.WARNING_XPATH_MANDATORY)); xpathText.setFocus(); flValid = false; } } } else { flClassError = true; } } catch (ClassNotFoundException e) { flClassError = true; } catch (InstantiationException e) { flClassError = true; } catch (IllegalAccessException e) { flClassError = true; } } // else only modify appropriate fields (edit mode) else { editedRule.setMessage(messageText.getText().trim()); editedRule.setPriority(RulePriority.valueOf(priorityCombo.getSelectionIndex() + 1)); editedRule.setDescription(descriptionText.getText()); editedRule.setExternalInfoUrl(externalInfoUrlText.getText()); editedRule.addExample(this.exampleText.getText()); String xpath = xpathText.getText().trim(); if (xpath.length() > 0) { editedRule.setProperty(XPathRule.XPATH_DESCRIPTOR, xpath); } } // Display class error if needed if (flClassError) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.WARNING_TITLE), getMessage(StringKeys.WARNING_CLASS_INVALID)); implementationClassText.setFocus(); flValid = false; } return flValid; } /** * Returns the rule. * * @return Rule */ public Rule getRule() { return rule; } /** * @see org.eclipse.jface.dialogs.Dialog#cancelPressed() */ @Override protected void cancelPressed() { courierFont.dispose(); super.cancelPressed(); } }