From 7fa24a8af0dccac039751f9b9b706b41fa0b8660 Mon Sep 17 00:00:00 2001 From: Brian Remedios Date: Sat, 25 Oct 2008 22:49:37 +0000 Subject: [PATCH] Code cleanup, deprecations, some adaptations for new properties. Some classes that currently have errors will soon be removed. git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@6677 51baf565-9d33-0410-a72c-fc3788e3496d --- .../ui/preferences/CPDPreferencePage.java | 2 +- .../ui/preferences/PMDPreferencePage.java | 51 +- .../ui/preferences/RuleCellModifier.java | 2 +- .../eclipse/ui/preferences/RuleDialog.java | 5 +- .../RulePropertiesContentProvider.java | 10 +- .../eclipse/ui/preferences/RuleProperty.java | 2 +- .../preferences/RuleSetContentProvider.java | 6 +- ...tExcludeIncludePatternContentProvider.java | 17 +- .../preferences/br/AbstractEditorFactory.java | 78 ++ .../br/AbstractMultiValueEditorFactory.java | 86 ++ .../br/AbstractRulePanelManager.java | 61 + .../br/BasicRuleFieldAccessor.java | 22 + .../preferences/br/BooleanEditorFactory.java | 70 ++ .../ui/preferences/br/CellPainterBuilder.java | 8 + .../br/CharacterEditorFactory.java | 91 ++ .../ui/preferences/br/ColourManager.java | 62 + .../br/DescriptionPanelManager.java | 68 ++ .../ui/preferences/br/EditorFactory.java | 34 + .../br/EnumerationEditorFactory.java | 62 + .../preferences/br/ExclusionPanelManager.java | 121 ++ .../ui/preferences/br/FormArranger.java | 114 ++ .../preferences/br/IntegerEditorFactory.java | 72 ++ .../br/MultiIntegerEditorFactory.java | 59 + .../br/MultiStringEditorFactory.java | 38 + .../br/MultiTypeEditorFactory.java | 78 ++ .../ui/preferences/br/PMDPreferencePage.java | 1022 +++++++++++++++++ .../br/PerRulePropertyPanelManager.java | 60 + .../br/PropertyChangeListener.java | 12 + .../br/RealNumberEditorFactory.java | 62 + .../preferences/br/RuleColumnDescriptor.java | 97 ++ .../ui/preferences/br/RuleFieldAccessor.java | 138 +++ .../eclipse/ui/preferences/br/RuleGroup.java | 81 ++ .../ui/preferences/br/RuleLabelProvider.java | 59 + .../preferences/br/RulePropertyManager.java | 8 + .../br/RuleSetTreeItemProvider.java | 165 +++ .../ui/preferences/br/RuleSortListener.java | 7 + .../preferences/br/StringEditorFactory.java | 101 ++ .../ui/preferences/br/TypeEditorFactory.java | 116 ++ .../pmd/eclipse/ui/preferences/br/Util.java | 218 ++++ .../preferences/br/ValueChangeListener.java | 15 + .../ui/preferences/br/ValueFormatter.java | 59 + .../eclipse/ui/preferences/br/testing.jpage | 9 + 42 files changed, 3401 insertions(+), 47 deletions(-) create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractMultiValueEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractRulePanelManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BasicRuleFieldAccessor.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BooleanEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CellPainterBuilder.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CharacterEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ColourManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/DescriptionPanelManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EnumerationEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ExclusionPanelManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/FormArranger.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/IntegerEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiIntegerEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiStringEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiTypeEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PMDPreferencePage.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PerRulePropertyPanelManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PropertyChangeListener.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RealNumberEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleColumnDescriptor.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleFieldAccessor.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleGroup.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleLabelProvider.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RulePropertyManager.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSetTreeItemProvider.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSortListener.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/StringEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/TypeEditorFactory.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/Util.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ValueChangeListener.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ValueFormatter.java create mode 100644 pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/testing.jpage diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/CPDPreferencePage.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/CPDPreferencePage.java index 851c44d8cc..e7d8770e9a 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/CPDPreferencePage.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/CPDPreferencePage.java @@ -96,7 +96,7 @@ public class CPDPreferencePage extends PreferencePage implements IWorkbenchPrefe * @see org.eclipse.jface.preference.IPreferencePage#performOk() */ public boolean performOk() { - this.preferences.setMinTileSize(new Integer(this.minTileText.getText()).intValue()); + this.preferences.setMinTileSize(Integer.valueOf(this.minTileText.getText()).intValue()); this.preferences.sync(); return super.performOk(); diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/PMDPreferencePage.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/PMDPreferencePage.java index 45fb6b7908..be09e739bf 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/PMDPreferencePage.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/PMDPreferencePage.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.util.Comparator; -import java.util.Iterator; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; @@ -79,7 +78,7 @@ public class PMDPreferencePage extends PreferencePage implements IWorkbenchPrefe protected Button addRuleButton; protected Button removeRuleButton; protected Button editRuleButton; - protected Button addPropertyButton; +// protected Button addPropertyButton; protected Button addExcludePatternButton; protected Button addIncludePatternButton; protected RuleSet ruleSet; @@ -290,7 +289,7 @@ public class PMDPreferencePage extends PreferencePage implements IWorkbenchPrefe rowLayout.pack = false; composite.setLayout(rowLayout); - addPropertyButton = buildAddPropertyButton(composite); +// addPropertyButton = buildAddPropertyButton(composite); return composite; } @@ -360,7 +359,7 @@ public class PMDPreferencePage extends PreferencePage implements IWorkbenchPrefe rulePropertiesTableViewer.setInput(selectedRule); removeRuleButton.setEnabled(selectedRule != null); editRuleButton.setEnabled(selectedRule != null); - addPropertyButton.setEnabled(selectedRule != null); +// addPropertyButton.setEnabled(selectedRule != null); } }); @@ -640,28 +639,28 @@ public class PMDPreferencePage extends PreferencePage implements IWorkbenchPrefe /** * Build the add property button */ - private Button buildAddPropertyButton(Composite parent) { - Button button = new Button(parent, SWT.PUSH | SWT.LEFT); - button.setText(getMessage(StringKeys.MSGKEY_PREF_RULESET_BUTTON_ADDPROPERTY)); - button.setEnabled(false); - button.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent event) { - InputDialog input = new InputDialog(getShell(), - getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_TITLE), - getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_PROPERTY_NAME), "", null); - int result = input.open(); - if (result == InputDialog.OK) { - IStructuredSelection selection = (IStructuredSelection)ruleTableViewer.getSelection(); - Rule selectedRule = (Rule)selection.getFirstElement(); - selectedRule.addProperty(input.getValue(), ""); - setModified(true); - rulePropertiesTableViewer.refresh(); - } - } - }); - return button; - } +// private Button buildAddPropertyButton(Composite parent) { +// Button button = new Button(parent, SWT.PUSH | SWT.LEFT); +// button.setText(getMessage(StringKeys.MSGKEY_PREF_RULESET_BUTTON_ADDPROPERTY)); +// button.setEnabled(false); +// button.addSelectionListener(new SelectionAdapter() { +// @Override +// public void widgetSelected(SelectionEvent event) { +// InputDialog input = new InputDialog(getShell(), +// getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_TITLE), +// getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_PROPERTY_NAME), "", null); +// int result = input.open(); +// if (result == InputDialog.OK) { +// IStructuredSelection selection = (IStructuredSelection)ruleTableViewer.getSelection(); +// Rule selectedRule = (Rule)selection.getFirstElement(); +//// selectedRule.addProperty(input.getValue(), ""); +// setModified(true); +// rulePropertiesTableViewer.refresh(); +// } +// } +// }); +// return button; +// } /** * Build the exclude pattern table viewer diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleCellModifier.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleCellModifier.java index 203efca143..57c3ab9a7a 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleCellModifier.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleCellModifier.java @@ -46,7 +46,7 @@ public class RuleCellModifier implements ICellModifier { } else if (property.equalsIgnoreCase(PMDPreferencePage.PROPERTY_RULE_NAME)) { result = rule.getName(); } else if (property.equalsIgnoreCase(PMDPreferencePage.PROPERTY_PRIORITY)) { - result = new Integer(rule.getPriority().getPriority() - 1); + result = Integer.valueOf(rule.getPriority().getPriority() - 1); } else if (property.equalsIgnoreCase(PMDPreferencePage.PROPERTY_DESCRIPTION)) { result = rule.getDescription(); } diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleDialog.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleDialog.java index d5aa66d50e..92d3ee57a8 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleDialog.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleDialog.java @@ -8,6 +8,7 @@ import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.util.StringUtil; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; @@ -707,7 +708,7 @@ public class RuleDialog extends Dialog { boolean flValid = true; String name = nameText.getText(); - if (name.trim().length() == 0) { + if (StringUtil.isEmpty(name)) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.MSGKEY_WARNING_TITLE), getMessage(StringKeys.MSGKEY_WARNING_NAME_MANDATORY)); nameText.setFocus(); @@ -740,7 +741,7 @@ public class RuleDialog extends Dialog { boolean flValid = true; String message = messageText.getText(); - if (message.trim().length() == 0) { + if (StringUtil.isEmpty(message)) { MessageDialog.openWarning(getShell(), getMessage(StringKeys.MSGKEY_WARNING_TITLE), getMessage(StringKeys.MSGKEY_WARNING_MESSAGE_MANDATORY)); messageText.setFocus(); diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RulePropertiesContentProvider.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RulePropertiesContentProvider.java index e4a4b4ab17..216bbb835e 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RulePropertiesContentProvider.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RulePropertiesContentProvider.java @@ -5,13 +5,14 @@ import java.util.Enumeration; import java.util.List; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.eclipse.ui.preferences.br.Util; /** * This class implements a content provider for the rule properties table of * the PMD Preference page * * @author Philippe Herlin - * + * @deprecated */ public class RulePropertiesContentProvider extends AbstractStructuredContentProvider { @@ -19,8 +20,7 @@ public class RulePropertiesContentProvider extends AbstractStructuredContentProv * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(Object) */ public Object[] getElements(Object inputElement) { - Object[] result = new Object[0]; - + if (inputElement instanceof Rule) { Rule rule = (Rule) inputElement; Enumeration keys = rule.getProperties().keys(); @@ -28,9 +28,9 @@ public class RulePropertiesContentProvider extends AbstractStructuredContentProv while (keys.hasMoreElements()) { propertyList.add(new RuleProperty(rule, keys.nextElement())); } - result = propertyList.toArray(); + return propertyList.toArray(); } - return result; + return Util.EMPTY_ARRAY; } } diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleProperty.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleProperty.java index 47aa298924..6a8908083e 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleProperty.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleProperty.java @@ -6,7 +6,7 @@ import net.sourceforge.pmd.Rule; * Helper class to display rule properties in a table * * @author Philippe Herlin - * + * @deprecated */ public class RuleProperty { private Rule rule; diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetContentProvider.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetContentProvider.java index d35a5efe37..851ffab7ed 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetContentProvider.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetContentProvider.java @@ -1,6 +1,7 @@ package net.sourceforge.pmd.eclipse.ui.preferences; import net.sourceforge.pmd.RuleSet; +import net.sourceforge.pmd.eclipse.ui.preferences.br.Util; /** * This class implements a content provider for the rule table of @@ -15,13 +16,12 @@ public class RuleSetContentProvider extends AbstractStructuredContentProvider { * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(Object) */ public Object[] getElements(Object inputElement) { - Object[] elements = new Object[0]; if (inputElement instanceof RuleSet) { RuleSet ruleSet = (RuleSet) inputElement; - elements = ruleSet.getRules().toArray(); + return ruleSet.getRules().toArray(); } - return elements; + return Util.EMPTY_ARRAY; } } diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetExcludeIncludePatternContentProvider.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetExcludeIncludePatternContentProvider.java index 577c4310d3..36def6e607 100644 --- a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetExcludeIncludePatternContentProvider.java +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/RuleSetExcludeIncludePatternContentProvider.java @@ -1,6 +1,5 @@ package net.sourceforge.pmd.eclipse.ui.preferences; -import java.util.ArrayList; import java.util.List; import net.sourceforge.pmd.RuleSet; @@ -14,6 +13,9 @@ public class RuleSetExcludeIncludePatternContentProvider extends AbstractStructu private final boolean exclude; + private static final RuleSetExcludeIncludePattern[] emptyRuleSetPattern = new RuleSetExcludeIncludePattern[0]; + + public RuleSetExcludeIncludePatternContentProvider(boolean exclude) { this.exclude = exclude; } @@ -22,18 +24,17 @@ public class RuleSetExcludeIncludePatternContentProvider extends AbstractStructu * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(Object) */ public RuleSetExcludeIncludePattern[] getElements(Object inputElement) { - RuleSetExcludeIncludePattern[] result = new RuleSetExcludeIncludePattern[0]; - + if (inputElement instanceof RuleSet) { RuleSet ruleSet = (RuleSet)inputElement; List patterns = exclude ? ruleSet.getExcludePatterns() : ruleSet.getIncludePatterns(); - List patternList = new ArrayList(); - for (int i = 0; i < patterns.size(); i++) { - patternList.add(new RuleSetExcludeIncludePattern(ruleSet, exclude, i)); + RuleSetExcludeIncludePattern[] patternList = new RuleSetExcludeIncludePattern[patterns.size()]; + for (int i = 0; i < patternList.length; i++) { + patternList[i] = new RuleSetExcludeIncludePattern(ruleSet, exclude, i); } - result = patternList.toArray(result); + return patternList; } - return result; + return emptyRuleSetPattern; } } \ No newline at end of file diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractEditorFactory.java new file mode 100644 index 0000000000..73fae7f9d0 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractEditorFactory.java @@ -0,0 +1,78 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; + +/** + * + * @author Brian Remedios + */ +public abstract class AbstractEditorFactory implements EditorFactory { + + protected AbstractEditorFactory() { } + + /** + * @return int + * @see net.sourceforge.pmd.ui.preferences.br.EditorFactory#columnsRequired() + */ + public int columnsRequired() { return 2; }; + + /** + * Method addLabel. + * @param parent Composite + * @param desc PropertyDescriptor + * @return Label + */ + protected Label addLabel(Composite parent, PropertyDescriptor desc) { + + Label label = new Label(parent, SWT.NONE); + label.setText(desc.description()); + return label; + } + + /** + * Return the value as a string that can be easily recognized and parsed + * when we see it again. + * + * @param value Object + * @return String + */ + protected String asString(Object value) { + return value == null ? "" : value.toString(); + } + + /** + * Return the specified values as a single string using the delimiter. + * @param values Object + * @param delimiter char + * @return String + * @see net.sourceforge.pmd.PropertyDescriptor#asDelimitedString(Object) + */ + public String asDelimitedString(Object values, char delimiter) { + + if (values == null) { + return ""; + } + + if (values instanceof Object[]) { + Object[] valueSet = (Object[])values; + if (valueSet.length == 0) { + return ""; + } + if (valueSet.length == 1) { + return asString(valueSet[0]); + } + + StringBuilder sb = new StringBuilder(asString(valueSet[0])); + for (int i=1; i desc, Rule rule, ValueChangeListener listener); + + /** + * + * @param parent Composite + * @param columnIndex int + * @param desc PropertyDescriptor + * @param rule Rule + * @param listener ValueChangeListener + * @return Control + * @see net.sourceforge.pmd.ui.preferences.br.EditorFactory#newEditorOn(Composite, int, PropertyDescriptor, Rule) + */ + public Control newEditorOn(Composite parent, int columnIndex, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout(2, false)); + + Text textWidget = new Text(panel, SWT.SINGLE | SWT.BORDER); + // final Button butt = new Button(panel, SWT.BORDER); + // butt.setText("..."); + + textWidget.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + fillWidget(textWidget, desc, rule); + configure(textWidget, desc, rule, listener); + + return panel; + } + + return null; + } + + protected void fillWidget(Text textWidget, PropertyDescriptor desc, Rule rule) { + + Object[] values = (Object[])rule.getProperty(desc); + textWidget.setText(values == null ? "" : StringUtil.asString(values, delimiter + ' ')); + } + + protected String[] textWidgetValues(Text textWidget) { + + String values = textWidget.getText().trim(); + + if (StringUtil.isEmpty(values)) return StringUtil.EMPTY_STRINGS; + + String[] valueSet = values.split(delimiter); + List valueList = new ArrayList(valueSet.length); + + for (int i=0; i 0) valueList.add(str); + } + + return (String[])valueList.toArray(new String[valueList.size()]); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractRulePanelManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractRulePanelManager.java new file mode 100644 index 0000000000..f747fd1cc7 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/AbstractRulePanelManager.java @@ -0,0 +1,61 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; +import net.sourceforge.pmd.util.StringUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + + +/** + * + * @author Brian Remedios + */ +public abstract class AbstractRulePanelManager implements RulePropertyManager { + + protected Rule currentRule; + final protected ValueChangeListener changeListener; + + public AbstractRulePanelManager(ValueChangeListener theListener) { + changeListener = theListener; + } + + protected void addTextListeners(final Text control, final StringProperty desc) { + + control.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + changed(desc, control.getText()); + } + }); + } + + /** + * @param property StringProperty + * @param newValue String + */ + protected void changed(StringProperty property, String newValue) { + + if (currentRule == null) return; + + String cleanValue = newValue.trim(); + String existingValue = currentRule.getProperty(property); + + if (StringUtil.areSemanticEquals(existingValue, cleanValue)) return; + + currentRule.setProperty(property, cleanValue); + changeListener.changed(property, cleanValue); + } + + protected void shutdown(Text control) { + control.setText(""); + control.setEnabled(false); + } + + protected void show(Text control, String value) { + control.setText(value == null ? "" : value); + control.setEnabled(true); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BasicRuleFieldAccessor.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BasicRuleFieldAccessor.java new file mode 100644 index 0000000000..c5247eae51 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BasicRuleFieldAccessor.java @@ -0,0 +1,22 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; + +/** + * + * @author Brian Remedios + */ +public class BasicRuleFieldAccessor implements RuleFieldAccessor { + + public BasicRuleFieldAccessor() { + } + + public String labelFor(Rule rule) { + Comparable value = valueFor(rule); + return value == null ? "" : value.toString(); + } + + public Comparable valueFor(Rule rule) { + throw new RuntimeException("unimplemented method"); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BooleanEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BooleanEditorFactory.java new file mode 100644 index 0000000000..f0fc530ccb --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/BooleanEditorFactory.java @@ -0,0 +1,70 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.BooleanProperty; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * @author Brian Remedios + */ +public class BooleanEditorFactory extends AbstractEditorFactory { + + public static final BooleanEditorFactory instance = new BooleanEditorFactory(); + + + private BooleanEditorFactory() { } + + /** + * Method newEditorOn. + * @param parent Composite + * @param columnIndex int + * @param desc PropertyDescriptor + * @param rule Rule + * @return Control + * @see net.sourceforge.pmd.ui.preferences.br.EditorFactory#newEditorOn(Composite, int, PropertyDescriptor, Rule) + */ + public Control newEditorOn(Composite parent, int columnIndex, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Button butt = new Button(parent, SWT.CHECK); + butt.setText(""); + + if (desc instanceof PropertyDescriptorWrapper) { + + // TODO + return butt; + } + + final BooleanProperty bp = (BooleanProperty)desc; // TODO - do I really have to do this? + + boolean set = ((Boolean)rule.getProperty(desc)).booleanValue(); + butt.setSelection(set); + + butt.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + boolean selected = butt.getSelection(); + if (selected == rule.getProperty(bp)) return; + + rule.setProperty(bp, Boolean.valueOf(selected)); + listener.changed(desc, Boolean.valueOf(selected)); + } + }); + + + return butt; + } + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CellPainterBuilder.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CellPainterBuilder.java new file mode 100644 index 0000000000..c78c480785 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CellPainterBuilder.java @@ -0,0 +1,8 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import org.eclipse.swt.widgets.Tree; + +public interface CellPainterBuilder { + + void addPainterFor(Tree tree, int columnIndex, RuleFieldAccessor getter); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CharacterEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CharacterEditorFactory.java new file mode 100644 index 0000000000..ce6d8ffca0 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/CharacterEditorFactory.java @@ -0,0 +1,91 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.CharacterProperty; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class CharacterEditorFactory extends AbstractEditorFactory { + + public static final CharacterEditorFactory instance = new CharacterEditorFactory(); + + private CharacterEditorFactory() { } + + /** + * Method fillWidget. + * @param textWidget Text + * @param desc PropertyDescriptor + * @param rule Rule + */ + protected void fillWidget(Text textWidget, PropertyDescriptor desc, Rule rule) { + Character val = (Character)rule.getProperty(desc); + textWidget.setText(val == null ? "" : val.toString()); + } + + private static Character charValueIn(Text textControl) { + String newValue = textControl.getText().trim(); + if (newValue.length() == 0) return null; + return Character.valueOf(newValue.charAt(0)); + } + + public Control newEditorOn(Composite parent, int columnIndex, PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); + + fillWidget(text, desc, rule); + + if (desc instanceof PropertyDescriptorWrapper) { + + final PropertyDescriptorWrapper descWrapper = (PropertyDescriptorWrapper)desc; + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Character newValue = charValueIn(text); + Character existingValue = (Character)rule.getProperty(descWrapper); + if (existingValue.equals(newValue)) return; + + rule.setProperty(descWrapper, newValue); + listener.changed(descWrapper, newValue); + } + }); + + return text; + } + + final CharacterProperty cp = (CharacterProperty)desc; // TODO - really necessary? + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Character newValue = charValueIn(text); + Character existingValue = rule.getProperty(cp); + if (existingValue.equals(newValue)) return; + + rule.setProperty(cp, newValue); + listener.changed(cp, newValue); + } + }); + + return text; + + + } + + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ColourManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ColourManager.java new file mode 100644 index 0000000000..5245448c0f --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ColourManager.java @@ -0,0 +1,62 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.pmd.util.StringUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; + +/** + * + * @author Brian Remedios + */ +public class ColourManager { + + private final Display display; + + private final Map coloursByRGB = new HashMap(); + + public ColourManager(Display theDisplay) { + display = theDisplay; + } + + public Color colourFor(String text) { + + if (StringUtil.isEmpty(text)) return display.getSystemColor(SWT.COLOR_WHITE); + + text = text.trim(); + int length = text.length(); + + if (length < 3) return display.getSystemColor(SWT.COLOR_WHITE); + + int posA = length / 3; + int posB = posA * 2; + + int rHash = text.subSequence(0, posA).hashCode(); + int gHash = text.subSequence(posA, posB).hashCode(); + int bHash = text.subSequence(posB, length).hashCode(); + + int colourFractions[] = new int[] { + (int)(Math.log10(rHash) % 1 * 255), + (int)(Math.log10(gHash) % 1 * 255), + (int)(Math.log10(bHash) % 1 * 255) + }; + + Color colour = coloursByRGB.get(colourFractions); + if (colour != null) return colour; + + colour = new Color(display, colourFractions[0], colourFractions[1], colourFractions[2]); + coloursByRGB.put(colourFractions, colour); + return colour; + } + + public void dispose() { + + Iterator iter = coloursByRGB.values().iterator(); + while (iter.hasNext()) iter.next().dispose(); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/DescriptionPanelManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/DescriptionPanelManager.java new file mode 100644 index 0000000000..17c329658e --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/DescriptionPanelManager.java @@ -0,0 +1,68 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.util.StringUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class DescriptionPanelManager extends AbstractRulePanelManager { + + private Text descriptionBox; + + public DescriptionPanelManager(ValueChangeListener theListener) { + super(theListener); + } + + public Control setupOn(Composite parent) { + + descriptionBox = buildDescriptionBox(parent); + + descriptionBox.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + + if (currentRule == null) return; + + String cleanValue = descriptionBox.getText().trim(); + String existingValue = currentRule.getDescription(); + + if (StringUtil.areSemanticEquals(existingValue, cleanValue)) return; + + currentRule.setDescription(cleanValue); + changeListener.changed(null, cleanValue); + } + }); + + return descriptionBox; + } + + /** + * Method buildDescriptionBox. + * @param parent Composite + * @return Text + */ + private Text buildDescriptionBox(Composite parent) { + + return new Text(parent, SWT.BORDER | SWT.WRAP | SWT.MULTI); + } + + public void showRule(Rule rule) { + + currentRule = rule; + + if (rule == null) { + shutdown(descriptionBox); + } else { + show(descriptionBox, rule.getDescription().trim()); + } + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EditorFactory.java new file mode 100644 index 0000000000..66de990cb6 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EditorFactory.java @@ -0,0 +1,34 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * @author Brian Remedios + */ +public interface EditorFactory { + + /** + * Return the total number of columns required to position all the widgets + * for the editor in a row. + * + * @return int + */ + int columnsRequired(); + + /** + * Creates and parks a new editor widget(s) on the parent for the specified descriptor + * and rule. It does not perform any layout operations or set form attachments. + * + * @param parent Composite + * @param columnIndex int + * @param desc PropertyDescriptor + * @param rule Rule + * @param listener ValueChangeListener + * @return Control + */ + Control newEditorOn(Composite parent, int columnIndex, PropertyDescriptor desc, Rule rule, ValueChangeListener listener); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EnumerationEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EnumerationEditorFactory.java new file mode 100644 index 0000000000..24ea80f8ec --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/EnumerationEditorFactory.java @@ -0,0 +1,62 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * + * @author Brian Remedios + */ +public class EnumerationEditorFactory extends AbstractEditorFactory { + + public static final EnumerationEditorFactory instance = new EnumerationEditorFactory(); + + private EnumerationEditorFactory() { } + + private static String[] labelsIn(Object[][] items) { + + String[] labels = new String[items.length]; + for (int i=0; i desc, Rule rule, ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + final Combo combo = new Combo(parent, SWT.READ_ONLY); + + if (desc instanceof PropertyDescriptorWrapper) { + + // TODO + return combo; + } + + final EnumeratedProperty ep = (EnumeratedProperty)desc; + + combo.setItems(labelsIn(ep.choices())); + + combo.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + + + } + }); + + return combo; + } + + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ExclusionPanelManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ExclusionPanelManager.java new file mode 100644 index 0000000000..46e24685f0 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ExclusionPanelManager.java @@ -0,0 +1,121 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +/** + * Manages the UI form for rule exclusion fields for a designated property rule. + * + * @author Brian Remedios + */ +public class ExclusionPanelManager extends AbstractRulePanelManager { + + private Text excludeWidget; + private Text xpathWidget; + private Composite excludeColour; + private Composite xPathColour; + private ColourManager colourManager; + + /** + * Constructor for ExclusionPanelManager. + * @param listener ValueChangeListener + */ + public ExclusionPanelManager(ValueChangeListener listener) { + super(listener); + } + + private void addListeners(final Text control, final StringProperty desc, final Control colourWindow) { + + addTextListeners(control, desc); + + control.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + colourWindow.setBackground( + colourManager.colourFor(control.getText()) + ); + } + }); + } + + /** + * @param parent Composite + * @param regexExclusionLabel String + * @param xpathExclusionLabel String + * @return Control + */ + public Control setupOn(Composite parent, String regexExclusionLabel, String xpathExclusionLabel) { + + colourManager = new ColourManager(parent.getDisplay()); + + GridData gridData = new GridData(GridData.FILL_HORIZONTAL); + + Composite panel = new Composite(parent, 0); + GridLayout layout = new GridLayout(2, false); + panel.setLayout(layout); + + Label labelA = new Label(panel, 0); + labelA.setText(regexExclusionLabel); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.horizontalSpan = 2; + labelA.setLayoutData(gridData); + + gridData.grabExcessHorizontalSpace = true; + excludeWidget = new Text(panel, SWT.BORDER | SWT.WRAP | SWT.MULTI); + gridData = new GridData(GridData.FILL_BOTH); + gridData.grabExcessHorizontalSpace = true; + gridData.horizontalSpan = 1; + excludeWidget.setLayoutData(gridData); + + excludeColour = new Composite(panel, SWT.BORDER); + addListeners(excludeWidget, Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR, excludeColour); + + Label labelB = new Label(panel, 0); + labelB.setText(xpathExclusionLabel); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.horizontalSpan = 2; + labelB.setLayoutData(gridData); + + gridData = new GridData(GridData.FILL_BOTH); + gridData.horizontalSpan = 1; + gridData.grabExcessHorizontalSpace = true; + xpathWidget = new Text(panel, SWT.BORDER | SWT.WRAP | SWT.MULTI); + xpathWidget.setLayoutData(gridData); + + xPathColour = new Composite(panel, SWT.BORDER); + xPathColour.setSize(1,1); + addListeners(xpathWidget, Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR, xPathColour); + + panel.pack(); + + return panel; + } + + /** + * Method showRule. + * @param rule Rule + */ + public void showRule(Rule rule) { + + currentRule = rule; + + if (rule == null) { + shutdown(excludeWidget); + shutdown(xpathWidget); + return; + } + + show(excludeWidget, rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR)); + show(xpathWidget, rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR)); + } +} + diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/FormArranger.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/FormArranger.java new file mode 100644 index 0000000000..39aa03ad3d --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/FormArranger.java @@ -0,0 +1,114 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.Map; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; + +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * + * @author Brian Remedios + */ +public class FormArranger { + + private final Composite parent; + private final Map editorFactoriesByValueType; + private final ValueChangeListener changeListener; + private Rule rule; + + private Control[][] widgets; + + /** + * Constructor for FormArranger. + * @param theParent Composite + * @param factories Map + */ + public FormArranger(Composite theParent, Map factories, ValueChangeListener listener) { + parent = theParent; + editorFactoriesByValueType = factories; + changeListener = listener; + } + + /** + * Method factoryFor. + * @param desc PropertyDescriptor + * @return EditorFactory + */ + private EditorFactory factoryFor(PropertyDescriptor desc) { + return editorFactoriesByValueType.get(desc.type()); + } + + private void clearChildren() { + Control[] kids = parent.getChildren(); + for (int i=0; i, Object> valuesByDescriptor = PMDPreferencePage.filteredPropertiesOf(rule); + if (valuesByDescriptor.isEmpty()) return; + + PropertyDescriptor[] orderedDescs = (PropertyDescriptor[])valuesByDescriptor.keySet().toArray(new PropertyDescriptor[valuesByDescriptor.size()]); + + int maxColumns = 2; + int rowCount = 0; // count up the actual rows with widgets needed, not all have editors yet + for (int i=0; i 0) { + parent.pack(); + } + } + + /** + * @param factory EditorFactory + * @param rowIndex int + * @param desc PropertyDescriptor + * @return boolean + */ + private boolean addRowWidgets(EditorFactory factory, int rowIndex, PropertyDescriptor desc) { + + if (factory == null) return false; + + int columns = factory.columnsRequired(); + for (int i=0; i desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Spinner spinner = new Spinner(parent, SWT.SINGLE | SWT.BORDER); + + if (desc instanceof PropertyDescriptorWrapper) { + + // TODO + return spinner; + } + + + final IntegerProperty ip = (IntegerProperty)desc; // TODO - do I really have to do this? + + int val = ((Number)rule.getProperty(desc)).intValue(); + + spinner.setMinimum(ip.lowerLimit().intValue()); + spinner.setMaximum(ip.upperLimit().intValue()); + spinner.setSelection(val); + + spinner.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent event) { + int newValue = spinner.getSelection(); + if (newValue == rule.getProperty(ip)) return; + + rule.setProperty(ip, Integer.valueOf(newValue)); + listener.changed(desc, Integer.valueOf(newValue)); + } + }); + + return spinner; + } + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiIntegerEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiIntegerEditorFactory.java new file mode 100644 index 0000000000..8475c186bc --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiIntegerEditorFactory.java @@ -0,0 +1,59 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.IntegerMultiProperty; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +public class MultiIntegerEditorFactory extends AbstractMultiValueEditorFactory { + + public static final MultiIntegerEditorFactory instance = new MultiIntegerEditorFactory(); + + private static final Integer[] emptyIntSet = new Integer[0]; + + private MultiIntegerEditorFactory() { } + + private Integer[] currentIntegers(Text textWidget) { + + String[] numberStrings = textWidgetValues(textWidget); + if (numberStrings.length == 0) return emptyIntSet; + + List ints = new ArrayList(numberStrings.length); + + Integer intrg = null; + + for (int i=0; i desc, final Rule rule, final ValueChangeListener listener) { + + final IntegerMultiProperty tmp = (IntegerMultiProperty)desc; // TODO - really necessary? + + textWidget.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Integer[] newValue = currentIntegers(textWidget); + Integer[] existingValue = rule.getProperty(tmp); + if (Util.areSemanticEquals(existingValue, newValue)) return; + + rule.setProperty(tmp, newValue); + fillWidget(textWidget, desc, rule); // display the accepted values + listener.changed(desc, newValue); + } + }); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiStringEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiStringEditorFactory.java new file mode 100644 index 0000000000..042139f405 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiStringEditorFactory.java @@ -0,0 +1,38 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.StringMultiProperty; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class MultiStringEditorFactory extends AbstractMultiValueEditorFactory { + + public static final MultiStringEditorFactory instance = new MultiStringEditorFactory(); + + private MultiStringEditorFactory() { } + + protected void configure(final Text textWidget, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + final StringMultiProperty smp = (StringMultiProperty)desc; // TODO - really necessary? + + textWidget.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + String[] newValues = textWidgetValues(textWidget); + String[] existingValues = rule.getProperty(smp); + if (Util.areSemanticEquals(existingValues, newValues)) return; + + rule.setProperty(smp, newValues); + fillWidget(textWidget, desc, rule); // reload with latest scrubbed values + listener.changed(desc, newValues); + } + }); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiTypeEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiTypeEditorFactory.java new file mode 100644 index 0000000000..c04ce04fdb --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/MultiTypeEditorFactory.java @@ -0,0 +1,78 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.TypeMultiProperty; +import net.sourceforge.pmd.util.ClassUtil; +import net.sourceforge.pmd.util.StringUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class MultiTypeEditorFactory extends AbstractMultiValueEditorFactory { + + public static final MultiTypeEditorFactory instance = new MultiTypeEditorFactory(); + + private MultiTypeEditorFactory() { } + + public static String[] shortNamesFor(Class[] types) { + String[] typeNames = new String[types.length]; + for (int i=0; i desc, Rule rule) { + + Class[] values = (Class[])rule.getProperty(desc); + if (values == null) { + textWidget.setText(""); + return; + } + + String[] typeNames = shortNamesFor(values); + + textWidget.setText(values == null ? "" : StringUtil.asString(typeNames, delimiter + ' ')); + } + + private Class[] currentTypes(Text textWidget) { + + String[] typeNames = textWidgetValues(textWidget); + if (typeNames.length == 0) return ClassUtil.EMPTY_CLASS_ARRAY; + + List types = new ArrayList(typeNames.length); + + for (int i=0; i desc, final Rule rule, final ValueChangeListener listener) { + + final TypeMultiProperty tmp = (TypeMultiProperty)desc; // TODO - really necessary? + + textWidget.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Class[] newValue = currentTypes(textWidget); + Class[] existingValue = rule.getProperty(tmp); + if (Util.areSemanticEquals(existingValue, newValue)) return; + + rule.setProperty(tmp, newValue); + fillWidget(textWidget, desc, rule); // display the accepted values + listener.changed(desc, newValue); + } + }); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PMDPreferencePage.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PMDPreferencePage.java new file mode 100644 index 0000000000..b24cd7309d --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PMDPreferencePage.java @@ -0,0 +1,1022 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleSet; +import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; +import net.sourceforge.pmd.eclipse.runtime.writer.IRuleSetWriter; +import net.sourceforge.pmd.eclipse.runtime.writer.WriterException; +import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; +import net.sourceforge.pmd.eclipse.ui.preferences.RuleDialog; +import net.sourceforge.pmd.eclipse.ui.preferences.RuleSetSelectionDialog; +import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.util.CollectionUtil; +import net.sourceforge.pmd.util.designer.Designer; + +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferencePage; +import org.eclipse.jface.viewers.CheckboxTreeViewer; +import org.eclipse.jface.viewers.ComboViewer; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +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.layout.RowLayout; +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.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * This page is used to modify preferences only. They are stored in the preference store that belongs to + * the main plug-in class. That way, preferences can be accessed directly via the preference store. + * + * @author Philippe Herlin + * @author Brian Remedios + */ + +public class PMDPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, ValueChangeListener, RuleSortListener { + + public static PMDPreferencePage activeInstance = null; + + // columns shown in the rule treetable in the desired order + private static final RuleColumnDescriptor[] availableColumns = new RuleColumnDescriptor[] { + RuleColumnDescriptor.name, + RuleColumnDescriptor.priorityName, + RuleColumnDescriptor.since, + RuleColumnDescriptor.ruleSetName, + RuleColumnDescriptor.ruleType, + RuleColumnDescriptor.minLangVers, + RuleColumnDescriptor.properties + }; + private static final Set availableColumnSet = CollectionUtil.asSet(availableColumns); + + // last item in this list is the grouping used at startup + private static final Object[][] groupingChoices = new Object[][] { + { RuleColumnDescriptor.ruleSetName, "Rule set" }, + { RuleColumnDescriptor.since, "PMD version" }, + { RuleColumnDescriptor.priorityName, "Priority" }, + { RuleColumnDescriptor.ruleType, "Type" }, + { RuleColumnDescriptor.filterExpression, "Regex filter" }, + { null, "" } + }; + + // properties that should not be shown in the PerRuleProperty page + private static final PropertyDescriptor[] excludedRuleProperties = new PropertyDescriptor[] { + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR, + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR, + XPathRule.XPATH_DESCRIPTOR, + XPathRule.VERSION_DESCRIPTOR, + }; + + private static final Map formattersByType = new HashMap(); + + static { + formattersByType.put(String.class, ValueFormatter.StringFormatter); + formattersByType.put(String[].class, ValueFormatter.MultiStringFormatter); + formattersByType.put(Boolean.class, ValueFormatter.BooleanFormatter); + formattersByType.put(Integer.class, ValueFormatter.NumberFormatter); + formattersByType.put(Double.class, ValueFormatter.NumberFormatter); + formattersByType.put(Character.class, ValueFormatter.ObjectFormatter); + formattersByType.put(Class.class, ValueFormatter.TypeFormatter); + formattersByType.put(Class[].class, ValueFormatter.MultiTypeFormatter); + } + + private CheckboxTreeViewer ruleTreeViewer; + private Button addRuleButton; + private Button removeRuleButton; + private Button editRuleButton; + private RuleSet ruleSet; // TODO - what is this used for? - br + private TabFolder tabFolder; + private Set checkedRules = new HashSet(); + + private RulePropertyManager[] rulePropertyManagers; + + private boolean sortDescending; + private RuleFieldAccessor columnSorter = RuleFieldAccessor.name; // initial sort + private RuleColumnDescriptor groupingColumn; + + private boolean modified = false; + private static PMDPlugin plugin = PMDPlugin.getDefault(); + + /** + * @see IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + setDescription(getMessage(StringKeys.MSGKEY_PREF_RULESET_TITLE)); + activeInstance = this; + } + + /** + * @see org.eclipse.jface.preference.PreferencePage#performDefaults() + */ + protected void performDefaults() { + populateRuleTable(); + super.performDefaults(); + } + + /** + * @see org.eclipse.jface.preference.IPreferencePage#performOk() + */ + public boolean performOk() { + if (modified) { + updateRuleSet(); + rebuildProjects(); + } + + return super.performOk(); + } + + /** + * @see org.eclipse.jface.preference.PreferencePage#createContents(Composite) + */ + protected Control createContents(Composite parent) { + Composite composite = new Composite(parent, SWT.NULL); + layoutControls(composite); + return composite; + } + + /** + * Main layout + * @param parent Composite + */ + private void layoutControls(Composite parent) { + + // Create the controls (order is important !) + Composite groupCombo = buildGroupCombo(parent, "Rules grouped by "); + + Tree ruleTree = buildRuleTreeViewer(parent); + groupBy(null); + + Composite ruleTableButtons = buildRuleTableButtons(parent); + TabFolder tabFolder = buildTabFolder(parent); + Composite rulePropertiesTableButton = buildRulePropertiesTableButtons(parent); + + // Place controls on the layout + GridLayout gridLayout = new GridLayout(3, false); + parent.setLayout(gridLayout); + + GridData data = new GridData(); + data.horizontalSpan = 3; + groupCombo.setLayoutData(data); + + data = new GridData(); + data.heightHint = 200; + data.widthHint = 350; + data.horizontalSpan = 1; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + data.grabExcessVerticalSpace = true; + ruleTree.setLayoutData(data); + + data = new GridData(); + data.horizontalSpan = 1; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + ruleTableButtons.setLayoutData(data); + + data = new GridData(); + data.horizontalSpan = 2; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + data.heightHint = 150; + data.widthHint = 500; + tabFolder.setLayoutData(data); + + data = new GridData(); + data.horizontalSpan = 1; + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.FILL; + rulePropertiesTableButton.setLayoutData(data); + } + + public static Map, Object> filteredPropertiesOf(Rule rule) { + + Map, Object> valuesByProp = rule.getPropertiesByPropertyDescriptor(); + + for (int i=0; i datatype) { + + ValueFormatter formatter = formattersByType.get(datatype); + if (formatter != null) { + formatter.format(value, target); + return; + } + + target.append(value); // should not get here..breakpoint here + } + + /** + * @param rule Rule + * @return String + */ + public static String propertyStringFrom(Rule rule) { + + Map, Object> valuesByProp = filteredPropertiesOf(rule); + + if (valuesByProp.isEmpty()) return ""; + StringBuilder sb = new StringBuilder(); + + Iterator> iter = valuesByProp.keySet().iterator(); + + PropertyDescriptor desc = iter.next(); + sb.append(desc.name()).append(": "); + sb.append(rule.getProperty(desc)); + + while (iter.hasNext()) { + desc = iter.next(); + sb.append(", ").append(desc.name()).append(": "); + formatValueOn(sb, rule.getProperty(desc), desc.type()); + } + return sb.toString(); + } + + public static String ruleSetNameFrom(Rule rule) { + + String name = rule.getRuleSetName(); + int pos = name.toUpperCase().indexOf("RULES"); + return pos < 0 ? name : name.substring(0, pos-1); + } + + private void redrawTable() { + groupBy(groupingColumn); + } + + /** + * @param parent Composite + * @return Combo + */ + private Composite buildGroupCombo(Composite parent, String comboLabel) { + + final Composite panel = new Composite(parent, 0); + RowLayout layout = new RowLayout(SWT.HORIZONTAL); + panel.setLayout(layout); + + Label label = new Label(panel, 0); + label.setText(comboLabel); + + + final ComboViewer viewer = new ComboViewer(panel, SWT.DROP_DOWN); + viewer.setLabelProvider(new LabelProvider() { + public String getText(Object element) { return ((Object[])element)[1].toString(); } + }); + viewer.add(groupingChoices); + viewer.setSelection(new StructuredSelection(groupingChoices[groupingChoices.length-1]), true); + + final Combo combo = viewer.getCombo(); + + combo.addSelectionListener( new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + int pos = combo.getSelectionIndex(); + Object[] choice = groupingChoices[pos]; + groupingColumn = (RuleColumnDescriptor)choice[0]; + redrawTable(); + } + }); + + return panel; + } + + /** + * Method buildTabFolder. + * @param parent Composite + * @return TabFolder + */ + private TabFolder buildTabFolder(Composite parent) { + + tabFolder = new TabFolder(parent, SWT.TOP); + +// buildPropertyTab(tabFolder, 0); + + rulePropertyManagers = new RulePropertyManager[] { + buildPropertyTab(tabFolder, 0), + buildDescriptionTab(tabFolder, 1), + buildUsageTab(tabFolder, 2) + }; + + tabFolder.pack(); + return tabFolder; + } + + /** + * @param parent TabFolder + * @param index int + */ + private RulePropertyManager buildPropertyTab(TabFolder parent, int index) { + + TabItem propertyTab = new TabItem(parent, 0, index); + propertyTab.setText("Properties"); + + PerRulePropertyPanelManager manager = new PerRulePropertyPanelManager(this); + propertyTab.setControl( + manager.setupOn(parent, this) + ); + return manager; + } + + /** + * @param parent TabFolder + * @param index int + */ + private RulePropertyManager buildDescriptionTab(TabFolder parent, int index) { + + TabItem tab = new TabItem(parent, 0, index); + tab.setText("Description"); + + DescriptionPanelManager manager = new DescriptionPanelManager(this); + tab.setControl( + manager.setupOn(parent) + ); + return manager; + } + + /** + * Method buildUsageTab. + * @param parent TabFolder + * @param index int + */ + private RulePropertyManager buildUsageTab(TabFolder parent, int index) { + + TabItem tab = new TabItem(parent, 0, index); + tab.setText("Usage"); + + ExclusionPanelManager manager = new ExclusionPanelManager(this); + tab.setControl( + manager.setupOn( + parent, + "Exclusion regular expression", + "XPath exclusion expression" + ) + ); + return manager; + } + + /** + * Create buttons for rule table management + * @param parent Composite + * @return Composite + */ + private Composite buildRuleTableButtons(Composite parent) { + Composite composite = new Composite(parent, SWT.NULL); + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + gridLayout.verticalSpacing = 3; + composite.setLayout(gridLayout); + + removeRuleButton = buildRemoveRuleButton(composite); + editRuleButton = buildEditRuleButton(composite); + addRuleButton = buildAddRuleButton(composite); + Button importRuleSetButton = buildImportRuleSetButton(composite); + Button exportRuleSetButton = buildExportRuleSetButton(composite); + Button clearAllButton = buildClearAllButton(composite); + Button ruleDesignerButton = buildRuleDesignerButton(composite); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + removeRuleButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + editRuleButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + addRuleButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + importRuleSetButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + exportRuleSetButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + clearAllButton.setLayoutData(data); + + data = new GridData(); + data.horizontalAlignment = GridData.FILL; + data.grabExcessVerticalSpace = true; + data.verticalAlignment = GridData.END; + ruleDesignerButton.setLayoutData(data); + + return composite; + } + + /** + * Create buttons for rule properties table management + * @param parent Composite + * @return Composite + */ + private Composite buildRulePropertiesTableButtons(Composite parent) { + Composite composite = new Composite(parent, SWT.NULL); + RowLayout rowLayout = new RowLayout(); + rowLayout.type = SWT.VERTICAL; + rowLayout.wrap = false; + rowLayout.pack = false; + composite.setLayout(rowLayout); + + return composite; + } + + /** + * Build rule table viewer + * @param parent Composite + * @return Tree + */ + private Tree buildRuleTreeViewer(Composite parent) { + + int treeStyle = SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION | SWT.CHECK; + ruleTreeViewer = new CheckboxTreeViewer(parent, treeStyle); + + Tree ruleTree = ruleTreeViewer.getTree(); + ruleTree.setLinesVisible(true); + ruleTree.setHeaderVisible(true); + + ruleTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + IStructuredSelection selection = (IStructuredSelection)event.getSelection(); + Object item = selection.getFirstElement(); + selectedRule((item instanceof Rule) ? (Rule)item : null); + } + }); + + ruleTree.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + if (event.detail == SWT.CHECK) { + TreeItem item = (TreeItem) event.item; + boolean checked = item.getChecked(); + checkItems(item, checked); + checkPath(item.getParentItem(), checked, false); + } + // if (!checkedRules.isEmpty()) System.out.println(checkedRules.iterator().next()); + } + }); + + // ruleTreeViewer.setSorter(this.ruleTableViewerSorter); + + return ruleTree; + } + + /** + * @param rule Rule + */ + private void selectedRule(Rule rule) { + + for (RulePropertyManager manager : rulePropertyManagers) manager.showRule(rule); + + removeRuleButton.setEnabled(rule != null); + editRuleButton.setEnabled(rule != null); + + // updatePropertyEditorFor(rule); + } + + /** + * Method groupBy. + * @param chosenColumn RuleColumnDescriptor + */ + private void groupBy(RuleColumnDescriptor chosenColumn) { + + if (chosenColumn == null) { + setupTreeColumns(availableColumns, null); + return; + } + + RuleColumnDescriptor[] remainingCols = availableColumns; + + if (availableColumnSet.contains(chosenColumn)) { + remainingCols = new RuleColumnDescriptor[availableColumns.length-1]; + int j=0; + for (int i=0; i0;) ruleTree.getColumns()[0].dispose(); + + for (int i = 0; i iter = selectedRuleSet.getRules().iterator(); + while (iter.hasNext()) { + Rule rule = (Rule)iter.next(); + rule.setRuleSetName("pmd-eclipse"); + ruleSet.addRule(rule); + } + } + setModified(true); + try { + refresh(); + } catch (Throwable t) { + plugin.logError("Exception when refreshing the rule table", t); + } + } catch (RuntimeException e) { + plugin.showError(getMessage(StringKeys.MSGKEY_ERROR_IMPORTING_RULESET), e); + } + } + } + }); + + return button; + } + + /** + * Build the export rule set button + * @param parent Composite + * @return Button + */ + private Button buildExportRuleSetButton(Composite parent) { + Button button = new Button(parent, SWT.PUSH | SWT.LEFT); + button.setText(getMessage(StringKeys.MSGKEY_PREF_RULESET_BUTTON_EXPORTRULESET)); + button.setEnabled(true); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); + String fileName = dialog.open(); + if (fileName != null) { + try { + File file = new File(fileName); + boolean flContinue = true; + if (file.exists()) { + flContinue = MessageDialog.openConfirm(getShell(), + getMessage(StringKeys.MSGKEY_CONFIRM_TITLE), + getMessage(StringKeys.MSGKEY_CONFIRM_RULESET_EXISTS)); + } + + InputDialog input = null; + if (flContinue) { + input = new InputDialog(getShell(), + getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_TITLE), + getMessage(StringKeys.MSGKEY_PREF_RULESET_DIALOG_RULESET_DESCRIPTION), + ruleSet.getDescription() == null ? "" : ruleSet.getDescription().trim(), null); + flContinue = input.open() == InputDialog.OK; + } + + if (flContinue) { + ruleSet.setName(Util.getFileNameWithoutExtension(file.getName())); + ruleSet.setDescription(input.getValue()); + OutputStream out = new FileOutputStream(fileName); + IRuleSetWriter writer = plugin.getRuleSetWriter(); + writer.write(out, ruleSet); + out.close(); + MessageDialog.openInformation(getShell(), getMessage(StringKeys.MSGKEY_INFORMATION_TITLE), + getMessage(StringKeys.MSGKEY_INFORMATION_RULESET_EXPORTED)); + } + } catch (IOException e) { + plugin.showError(getMessage(StringKeys.MSGKEY_ERROR_EXPORTING_RULESET), e); + } catch (WriterException e) { + plugin.showError(getMessage(StringKeys.MSGKEY_ERROR_EXPORTING_RULESET), e); + } + } + } + }); + + return button; + } + + /** + * Build the clear all button + * @param parent Composite + * @return Button + */ + private Button buildClearAllButton(Composite parent) { + Button button = new Button(parent, SWT.PUSH | SWT.LEFT); + button.setText(getMessage(StringKeys.MSGKEY_PREF_RULESET_BUTTON_CLEARALL)); + button.setEnabled(true); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + if (MessageDialog.openConfirm(getShell(), getMessage(StringKeys.MSGKEY_CONFIRM_TITLE), + getMessage(StringKeys.MSGKEY_CONFIRM_CLEAR_RULESET))) { + ruleSet.getRules().clear(); + setModified(true); + try { + refresh(); + } catch (Throwable t) { + plugin.logError("Exception when refreshing the rule table", t); + } + } + } + }); + + return button; + } + + /** + * Build the Rule Designer button + * @param parent Composite + * @return Button + */ + private Button buildRuleDesignerButton(Composite parent) { + Button button = new Button(parent, SWT.PUSH | SWT.LEFT); + button.setText(getMessage(StringKeys.MSGKEY_PREF_RULESET_BUTTON_RULEDESIGNER)); + button.setEnabled(true); + button.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + // TODO Is this cool from Eclipse? Is there a nicer way to spawn a J2SE Application? + new Thread(new Runnable() { + public void run() { + Designer.main(new String[] { "-noexitonclose" }); + } + }).start(); + } + }); + + return button; + } + + /** + * Populate the rule table + */ + private void populateRuleTable() { + RuleSet defaultRuleSet = plugin.getPreferencesManager().getRuleSet(); + ruleSet = new RuleSet(); + ruleSet.addRuleSet(defaultRuleSet); + ruleSet.setName(defaultRuleSet.getName()); + ruleSet.setDescription(Util.asCleanString(defaultRuleSet.getDescription())); + ruleSet.addExcludePatterns(defaultRuleSet.getExcludePatterns()); + ruleSet.addIncludePatterns(defaultRuleSet.getIncludePatterns()); + ruleTreeViewer.setInput(ruleSet); + + checkSelections(); + } + + private void checkSelections() { + ruleTreeViewer.setCheckedElements(checkedRules.toArray()); + } + + /** + * Helper method to shorten message access + * @param key a message key + * @return requested message + */ + protected String getMessage(String key) { + return plugin.getStringTable().getString(key); + } + + /** + * @see org.eclipse.jface.preference.PreferencePage#doGetPreferenceStore() + */ + protected IPreferenceStore doGetPreferenceStore() { + return plugin.getPreferenceStore(); + } + + /** + * Returns the activeInstance. + * @return PMDPreferencePage + */ + public static PMDPreferencePage getActiveInstance() { + return activeInstance; + } + + /** + * Returns the isModified. + * @return boolean + */ + public boolean isModified() { + return modified; + } + + /** + * Sets the isModified. + * @param isModified The isModified to set + */ + public void setModified(boolean isModified) { + this.modified = isModified; + } + + /** + * Refresh the list + */ + protected void refresh() { + try { + ruleTreeViewer.getControl().setRedraw(false); + ruleTreeViewer.refresh(); + } catch (ClassCastException e) { + plugin.logError("Ignoring exception while refreshing table", e); + } finally { + ruleTreeViewer.getControl().setRedraw(true); + } + } + + /** + * Update the configured rule set + * Update also all configured projects + */ + private void updateRuleSet() { + try { + ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(getShell()); + monitorDialog.run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + plugin.getPreferencesManager().setRuleSet(ruleSet); + } + }); + } catch (InterruptedException e) { + plugin.logError("Exception updating all projects after a preference change", e); + } catch (InvocationTargetException e) { + plugin.logError("Exception updating all projects after a preference change", e); + } + } + + /** + * If user wants to, rebuild all projects + */ + private void rebuildProjects() { + if (MessageDialog.openQuestion(getShell(), getMessage(StringKeys.MSGKEY_QUESTION_TITLE), + getMessage(StringKeys.MSGKEY_QUESTION_RULES_CHANGED))) { + try { + ProgressMonitorDialog monitorDialog = new ProgressMonitorDialog(getShell()); + monitorDialog.run(true, true, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + ResourcesPlugin.getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, monitor); + } catch (CoreException e) { + plugin.logError( + "Exception building all projects after a preference change", e); + } + } + }); + } catch (InterruptedException e) { + plugin.logError("Exception building all projects after a preference change", e); + } catch (InvocationTargetException e) { + plugin.logError("Exception building all projects after a preference change", e); + } + } + } + + /** + * Select and show a particular rule in the table + * @param rule Rule + */ + protected void selectAndShowRule(Rule rule) { + Tree tree = ruleTreeViewer.getTree(); + TreeItem[] items = tree.getItems(); + for (int i = 0; i < items.length; i++) { + Rule itemRule = (Rule)items[i].getData(); + if (itemRule.equals(rule)) { + // tree.setSelection(tree.indexOf(items[i])); + tree.showSelection(); + break; + } + } + } + + public void changed(PropertyDescriptor desc, Object newValue) { + // TODO enhance to recognize default values + modified = true; + ruleTreeViewer.refresh(); + } + + public void sortBy(RuleFieldAccessor accessor) { + + if (columnSorter == accessor) { + sortDescending = !sortDescending; + } else { + columnSorter = accessor; + } + redrawTable(); + } + +} \ No newline at end of file diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PerRulePropertyPanelManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PerRulePropertyPanelManager.java new file mode 100644 index 0000000000..9bf16e0cdb --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PerRulePropertyPanelManager.java @@ -0,0 +1,60 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.HashMap; +import java.util.Map; + +import net.sourceforge.pmd.Rule; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TabFolder; + +/** + * + * @author Brian Remedios + */ +public class PerRulePropertyPanelManager extends AbstractRulePanelManager { + + private Composite composite; + private FormArranger formArranger; + + private static final Map editorFactoriesByPropertyType; + + static { + editorFactoriesByPropertyType = new HashMap(); + + editorFactoriesByPropertyType.put(Boolean.class, BooleanEditorFactory.instance); + editorFactoriesByPropertyType.put(String.class, StringEditorFactory.instance); + editorFactoriesByPropertyType.put(Integer.class, IntegerEditorFactory.instance); + editorFactoriesByPropertyType.put(Float.class, RealNumberEditorFactory.instance); + editorFactoriesByPropertyType.put(Double.class, RealNumberEditorFactory.instance); + editorFactoriesByPropertyType.put(Object.class, EnumerationEditorFactory.instance); + editorFactoriesByPropertyType.put(Character.class, CharacterEditorFactory.instance); + + editorFactoriesByPropertyType.put(Class.class, TypeEditorFactory.instance); + editorFactoriesByPropertyType.put(Class[].class, MultiTypeEditorFactory.instance); + editorFactoriesByPropertyType.put(String[].class, MultiStringEditorFactory.instance); + editorFactoriesByPropertyType.put(Integer[].class, MultiIntegerEditorFactory.instance); + } + + public PerRulePropertyPanelManager(ValueChangeListener theListener) { + super(theListener); + } + + public Control setupOn(TabFolder parent, ValueChangeListener changeListener) { + + composite = new Composite(parent, SWT.NONE); + + formArranger = new FormArranger(composite, editorFactoriesByPropertyType, changeListener); + + return composite; + } + + public void showRule(Rule rule) { + + currentRule = rule; + + formArranger.arrangeFor(rule); + } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PropertyChangeListener.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PropertyChangeListener.java new file mode 100644 index 0000000000..4a6e43c04e --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/PropertyChangeListener.java @@ -0,0 +1,12 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; + +/** + * + * @author Brian Remedios + */ +public interface PropertyChangeListener { + + void changed(PropertyDescriptor descriptor, Object newValue); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RealNumberEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RealNumberEditorFactory.java new file mode 100644 index 0000000000..fc1a29fe61 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RealNumberEditorFactory.java @@ -0,0 +1,62 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.FloatProperty; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class RealNumberEditorFactory extends AbstractEditorFactory { + + public static final RealNumberEditorFactory instance = new RealNumberEditorFactory(); + + + private RealNumberEditorFactory() { } + + public Control newEditorOn(Composite parent, int columnIndex, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Text text = new Text(parent, SWT.SINGLE); // TODO use a number-only widget + + if (desc instanceof PropertyDescriptorWrapper) { + + // TODO + return text; + } + + Number val = (Number)rule.getProperty(desc); + text.setText(val == null ? "" : val.toString()); + + final FloatProperty fp = (FloatProperty)desc; + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + String newValue = text.getText(); + + rule.setProperty(fp, Float.valueOf(newValue)); + listener.changed(fp, Float.valueOf(newValue)); + } + }); + + return text; + } + + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleColumnDescriptor.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleColumnDescriptor.java new file mode 100644 index 0000000000..9aa0f0fbbf --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleColumnDescriptor.java @@ -0,0 +1,97 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeColumn; + +/** + * + * @author Brian Remedios + */ +public class RuleColumnDescriptor { + + private String label; + private int alignment; + private int width; + private RuleFieldAccessor accessor; + private boolean isResizeable; + private CellPainterBuilder painterBuilder; + + public static final RuleColumnDescriptor name = new RuleColumnDescriptor("Name", SWT.LEFT, 210, RuleFieldAccessor.name, true); + public static final RuleColumnDescriptor ruleSetName = new RuleColumnDescriptor("Rule set", SWT.LEFT, 160, RuleFieldAccessor.ruleSetName, true); + public static final RuleColumnDescriptor priority = new RuleColumnDescriptor("Priority", SWT.RIGHT, 53, RuleFieldAccessor.priority, false); + public static final RuleColumnDescriptor priorityName = new RuleColumnDescriptor("Priority Name", SWT.LEFT, 80, RuleFieldAccessor.priorityName, true); + public static final RuleColumnDescriptor since = new RuleColumnDescriptor("Since", SWT.RIGHT, 46, RuleFieldAccessor.since, false); + public static final RuleColumnDescriptor usesDFA = new RuleColumnDescriptor("DFA", SWT.LEFT, 60, RuleFieldAccessor.usesDFA, false); + public static final RuleColumnDescriptor externalURL = new RuleColumnDescriptor("URL", SWT.LEFT, 100, RuleFieldAccessor.url, true); + public static final RuleColumnDescriptor properties = new RuleColumnDescriptor("Properties", SWT.LEFT, 100, RuleFieldAccessor.properties, true); + public static final RuleColumnDescriptor minLangVers = new RuleColumnDescriptor("Min Ver", SWT.LEFT, 30, RuleFieldAccessor.minLanguageVersion, false); + + public static final RuleColumnDescriptor exampleCount = new RuleColumnDescriptor("Examples", SWT.RIGHT, 20, RuleFieldAccessor.exampleCount, false); + public static final RuleColumnDescriptor ruleType = new RuleColumnDescriptor("Type", SWT.LEFT, 20, RuleFieldAccessor.ruleType, false); + public static final RuleColumnDescriptor filterExpression = new RuleColumnDescriptor("V.Regex", SWT.RIGHT, 20, RuleFieldAccessor.violationRegex, true); + public static final RuleColumnDescriptor violateXPath = new RuleColumnDescriptor("Filter", SWT.RIGHT, 20, RuleFieldAccessor.violationXPath, true); + + /** + * @param theLabel String + * @param theAlignment int + * @param theWidth int + * @param theAccessor RuleFieldAccessor + * @param resizableFlag boolean + */ + public RuleColumnDescriptor(String theLabel, int theAlignment, int theWidth, RuleFieldAccessor theAccessor, boolean resizableFlag) { + this(theLabel,theAlignment,theWidth,theAccessor,resizableFlag, null); + } + + /** + * @param theLabel String + * @param theAlignment int + * @param theWidth int + * @param theAccessor RuleFieldAccessor + * @param resizableFlag boolean + * @param thePainterBuilder CellPainterBuilder + */ + public RuleColumnDescriptor(String theLabel, int theAlignment, int theWidth, RuleFieldAccessor theAccessor, boolean resizableFlag, CellPainterBuilder thePainterBuilder) { + label = theLabel; + alignment = theAlignment; + width = theWidth; + accessor = theAccessor; + isResizeable = resizableFlag; + painterBuilder = thePainterBuilder; + } + + /** + * @param parent Tree + * @return TreeColumn + */ + public TreeColumn newTreeColumnFor(Tree parent, int columnIndex, final RuleSortListener sortListener) { + TreeColumn tc = new TreeColumn(parent, alignment); + tc.setText(label); + tc.setWidth(width); + tc.setResizable(isResizeable); + + tc.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + sortListener.sortBy(accessor); + } + }); + + if (painterBuilder != null) { + painterBuilder.addPainterFor(tc.getParent(), columnIndex, accessor); + } + + return tc; + } + + /** + * @return String + */ + public String label() { return label; } + + /** + * @return RuleFieldAccessor + */ + public RuleFieldAccessor accessor() { return accessor; } +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleFieldAccessor.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleFieldAccessor.java new file mode 100644 index 0000000000..e689ec77bf --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleFieldAccessor.java @@ -0,0 +1,138 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.lang.rule.XPathRule; + +/** + * A value and label extractor interface for anything implementing the Rule interface + * and may be real fields or values held as properties. + * + * Value returned are typed as comparable to facilitate sorting. Never return null, + * return an empty string instead. + * + * TODO - move this to PMD proper. + * + * @author Brian Remedios + */ +public interface RuleFieldAccessor { + + /** + * @param rule Rule + * @return Comparable + */ + Comparable valueFor(Rule rule); + String labelFor(Rule rule); + + RuleFieldAccessor ruleSetName = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return PMDPreferencePage.ruleSetNameFrom(rule); + } + }; + + RuleFieldAccessor since = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getSince(); + } + }; + + RuleFieldAccessor priority = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return Integer.valueOf(rule.getPriority().getPriority()); + } + }; + + RuleFieldAccessor priorityName = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getPriority().getName(); + } + }; + + RuleFieldAccessor name = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getName(); + } + }; + + RuleFieldAccessor description = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getDescription(); + } + }; + + RuleFieldAccessor usesDFA = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.usesDFA() ? Boolean.TRUE : Boolean.FALSE; + } + }; + + RuleFieldAccessor message = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getMessage(); + } + }; + + RuleFieldAccessor url = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getExternalInfoUrl(); + } + }; + + RuleFieldAccessor properties = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return PMDPreferencePage.propertyStringFrom(rule); + } + }; + + RuleFieldAccessor exampleCount = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + int count = rule.getExamples().size(); + return count > 0 ? Integer.toString(count) : ""; + } + }; + + RuleFieldAccessor ruleType = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + StringBuilder sb = new StringBuilder(3); + if (rule.hasDescriptor(XPathRule.XPATH_DESCRIPTOR)) sb.append('X'); + if (rule.usesDFA()) sb.append('D'); + if (rule.usesTypeResolution()) sb.append('T'); + return sb.toString(); + } + public String labelFor(Rule rule) { + List types = new ArrayList(3); + if (rule.hasDescriptor(XPathRule.XPATH_DESCRIPTOR)) types.add("XPath"); + if (rule.usesDFA()) types.add("Dataflow"); + if (rule.usesTypeResolution()) types.add("Type resolving"); + return Util.asString(types, ", "); + } + }; + + RuleFieldAccessor minLanguageVersion = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + LanguageVersion version = rule.getMinimumLanguageVersion(); + return version == null ? "" : version.getTerseName(); + } + }; + + RuleFieldAccessor maxLanguageVersion = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getMaximumLanguageVersion(); + } + }; + + RuleFieldAccessor violationRegex = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR); + } + }; + + RuleFieldAccessor violationXPath = new BasicRuleFieldAccessor() { + public Comparable valueFor(Rule rule) { + return rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR); + } + }; +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleGroup.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleGroup.java new file mode 100644 index 0000000000..85b725e746 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleGroup.java @@ -0,0 +1,81 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.pmd.Rule; + +/** + * Holds a collection of rules as assembled by the tree widget manager. + * + * @author Brian Remedios + */ +public class RuleGroup implements Comparable { + + private Comparable id; + private String label; + private String description; + private List rules = new ArrayList(); + + /** + * @param theId Object + * @param theDescription String + */ + public RuleGroup(Comparable theId, String theLabel, String theDescription) { + id = theId; + label = theLabel; + description = theDescription; + } + + /** + * @return Comparable + */ + public Comparable id() { return id; } + + /** + * @return String + */ + public String description() { return description; } + + /** + * @return String + */ + public String label() { + + if (label != null) return label; + return id == null ? "" : id.toString(); + } + + /** + * @return int + */ + public int ruleCount() { return rules.size(); } + + /** + * @param ref Rule + */ + public void add(Rule ref) { rules.add(ref); } + + /** + * @return Rule[] + */ + public Rule[] rules() { + return rules.toArray(new Rule[rules.size()]); + } + + /** + * @return boolean + */ + public boolean hasRules() { return !rules.isEmpty(); } + + + public String toString() { return label() + " rules: " + ruleCount(); } + + public int compareTo(RuleGroup otherGroup) { + + if (id == null) return -1; + if (otherGroup.id() == null) return -1; + + return id.compareTo(otherGroup.id()); + }; +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleLabelProvider.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleLabelProvider.java new file mode 100644 index 0000000000..8728323423 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleLabelProvider.java @@ -0,0 +1,59 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.eclipse.ui.preferences.AbstractTableLabelProvider; + +/** + * + * @author Brian Remedios + */ +public class RuleLabelProvider extends AbstractTableLabelProvider { + + private RuleColumnDescriptor[] columnDescriptors; + + /** + * Constructor for RuleLabelProvider. + * @param columns RuleColumnDescriptor[] + */ + public RuleLabelProvider(RuleColumnDescriptor[] columns) { + columnDescriptors = columns; + } + + /** + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(Object, int) + */ + public String getColumnText(Object element, int columnIndex) { + + if (element instanceof RuleGroup) { + RuleGroup rg = (RuleGroup)element; + if (columnIndex == 0) { + String label = rg.label(); + return standardized(label, rg.ruleCount()); + } + return ""; + } + + if (element instanceof Rule) { + Rule rule = (Rule) element; + Object value = columnDescriptors[columnIndex].accessor().valueFor(rule); + return value == null ? "" : value.toString(); + } + + return "??"; + } + + /** + * @param rawLabel String + * @param count int + * @return String + */ + private String standardized(String rawLabel, int count) { + + int rulesPos = rawLabel.indexOf(" Rules"); + String filteredLabel = rulesPos > 0 ? + rawLabel.substring(0, rulesPos) : rawLabel; + + return filteredLabel + " (" + count + ")"; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RulePropertyManager.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RulePropertyManager.java new file mode 100644 index 0000000000..95b3b0d5e7 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RulePropertyManager.java @@ -0,0 +1,8 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.Rule; + +public interface RulePropertyManager { + + public void showRule(Rule rule); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSetTreeItemProvider.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSetTreeItemProvider.java new file mode 100644 index 0000000000..568dcfa984 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSetTreeItemProvider.java @@ -0,0 +1,165 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleSet; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; + +/** + * @author Brian Remedios + */ +public class RuleSetTreeItemProvider implements ITreeContentProvider { + + private RuleFieldAccessor fieldAccessor; + private String groupDescription; + private Comparator comparator; + /** + * Constructor for RuleSetTreeItemProvider. + * @param accessor RuleFieldAccessor + * @param description String + */ + public RuleSetTreeItemProvider(RuleFieldAccessor accessor, String description, Comparator theComparator) { + fieldAccessor = accessor; + groupDescription = description; + comparator = theComparator; + } + + + /** + * + * @param accessor RuleFieldAccessor + */ + public void accessor(RuleFieldAccessor accessor) { + fieldAccessor = accessor; + } + + private Object[] sort(Collection ruleColl) { + Object[] rules = ruleColl.toArray(); + if (comparator == null) return rules; + + Arrays.sort(rules, comparator); + return rules; + } + + /** + * + * @param parentElement Object + * @return Object[] + * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(Object) + */ + public Object[] getChildren(Object parentElement) { + + if (parentElement instanceof RuleSet) { + RuleSet ruleSet = (RuleSet) parentElement; + return fieldAccessor == null ? + sort(ruleSet.getRules()) : + asRuleGroups(ruleSet.getRules()); + } + + if (parentElement instanceof RuleGroup) { + RuleGroup ruleGroup = (RuleGroup) parentElement; + return ruleGroup.rules(); + } + + return Util.EMPTY_ARRAY; + } + + /** + * Method asRuleGroups. + * @param rules Collection + * @return RuleGroup[] + */ + private RuleGroup[] asRuleGroups(Collection rules) { + + Iterator iter = rules.iterator(); + Map ruleGroups = new HashMap(); + while (iter.hasNext()) { + Rule rule = iter.next(); + + Comparable groupId = fieldAccessor.valueFor(rule); + + RuleGroup group = ruleGroups.get(groupId); + if (group != null) { + group.add(rule); + } else { + group = new RuleGroup( + groupId, + fieldAccessor.labelFor(rule), + groupDescription + ); + group.add(rule); + ruleGroups.put(groupId, group); + } + } + + RuleGroup[] groups = ruleGroups.values().toArray(new RuleGroup[ruleGroups.size()]); + Arrays.sort(groups); + return groups; + } + + /** + * Method getParent. + * @param element Object + * @return Object + * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(Object) + */ + public Object getParent(Object element) { + // TODO Auto-generated method stub + return null; + } + + /** + * Method hasChildren. + * @param element Object + * @return boolean + * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(Object) + */ + public boolean hasChildren(Object element) { + + if (element instanceof RuleSet) { + RuleSet ruleSet = (RuleSet) element; + return ruleSet.getRules().size() > 0; + } + + if (element instanceof RuleGroup) { + return ((RuleGroup)element).hasRules(); + } + + return false; + } + + /** + * Method getElements. + * @param inputElement Object + * @return Object[] + * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(Object) + */ + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + /** + * Method inputChanged. + * @param viewer Viewer + * @param oldInput Object + * @param newInput Object + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(Viewer, Object, Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // TODO Auto-generated method stub + + } + + public void dispose() { + // TODO Auto-generated method stub + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSortListener.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSortListener.java new file mode 100644 index 0000000000..13a1858c92 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/RuleSortListener.java @@ -0,0 +1,7 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + + +public interface RuleSortListener { + + void sortBy(RuleFieldAccessor accessor); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/StringEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/StringEditorFactory.java new file mode 100644 index 0000000000..357e23ca05 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/StringEditorFactory.java @@ -0,0 +1,101 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; +import net.sourceforge.pmd.lang.rule.properties.StringProperty; +import net.sourceforge.pmd.util.StringUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class StringEditorFactory extends AbstractEditorFactory { + + public static final StringEditorFactory instance = new StringEditorFactory(); + + protected StringEditorFactory() { } + + /** + * Method fillWidget. + * @param textWidget Text + * @param desc PropertyDescriptor + * @param rule Rule + */ + protected void fillWidget(Text textWidget, PropertyDescriptor desc, Rule rule) { + String val = (String)rule.getProperty(desc); + textWidget.setText(val == null ? "" : val); + } + + /** + * + * @param parent Composite + * @param columnIndex int + * @param desc PropertyDescriptor + * @param rule Rule + * @param listener ValueChangeListener + * @return Control + * @see net.sourceforge.pmd.ui.preferences.br.EditorFactory#newEditorOn(Composite, int, PropertyDescriptor, Rule) + */ + public Control newEditorOn(Composite parent, int columnIndex, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); + GridData gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + text.setLayoutData(gridData); + + fillWidget(text, desc, rule); + + if (desc instanceof PropertyDescriptorWrapper) { + + final PropertyDescriptorWrapper descWrapper = (PropertyDescriptorWrapper)desc; + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + String newValue = text.getText().trim(); + String existingValue = (String)rule.getProperty(descWrapper); + if (StringUtil.areSemanticEquals(existingValue, newValue)) return; + + rule.setProperty(descWrapper, newValue); + fillWidget(text, desc, rule); // redraw + listener.changed(desc, newValue); + } + }); + + return text; + } + + final StringProperty sp = (StringProperty)desc; // TODO - really necessary? + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + String newValue = text.getText().trim(); + String existingValue = rule.getProperty(sp); + if (StringUtil.areSemanticEquals(existingValue, newValue)) return; + + rule.setProperty(sp, newValue); + fillWidget(text, desc, rule); // redraw + listener.changed(desc, newValue); + } + }); + + return text; + } + + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/TypeEditorFactory.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/TypeEditorFactory.java new file mode 100644 index 0000000000..d24b95164e --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/TypeEditorFactory.java @@ -0,0 +1,116 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.PropertyDescriptor; +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.lang.rule.properties.PropertyDescriptorWrapper; +import net.sourceforge.pmd.lang.rule.properties.TypeProperty; +import net.sourceforge.pmd.util.ClassUtil; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; + +/** + * + * @author Brian Remedios + */ +public class TypeEditorFactory extends AbstractEditorFactory { + + public static final TypeEditorFactory instance = new TypeEditorFactory(); + + private TypeEditorFactory() { } + + public static Class typeFor(String typeName) { + + Class newType = ClassUtil.getTypeFor(typeName); // try for well-known types first + if (newType != null) return newType; + + try { + return Class.forName(typeName); + } catch (ClassNotFoundException e) { + return null; + } + } + + protected void fillWidget(Text textWidget, PropertyDescriptor desc, Rule rule) { + + Class type = (Class)rule.getProperty(desc); + textWidget.setText(type == null ? "" : ClassUtil.asShortestName(type)); + } + + private Class currentType(Text textWidget) { + + String typeName = textWidget.getText().trim(); + if (typeName.length() == 0) return null; + + return typeFor(typeName); + } + + /** + * + * @param parent Composite + * @param columnIndex int + * @param desc PropertyDescriptor + * @param rule Rule + * @param listener ValueChangeListener + * @return Control + * @see net.sourceforge.pmd.ui.preferences.br.EditorFactory#newEditorOn(Composite, int, PropertyDescriptor, Rule) + */ + public Control newEditorOn(Composite parent, int columnIndex, final PropertyDescriptor desc, final Rule rule, final ValueChangeListener listener) { + + if (columnIndex == 0) return addLabel(parent, desc); + + if (columnIndex == 1) { + + final Text text = new Text(parent, SWT.SINGLE | SWT.BORDER); + GridData gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + text.setLayoutData(gridData); + + fillWidget(text, desc, rule); + + if (desc instanceof PropertyDescriptorWrapper) { + + final PropertyDescriptorWrapper descWrapper = (PropertyDescriptorWrapper)desc; + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Class newValue = currentType(text); + Class existingValue = (Class)rule.getProperty(descWrapper); + if (existingValue == newValue) return; + + rule.setProperty(descWrapper, newValue); + fillWidget(text, desc, rule); // redraw + listener.changed(desc, newValue); + } + }); + + return text; + } + + final TypeProperty tp = (TypeProperty)desc; // TODO - really necessary? + + text.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + Class newValue = currentType(text); + Class existingValue = rule.getProperty(tp); + if (existingValue == newValue) return; + + rule.setProperty(tp, newValue); + fillWidget(text, desc, rule); // redraw + listener.changed(desc, newValue); + } + }); + + return text; + } + + return null; + } + +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/Util.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/Util.java new file mode 100644 index 0000000000..4abd7e9727 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/Util.java @@ -0,0 +1,218 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import java.util.Comparator; +import java.util.List; + +import net.sourceforge.pmd.Rule; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; + +public class Util { + + public static final Object[] EMPTY_ARRAY = new Object[0]; + + private Util() {}; + + public static boolean isEmpty(Object[] items) { + return items == null || items.length == 0; + } + + public static boolean areSemanticEquals(Object[] a, Object[] b) { + + if (a == null) return isEmpty(b); + if (b == null) return isEmpty(a); + return a.equals(b); + } + + /** + * Helper method to get a filename without its extension + * @param fileName String + * @return String + */ + public static String getFileNameWithoutExtension(String fileName) { + String name = fileName; + + int index = fileName.lastIndexOf('.'); + if (index != -1) { + name = fileName.substring(0, index); + } + + return name; + } + + public static Comparator comparatorFrom(final RuleFieldAccessor accessor, final boolean inverted) { + + return new Comparator() { + + public int compare(Object a, Object b) { + Comparable ca = accessor.valueFor((Rule) a); + Comparable cb = accessor.valueFor((Rule) b); + + int result = (ca == null) ? + -1 : (cb == null) ? + 1 : ca.compareTo(cb); + + return inverted ? result * -1 : result; + } + }; + } + + /** + * Method asCleanString. + * @param original String + * @return String + */ + public static String asCleanString(String original) { + return original == null ? "" : original.trim(); + } + + public static CellPainterBuilder backgroundBuilderFor(final int systemColourIndex) { + + return new CellPainterBuilder() { + + public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter) { + + final Display display = tree.getDisplay(); + + tree.addListener(SWT.EraseItem, new Listener() { + public void handleEvent(Event event) { + + if (event.index != columnIndex) return; + event.detail &= ~SWT.HOT; + + if ((event.detail & SWT.SELECTED) != 0) { + GC gc = event.gc; + Rectangle area = tree.getClientArea(); + /* + * If you wish to paint the selection beyond the end of last column, you must change the clipping region. + */ + int columnCount = tree.getColumnCount(); + if (event.index == columnCount - 1 || columnCount == 0) { + int width = area.x + area.width - event.x; + if (width > 0) { + Region region = new Region(); + gc.getClipping(region); + region.add(event.x, event.y, width, event.height); + gc.setClipping(region); + region.dispose(); + } + } + gc.setAdvanced(true); + if (gc.getAdvanced()) gc.setAlpha(127); + Rectangle rect = event.getBounds(); + Color foreground = gc.getForeground(); + Color background = gc.getBackground(); + gc.setForeground(display.getSystemColor(systemColourIndex)); + gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + gc.fillGradientRectangle(event.x, rect.y, 500, rect.height, false); + + gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); + gc.drawLine(event.x, rect.y, event.x + 20, rect.y + 20); + + gc.setForeground(foreground); // restore colors for subsequent drawing + gc.setBackground(background); + event.detail &= ~SWT.SELECTED; + } + } + }); + }}; + } + + public static CellPainterBuilder textBuilderFor(final int systemColourIndex) { + + return new CellPainterBuilder() { + + public void addPainterFor(final Tree tree, final int columnIndex, final RuleFieldAccessor getter) { + + final Display display = tree.getDisplay(); + +// tree.addListener(SWT.EraseItem, new Listener() { +// public void handleEvent(Event event) { +// if (event.index != columnIndex) return; +// +// // GC gc = event.gc; +// // Rectangle area = new Rectangle(event.x, event.y, event.width, event.height); +// +// // gc.fillRectangle(area); +// } +// +// }); + + tree.addListener(SWT.PaintItem, new Listener() { + public void handleEvent(Event event) { + + if (event.index != columnIndex) return; + event.detail &= ~SWT.HOT; + +// if ((event.detail & SWT.SELECTED) != 0) { + GC gc = event.gc; + Rectangle area = tree.getClientArea(); + + Rule rule = (Rule)((TreeItem)event.item).getData(); + String text = getter.valueFor(rule).toString(); + + int columnCount = tree.getColumnCount(); + if (event.index == columnCount - 1 || columnCount == 0) { + int width = area.x + area.width - event.x; + if (width > 0) { + Region region = new Region(); + gc.getClipping(region); + region.add(event.x, event.y, width, event.height); + gc.setClipping(region); + region.dispose(); + } + } + // gc.setAdvanced(true); + // if (gc.getAdvanced()) gc.setAlpha(127); + Rectangle rect = event.getBounds(); + // Color foreground = gc.getForeground(); + // Color background = gc.getBackground(); + // gc.setForeground(display.getSystemColor(systemColourIndex)); + // gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + + // gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); + gc.drawString(text, event.x, rect.y); + + // gc.setForeground(foreground); // restore colors for subsequent drawing + // gc.setBackground(background); +// event.detail &= ~SWT.SELECTED; +// } + } + }); + }}; + } + + + // TODO move these to StringUtil + public static String asString(List items, String separator) { + + if (items == null || items.isEmpty()) return ""; + if (items.size() == 1) return items.get(0); + + StringBuilder sb = new StringBuilder(items.get(0)); + for (int i=1; i + * @param newValue Object + */ + void changed(PropertyDescriptor desc, Object newValue); +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ValueFormatter.java b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ValueFormatter.java new file mode 100644 index 0000000000..3fbd9025d8 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/ValueFormatter.java @@ -0,0 +1,59 @@ +package net.sourceforge.pmd.eclipse.ui.preferences.br; + +import net.sourceforge.pmd.util.ClassUtil; + + +public interface ValueFormatter { + + void format(Object value, StringBuilder target); + + ValueFormatter StringFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append(value == null ? "" : value); + } + }; + + ValueFormatter MultiStringFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + Util.asString((Object[])value, ", ", target); + } + }; + + ValueFormatter NumberFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append(value == null ? "?" : value); + } + }; + + ValueFormatter BooleanFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append(value == null ? "?" : value); + } + }; + + ValueFormatter TypeFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append(value == null ? "" : ClassUtil.asShortestName((Class)value)); + } + }; + + ValueFormatter MultiTypeFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append('['); + Util.asString(MultiTypeEditorFactory.shortNamesFor((Class[])value), ", ", target); + target.append(']'); + } + }; + + ValueFormatter ObjectArrayFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + Util.asString((Object[])value, ", ", target); + } + }; + + ValueFormatter ObjectFormatter = new ValueFormatter() { + public void format(Object value, StringBuilder target) { + target.append(value == null ? "" : value); + } + }; +} diff --git a/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/testing.jpage b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/testing.jpage new file mode 100644 index 0000000000..3e9893ecf2 --- /dev/null +++ b/pmd-eclipse-plugin/plugins/net.sourceforge.pmd.eclipse.plugin/src/net/sourceforge/pmd/eclipse/ui/preferences/br/testing.jpage @@ -0,0 +1,9 @@ + + + + + (Math.log10(999.9f) % 1 ) * 255 + + 5.5 % 1 + + (int)(Math.log10(978787) % 1 * 255) \ No newline at end of file