package net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.eclipse.ui.nls.StringKeys;
import net.sourceforge.pmd.eclipse.ui.preferences.br.ValueChangeListener;
import net.sourceforge.pmd.eclipse.ui.preferences.editors.SWTUtil;
import net.sourceforge.pmd.lang.rule.RuleReference;
import net.sourceforge.pmd.util.StringUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.browser.IWebBrowser;
/**
*
* @author Brian Remedios
*/
public class DescriptionPanelManager extends AbstractRulePanelManager {
private Text descriptionBox;
private Text externalURLField;
private Label extURLLabel;
private Button browseButton;
private Label messageLabel;
private Text messageField;
private static final int MIN_MESSAGE_LENGTH = 10; //chars
public static final String ID = "description";
public DescriptionPanelManager(String theTitle, EditorUsageMode theMode, ValueChangeListener theListener) {
super(ID, theTitle, theMode, theListener);
}
protected boolean canManageMultipleRules() { return false; }
protected void clearControls() {
descriptionBox.setText("");
externalURLField.setText("");
}
public void showControls(boolean flag) {
descriptionBox.setVisible(flag);
externalURLField.setVisible(flag);
browseButton.setVisible(flag);
extURLLabel.setVisible(flag);
messageLabel.setVisible(flag);
messageField.setVisible(flag);
}
protected void updateOverridenFields() {
Rule rule = soleRule();
if (rule instanceof RuleReference) {
RuleReference ruleReference = (RuleReference)rule;
messageField.setBackground(ruleReference.getOverriddenMessage() != null ? overridenColour: null);
descriptionBox.setBackground(ruleReference.getOverriddenDescription() != null ? overridenColour: null);
externalURLField.setBackground(ruleReference.getOverriddenExternalInfoUrl() != null ? overridenColour: null);
}
}
public Control setupOn(Composite parent) {
initializeOn(parent);
GridData gridData;
Composite panel = new Composite(parent, 0);
GridLayout layout = new GridLayout(3, false);
panel.setLayout(layout);
descriptionBox = newTextField(panel);
gridData = new GridData(GridData.FILL_BOTH);
gridData.grabExcessHorizontalSpace = true;
gridData.horizontalSpan = 3;
descriptionBox.setLayoutData(gridData);
descriptionBox.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
Rule soleRule = soleRule();
if (soleRule == null) return;
String cleanValue = asCleanString(descriptionBox.getText());
String existingValue = soleRule.getDescription();
if (StringUtil.areSemanticEquals(existingValue, cleanValue)) return;
soleRule.setDescription(cleanValue);
valueChanged(null, cleanValue);
validateRuleParams(); // TODO hang off of valueChanged instead?
}
});
buildExternalUrlPanel(panel, SWTUtil.stringFor(StringKeys.PREF_RULEEDIT_LABEL_EXTERNAL_INFO_URL));
buildMessagePanel(panel, SWTUtil.stringFor(StringKeys.PREF_RULEEDIT_LABEL_MESSAGE));
return panel;
}
private void validateRuleParams() {
validate();
boolean urlOK = StringUtil.isEmpty(externalURLField.getText()) || hasValidURL();
adjustBrowseButton(urlOK);
}
private void buildExternalUrlPanel(Composite parent, String urlLabel) {
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
extURLLabel = new Label(parent, 0);
extURLLabel.setText(urlLabel);
gridData.horizontalSpan = 1;
gridData.grabExcessHorizontalSpace = false;
extURLLabel.setLayoutData(gridData);
externalURLField = new Text(parent, SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 1;
gridData.grabExcessHorizontalSpace = true;
externalURLField.setLayoutData(gridData);
browseButton = buildExternalInfoUrlButton(parent);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER);
gridData.horizontalSpan = 1;
browseButton.setLayoutData(gridData);
externalURLField.addListener(SWT.FocusOut, new Listener() {
public void handleEvent(Event e) {
handleExternalURLChange();
}
});
externalURLField.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
validateRuleParams();
}
});
}
private void buildMessagePanel(Composite parent, String messageLbl) {
GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
messageLabel = new Label(parent, 0);
messageLabel.setText(messageLbl);
gridData.horizontalSpan = 1;
gridData.grabExcessHorizontalSpace = false;
messageLabel.setLayoutData(gridData);
messageField = new Text(parent, SWT.BORDER);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = 2;
gridData.grabExcessHorizontalSpace = true;
messageField.setLayoutData(gridData);
messageField.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
handleMessageChange();
validateRuleParams();
}
});
}
private void handleExternalURLChange() {
String newURL = asCleanString(externalURLField.getText());
Rule rule = soleRule();
if (!StringUtil.areSemanticEquals(asCleanString(rule.getExternalInfoUrl()), newURL)) {
rule.setExternalInfoUrl(newURL);
valueChanged(null, newURL);
}
adjustBrowseButton( hasValidURL() );
}
private void handleMessageChange() {
String newMessage = asCleanString(messageField.getText());
Rule rule = soleRule();
if (!StringUtil.areSemanticEquals(asCleanString(rule.getMessage()), newMessage)) {
rule.setMessage(newMessage);
updateUI();
}
}
private Button buildExternalInfoUrlButton(Composite parent) {
final Button button = new Button(parent, SWT.PUSH);
button.setText(SWTUtil.stringFor(StringKeys.PREF_RULEEDIT_BUTTON_OPEN_EXTERNAL_INFO_URL));
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
String url = externalURLField.getText();
if (url.length() > 0) {
try {
IWebBrowser browser = PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser();
browser.openURL(new URL(url));
} catch (PartInitException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
});
return button;
}
protected void adapt() {
Rule soleRule = soleRule();
if (soleRule == null) {
shutdown(descriptionBox);
shutdown(externalURLField);
shutdown(messageField);
} else {
show(descriptionBox, asCleanString(soleRule.getDescription()));
show(externalURLField, asCleanString(soleRule.getExternalInfoUrl()));
show(messageField, asCleanString(soleRule.getMessage()));
}
boolean isValid = hasValidURL();
adjustBrowseButton(isValid);
}
public static boolean isValidURL(String url) {
if (StringUtil.isEmpty(url)) return false;
String urlUC = url.toUpperCase();
if (!urlUC.startsWith("HTTP")) return false;
for (int i=0; i<url.length(); i++) {
if (Character.isWhitespace(url.charAt(i))) return false;
}
return true;
}
private boolean hasValidURL() {
String url = externalURLField.getText().trim();
if (StringUtil.isEmpty(url)) return true; // not required
return isValidURL(url);
}
private boolean hasValidMessage() {
String message = messageField.getText().trim();
return StringUtil.isNotEmpty(message) && (message.length() > MIN_MESSAGE_LENGTH);
}
private boolean hasValidDescription() {
String description = descriptionBox.getText().trim();
return StringUtil.isNotEmpty(description) && (description.length() > MIN_MESSAGE_LENGTH);
}
private void adjustBrowseButton(boolean hasValidURL) {
browseButton.setEnabled(hasValidURL);
externalURLField.setForeground(
hasValidURL ? textColour : errorColour
);
}
protected List<String> fieldErrors() {
List<String> errors = new ArrayList<String>(3);
if (StringUtil.isEmpty(descriptionBox.getText().trim())) {
errors.add("Missing description");
}
if (StringUtil.isEmpty(messageField.getText().trim())) {
errors.add("Missing message");
}
if (!hasValidURL()) errors.add("Invalid external URL");
return errors;
}
}