package net.sourceforge.pmd.eclipse.ui.preferences.br; import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.List; import java.util.Set; import net.sourceforge.pmd.PropertyDescriptor; import net.sourceforge.pmd.PropertySource; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RuleSet; import net.sourceforge.pmd.eclipse.plugin.PMDPlugin; import net.sourceforge.pmd.eclipse.runtime.preferences.impl.PreferenceUIStore; import net.sourceforge.pmd.eclipse.ui.ModifyListener; import net.sourceforge.pmd.eclipse.ui.nls.StringKeys; import net.sourceforge.pmd.eclipse.ui.preferences.editors.SWTUtil; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.DescriptionPanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.EditorUsageMode; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.ExamplePanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.ExclusionPanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.PerRulePropertyPanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.RulePanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.RulePropertyManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.SummaryPanelManager; import net.sourceforge.pmd.eclipse.ui.preferences.panelmanagers.XPathPanelManager; import net.sourceforge.pmd.eclipse.util.Util; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Sash; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.Tree; /** * * @author Brian Remedios */ public class PMDPreferencePage2 extends AbstractPMDPreferencePage implements RuleSelectionListener, ModifyListener, ValueChangeListener, ValueResetHandler { private TabFolder tabFolder; private RulePropertyManager[] rulePropertyManagers; private RuleTableManager tableManager; private Button globalRuleManagementCheckButton; // columns shown in the rule treetable in the desired order public static final RuleColumnDescriptor[] availableColumns = new RuleColumnDescriptor[] { RuleTableColumns.name, //PreferenceTableColumns.priorityName, // IconColumnDescriptor.priority, RuleTableColumns.imgPriority, // PreferenceTableColumns.fixCount, RuleTableColumns.since, RuleTableColumns.ruleSetName, RuleTableColumns.ruleType, RuleTableColumns.minLangVers, RuleTableColumns.maxLangVers, RuleTableColumns.language, RuleTableColumns.filterViolationRegex, // regex text -> compact color squares (for comparison) RuleTableColumns.filterViolationXPath, // xpath text -> compact color circles (for comparison) RuleTableColumns.modCount, // PreferenceTableColumns.properties RuleTableColumns.imgProperties }; // last item in this list is the grouping used at startup public static final Object[][] groupingChoices = new Object[][] { { RuleTableColumns.ruleSetName, StringKeys.PREF_RULESET_COLUMN_RULESET}, { RuleTableColumns.since, StringKeys.PREF_RULESET_GROUPING_PMD_VERSION }, { RuleTableColumns.priorityName, StringKeys.PREF_RULESET_COLUMN_PRIORITY }, { RuleTableColumns.ruleType, StringKeys.PREF_RULESET_COLUMN_RULE_TYPE }, { RuleTableColumns.language, StringKeys.PREF_RULESET_COLUMN_LANGUAGE }, { RuleTableColumns.filterViolationRegex, StringKeys.PREF_RULESET_GROUPING_REGEX }, { null, StringKeys.PREF_RULESET_GROUPING_NONE } }; public PMDPreferencePage2() { } public static RulePropertyManager[] buildPropertyManagersOn(TabFolder folder, ValueChangeListener listener) { return new RulePropertyManager[] { buildFullViewTab(folder, 0, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_FULLVIEW), listener), buildRuleTab(folder, 1, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_RULE), listener), // buildDescriptionTab(folder, 2, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_DESCRIPTION), listener), buildPropertyTab(folder, 2, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_PROPERTIES), listener), buildExclusionTab(folder, 3, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_EXCLUSIONS), listener), buildXPathTab(folder, 4, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_XPATH), listener), // buildQuickFixTab(folder, 6, SWTUtil.stringFor(StringKeys.MSGKEY_PREF_RULESET_TAB_FIXES), listener), // buildExampleTab(folder, 6, SWTUtil.stringFor(StringKeys.PREF_RULESET_TAB_EXAMPLES), listener), }; } protected String descriptionId() { return StringKeys.PREF_RULESET_TITLE; } @Override protected Control createContents(Composite parent) { tableManager = new RuleTableManager("rules", availableColumns, PMDPlugin.getDefault().loadPreferences(), this); tableManager.modifyListener(this); tableManager.selectionListener(this); populateRuleset(); Composite composite = new Composite(parent, SWT.NULL); layoutControls(composite); tableManager.populateRuleTable(); int i = PreferenceUIStore.instance.selectedPropertyTab() ; tabFolder.setSelection( i ); return composite; } public void createControl(Composite parent) { super.createControl(parent); setModified(false); } /** * Create buttons for rule properties table management * @param parent Composite * @return Composite */ public static 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; } private Composite createRuleSection(Composite parent) { Composite ruleSection = new Composite(parent, SWT.NULL); // Create the controls (order is important !) Composite groupCombo = tableManager.buildGroupCombo(ruleSection, StringKeys.PREF_RULESET_RULES_GROUPED_BY, groupingChoices); Tree ruleTree = tableManager.buildRuleTreeViewer(ruleSection); tableManager.groupBy(null); Composite ruleTableButtons = tableManager.buildRuleTableButtons(ruleSection); Composite rulePropertiesTableButtons = buildRulePropertiesTableButtons(ruleSection); // Place controls on the layout GridLayout gridLayout = new GridLayout(3, false); ruleSection.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 = 1; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; rulePropertiesTableButtons.setLayoutData(data); return ruleSection; } /** * Method buildTabFolder. * @param parent Composite * @return TabFolder */ private TabFolder buildTabFolder(Composite parent) { tabFolder = new TabFolder(parent, SWT.TOP); rulePropertyManagers = buildPropertyManagersOn(tabFolder, this); tabFolder.pack(); return tabFolder; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildRuleTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); RulePanelManager manager = new RulePanelManager(title, EditorUsageMode.Editing, listener, null); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildPropertyTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); PerRulePropertyPanelManager manager = new PerRulePropertyPanelManager(title, EditorUsageMode.Editing, listener); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildDescriptionTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); DescriptionPanelManager manager = new DescriptionPanelManager(title, EditorUsageMode.Editing, listener); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildXPathTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); XPathPanelManager manager = new XPathPanelManager(title, EditorUsageMode.Editing, listener); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildFullViewTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); SummaryPanelManager manager = new SummaryPanelManager("asdf", title, EditorUsageMode.Editing, listener); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ private static RulePropertyManager buildExampleTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); ExamplePanelManager manager = new ExamplePanelManager(title, EditorUsageMode.Editing, listener); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } /** * @param parent TabFolder * @param index int */ // private static RulePropertyManager buildQuickFixTab(TabFolder parent, int index, String title, ValueChangeListener listener) { // // TabItem tab = new TabItem(parent, 0, index); // tab.setText(title); // // QuickFixPanelManager manager = new QuickFixPanelManager(title, EditorUsageMode.Editing, listener); // tab.setControl( // manager.setupOn(parent) // ); // manager.tab(tab); // return manager; // } /** * * @param parent TabFolder * @param index int * @param title String */ private static RulePropertyManager buildExclusionTab(TabFolder parent, int index, String title, ValueChangeListener listener) { TabItem tab = new TabItem(parent, 0, index); tab.setText(title); ExclusionPanelManager manager = new ExclusionPanelManager(title, EditorUsageMode.Editing, listener, true); tab.setControl( manager.setupOn(parent) ); manager.tab(tab); return manager; } public void changed(PropertySource source, PropertyDescriptor<?> desc, Object newValue) { // TODO enhance to recognize default values setModified(); tableManager.updated(source); } public void changed(RuleSelection selection, PropertyDescriptor<?> desc, Object newValue) { // TODO enhance to recognize default values for (Rule rule : selection.allRules()) { if (newValue != null) { // non-reliable update behaviour, alternate trigger option - weird tableManager.changed(selection, desc, newValue); // System.out.println("doing redraw"); } else { tableManager.changed(rule, desc, newValue); // System.out.println("viewer update"); } } for (RulePropertyManager manager : rulePropertyManagers) { manager.validate(); } setModified(); } /** * Main layout * @param parent Composite */ private void layoutControls(Composite parent) { GridLayout layout = new GridLayout(1, false); layout.verticalSpacing = 10; parent.setLayout(layout); Composite checkboxPanel = new Composite(parent, 0); RowLayout checkboxPanelLayout = new RowLayout(SWT.VERTICAL); checkboxPanelLayout.fill = true; checkboxPanelLayout.pack = false; checkboxPanel.setLayout(checkboxPanelLayout); checkboxPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); final Button checkButton = new Button(checkboxPanel, SWT.CHECK); globalRuleManagementCheckButton = checkButton; final Composite contentPanel = new Composite(parent, 0); contentPanel.setLayout(new FormLayout()); contentPanel.setLayoutData(new GridData(GridData.FILL_BOTH)); checkButton.setText(SWTUtil.stringFor(StringKeys.PREF_RULESET_BUTTON_GLOBALRULEMANAGEMENT)); checkButton.setSelection(preferences.getGlobalRuleManagement()); checkButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { boolean sel = checkButton.getSelection(); SWTUtil.setEnabledRecursive(contentPanel.getChildren(), sel); setModified(); } }); Label explanation = new Label(checkboxPanel, SWT.WRAP); RowData rowData = new RowData(); rowData.width = 450; explanation.setLayoutData(rowData); explanation.setText(SWTUtil.stringFor(StringKeys.PREF_RULESET_BUTTON_GLOBALRULEMANAGEMENT_EXPL)); int ruleTableFraction = 55; //PreferenceUIStore.instance.tableFraction(); // Create the sash first, so the other controls can be attached to it. final Sash sash = new Sash(contentPanel, SWT.HORIZONTAL); FormData data = new FormData(); data.left = new FormAttachment(0, 0); // attach to left data.right = new FormAttachment(100, 0); // attach to right data.top = new FormAttachment(ruleTableFraction, 0); sash.setLayoutData(data); sash.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { // Re-attach to the top edge, and we use the y value of the event to determine the offset from the top ((FormData)sash.getLayoutData()).top = new FormAttachment(0, event.y); // PreferenceUIStore.instance.tableFraction(event.y); contentPanel.layout(); } }); // Create the first text box and attach its bottom edge to the sash Composite ruleSection = createRuleSection(contentPanel); data = new FormData(); data.top = new FormAttachment(0, 0); data.bottom = new FormAttachment(sash, 0); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); ruleSection.setLayoutData(data); // Create the second text box and attach its top edge to the sash TabFolder propertySection = buildTabFolder(contentPanel); data = new FormData(); data.top = new FormAttachment(sash, 0); data.bottom = new FormAttachment(100, 0); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); propertySection.setLayoutData(data); SWTUtil.setEnabledRecursive(contentPanel.getChildren(), checkButton.getSelection()); } /** * @see org.eclipse.jface.preference.IPreferencePage#performOk() */ @Override public boolean performOk() { saveUIState(); if (isModified()) { updateRuleSet(); rebuildProjects(); storeActiveRules(); } return super.performOk(); } @Override public boolean performCancel() { saveUIState(); return super.performCancel(); } /** * @see org.eclipse.jface.preference.PreferencePage#performDefaults() */ @Override protected void performDefaults() { tableManager.populateRuleTable(); super.performDefaults(); } private void populateRuleset() { RuleSet defaultRuleSet = plugin.getPreferencesManager().getRuleSet(); RuleSet ruleSet = new RuleSet(); ruleSet.addRuleSet(defaultRuleSet); ruleSet.setName(defaultRuleSet.getName()); ruleSet.setDescription(Util.asCleanString(defaultRuleSet.getDescription())); ruleSet.addExcludePatterns(defaultRuleSet.getExcludePatterns()); ruleSet.addIncludePatterns(defaultRuleSet.getIncludePatterns()); tableManager.useRuleSet(ruleSet); } public void selection(RuleSelection selection) { if (rulePropertyManagers == null) return; for (RulePropertyManager manager : rulePropertyManagers) { manager.manage(selection); manager.validate(); } } private void saveUIState() { tableManager.saveUIState(); int i = tabFolder.getSelectionIndex(); PreferenceUIStore.instance.selectedPropertyTab( i ); PreferenceUIStore.instance.globalRuleManagement( globalRuleManagementCheckButton.getSelection() ); preferences.setGlobalRuleManagement( globalRuleManagementCheckButton.getSelection() ); PreferenceUIStore.instance.save(); } private void storeActiveRules() { List<Rule> chosenRules = tableManager.activeRules(); Set<String> activeRules = new HashSet<String>(); for (Rule rule : chosenRules) { activeRules.add(rule.getName()); } // override all the active rules preferences.setActiveRuleNames(activeRules); // System.out.println("Active rules: " + preferences.getActiveRuleNames()); } 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(tableManager.ruleSet()); } }); } catch (Exception e) { plugin.logError("Exception updating all projects after a preference change", e); } } public void resetValuesIn(RuleSelection rules) { rules.useDefaultValues(); tableManager.refresh(); for (RulePropertyManager rpm : rulePropertyManagers) { rpm.loadValues(); } } }