/*******************************************************************************
* Copyright (c) 2007, 2015 Spring IDE Developers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.ui.dialogs;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.springframework.ide.eclipse.core.PersistablePreferenceObjectSupport;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidationRuleDefinition;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidationRuleDefinitionFactory;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidatorDefinition;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidatorDefinitionFactory;
import org.springframework.ide.eclipse.core.model.IModelElement;
import org.springframework.ide.eclipse.core.model.validation.IValidationRule;
import org.springframework.ide.eclipse.core.model.validation.IValidator;
import org.springframework.ide.eclipse.ui.SpringUIImages;
import org.springframework.ide.eclipse.ui.SpringUIMessages;
import org.springframework.ide.eclipse.ui.SpringUIPlugin;
/**
* UI component that enables the use to enable and disable {@link IValidator}s and {@link IValidationRule}s on a per
* project basis.
* @author Christian Dupuis
* @author Torsten Juergeleit
* @author Terry Denney
* @since 2.0
*/
public class ProjectValidatorPropertyTab {
private static class ProjectValidatorContentProvider implements ITreeContentProvider {
private List<ValidatorDefinition> validatorDefinitions;
private Map<ValidatorDefinition, List<ValidationRuleDefinition>> validationRuleDefinitions;
public ProjectValidatorContentProvider(List<ValidatorDefinition> validatorDefinitions,
Map<ValidatorDefinition, List<ValidationRuleDefinition>> validationRuleDefinitions) {
this.validatorDefinitions = validatorDefinitions;
this.validationRuleDefinitions = validationRuleDefinitions;
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
return this.validatorDefinitions.toArray();
}
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof ValidatorDefinition) {
return this.validationRuleDefinitions.get((ValidatorDefinition) parentElement).toArray();
}
else {
return IModelElement.NO_CHILDREN;
}
}
public Object getParent(Object element) {
if (element instanceof ValidationRuleDefinition) {
for (ValidatorDefinition def : this.validatorDefinitions) {
if (((ValidationRuleDefinition) element).getValidatorId().equals(def.getID())) {
return def;
}
}
}
return null;
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
}
private static class ProjectBuilderLabelProvider extends LabelProvider {
public String getText(Object element) {
if (element instanceof ValidatorDefinition) {
return ((ValidatorDefinition) element).getName();
}
else if (element instanceof ValidationRuleDefinition) {
return ((ValidationRuleDefinition) element).getName();
}
return super.getText(element);
}
public Image getImage(Object element) {
Image image = null;
if (element instanceof ValidatorDefinition) {
String icon = ((ValidatorDefinition) element).getIconUri();
String ns = ((ValidatorDefinition) element).getNamespaceUri();
if (icon != null && ns != null) {
image = SpringUIPlugin.getDefault().getImageRegistry().get(icon);
if (image == null) {
ImageDescriptor imageDescriptor = SpringUIPlugin.imageDescriptorFromPlugin(ns, icon);
SpringUIPlugin.getDefault().getImageRegistry().put(icon, imageDescriptor);
image = SpringUIPlugin.getDefault().getImageRegistry().get(icon);
}
}
}
if (image == null) {
return SpringUIImages.getImage(SpringUIImages.IMG_OBJS_RULE);
}
else {
return image;
}
}
}
private ITreeContentProvider contentProvider;
private List<ValidatorDefinition> validatorDefinitions;
private Map<ValidatorDefinition, List<ValidationRuleDefinition>> validationRuleDefinitions;
private CheckboxTreeViewer validatorViewer;
private Text descriptionText;
private IProject project;
private Shell shell;
private Button configureButton;
private Button resetButton;
private Map<ValidationRuleDefinition, Map<String, String>> changedPropertyValues = new HashMap<ValidationRuleDefinition, Map<String, String>>();
private Map<ValidationRuleDefinition, Map<String, Integer>> changedMessageSeverities = new HashMap<ValidationRuleDefinition, Map<String, Integer>>();
private SelectionListener buttonListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
handleButtonPressed((Button) e.widget);
}
};
private SelectionListener resetListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if ((Button) e.widget == resetButton) {
performDefaults();
}
}
};
private Object[] checkedElements;
public ProjectValidatorPropertyTab(Shell shell, IProject project) {
this.validatorDefinitions = ValidatorDefinitionFactory.getValidatorDefinitions();
this.validationRuleDefinitions = new HashMap<ValidatorDefinition, List<ValidationRuleDefinition>>();
for (ValidatorDefinition def : this.validatorDefinitions) {
List<ValidationRuleDefinition> rules = new ArrayList<ValidationRuleDefinition>();
rules.addAll(ValidationRuleDefinitionFactory.getRuleDefinitions(def.getID()));
Collections.sort(rules, new Comparator<ValidationRuleDefinition>() {
public int compare(ValidationRuleDefinition o1, ValidationRuleDefinition o2) {
return o1.getName().compareTo(o2.getName());
}
});
validationRuleDefinitions.put(def, rules);
}
this.project = project;
this.shell = shell;
}
protected void handleButtonPressed(Button widget) {
if (widget == configureButton) {
IStructuredSelection selection = (IStructuredSelection) validatorViewer.getSelection();
if (!selection.isEmpty()) {
Object obj = selection.getFirstElement();
if (obj instanceof ValidationRuleDefinition) {
ValidationRuleDefinition ruleDef = (ValidationRuleDefinition) obj;
Map<String, String> propertyValues = null;
if (changedPropertyValues.containsKey(ruleDef)) {
propertyValues = new HashMap<String, String>(changedPropertyValues.get(ruleDef));
}
else {
propertyValues = new HashMap<String, String>(ruleDef.getPropertyValues());
}
Map<String, Integer> messageSeverities = null;
if (changedMessageSeverities.containsKey(ruleDef)) {
messageSeverities = new HashMap<String, Integer>(changedMessageSeverities.get(ruleDef));
}
else {
messageSeverities = new HashMap<String, Integer>(ruleDef.getMessageSeverities());
}
ValidationRuleConfigurationDialog dialog = new ValidationRuleConfigurationDialog(this.shell,
propertyValues, messageSeverities, ruleDef);
if (dialog.open() == Dialog.OK) {
changedPropertyValues.put(ruleDef, propertyValues);
changedMessageSeverities.put(ruleDef, messageSeverities);
}
}
}
}
}
public Control createContents(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 3;
layout.marginWidth = 3;
composite.setLayout(layout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
if (project != null ) {
Label beansLabel = new Label(composite, SWT.NONE);
beansLabel.setText(SpringUIMessages.ProjectValidatorPropertyPage_description);
}
Composite tableAndButtons = new Composite(composite, SWT.NONE);
tableAndButtons.setLayoutData(new GridData(GridData.FILL_BOTH));
layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 2;
tableAndButtons.setLayout(layout);
// config set list viewer
validatorViewer = new CheckboxTreeViewer(tableAndButtons);
// validatorViewer.setUseHashlookup(true);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 150;
this.contentProvider = new ProjectValidatorContentProvider(this.validatorDefinitions,
this.validationRuleDefinitions);
validatorViewer.setContentProvider(this.contentProvider);
validatorViewer.setLabelProvider(new ProjectBuilderLabelProvider());
validatorViewer.setInput(this); // activate content provider
GridData data = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL);
data.heightHint = 150;
validatorViewer.getControl().setLayoutData(data);
validatorViewer.getControl().setFont(font);
validatorViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
if (event.getSelection() instanceof IStructuredSelection) {
IStructuredSelection sel = (IStructuredSelection) event.getSelection();
if (sel.getFirstElement() == null) {
clearDescription();
}
else {
showDescription(sel.getFirstElement());
}
updateConfigureButtonEnablement(sel.getFirstElement());
}
}
});
validatorViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
handleCheckStateChange(event);
checkedElements = validatorViewer.getCheckedElements();
}
});
// Create button area
Composite buttonArea = new Composite(tableAndButtons, SWT.NONE);
layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
buttonArea.setLayout(layout);
buttonArea.setLayoutData(new GridData(GridData.FILL_VERTICAL));
configureButton = new Button(buttonArea, SWT.PUSH);
configureButton.setText("Configure");
configureButton.setEnabled(false);
configureButton.addSelectionListener(buttonListener);
Label descriptionLabel = new Label(composite, SWT.NONE);
descriptionLabel.setText(SpringUIMessages.ProjectValidatorPropertyPage_builderDescription);
descriptionText = new Text(composite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.BORDER | SWT.H_SCROLL);
data = new GridData(GridData.FILL_BOTH);
data.heightHint = 30;
descriptionText.setLayoutData(data);
resetButton = new Button(composite, SWT.PUSH);
resetButton.setText("Restore Defaults");
data = new GridData(GridData.HORIZONTAL_ALIGN_END);
resetButton.setLayoutData(data);
resetButton.addSelectionListener(resetListener);
initializeCheckedState(project, false);
return composite;
}
private void handleCheckStateChange(final CheckStateChangedEvent event) {
BusyIndicator.showWhile(shell.getDisplay(), new Runnable() {
public void run() {
boolean state = event.getChecked();
setSubtreeChecked(event.getElement(), state, true);
updateParentState(event.getElement());
}
});
}
private void updateParentState(Object child) {
if (child == null || contentProvider.getParent(child) == null) {
return;
}
Object parent = contentProvider.getParent(child);
boolean childChecked = false;
Object[] members = contentProvider.getChildren(parent);
for (int i = members.length - 1; i >= 0; i--) {
if (validatorViewer.getChecked(members[i]) || validatorViewer.getGrayed(members[i])) {
childChecked = true;
break;
}
}
validatorViewer.setGrayChecked(parent, childChecked);
updateParentState(parent);
}
private void setSubtreeChecked(Object container, boolean state, boolean checkExpandedState) {
Object[] members = contentProvider.getChildren(container);
for (int i = members.length - 1; i >= 0; i--) {
Object element = members[i];
boolean elementGrayChecked = validatorViewer.getGrayed(element) || validatorViewer.getChecked(element);
if (state) {
validatorViewer.setChecked(element, true);
validatorViewer.setGrayed(element, false);
}
else {
validatorViewer.setGrayChecked(element, false);
} // unchecked state only
// needs
if ((state || elementGrayChecked)) {
setSubtreeChecked(element, state, true);
}
}
}
private List<PersistablePreferenceObjectSupport> getEnabledProjectBuilderDefinitions(IProject project, boolean getDefault) {
List<ValidatorDefinition> validatorDefinitions = this.validatorDefinitions;
List<PersistablePreferenceObjectSupport> filteredValidatorDefinitions = new ArrayList<PersistablePreferenceObjectSupport>();
for (ValidatorDefinition builderDefinition : validatorDefinitions) {
if (getDefault ? builderDefinition.isEnabledByDefault(): builderDefinition.isEnabled(project)) {
filteredValidatorDefinitions.add(builderDefinition);
}
}
for (List<ValidationRuleDefinition> defs : this.validationRuleDefinitions.values()) {
for (ValidationRuleDefinition def : defs) {
if (getDefault ? def.isEnabledByDefault(): def.isEnabled(project)) {
filteredValidatorDefinitions.add(def);
}
}
}
return filteredValidatorDefinitions;
}
/**
* Show the selected description in the text.
*/
private void showDescription(Object definition) {
if (descriptionText == null || descriptionText.isDisposed()) {
return;
}
String text = null;
if (definition instanceof ValidatorDefinition) {
text = ((ValidatorDefinition) definition).getDescription();
}
else if (definition instanceof ValidationRuleDefinition) {
text = ((ValidationRuleDefinition) definition).getDescription();
}
if (text == null || text.length() == 0) {
descriptionText.setText(SpringUIMessages.ProjectValidatorPropertyPage_noBuilderDescription);
}
else {
descriptionText.setText(text);
}
}
private void initializeCheckedState(final IProject project, final boolean getDefault) {
BusyIndicator.showWhile(shell.getDisplay(), new Runnable() {
public void run() {
List items = getEnabledProjectBuilderDefinitions(project, getDefault);
validatorViewer.setCheckedElements(items.toArray());
for (int i = 0; i < items.size(); i++) {
Object item = items.get(i);
updateParentState(item);
}
checkedElements = validatorViewer.getCheckedElements();
}
});
}
/**
* Clear the selected description in the text.
*/
private void clearDescription() {
if (descriptionText == null || descriptionText.isDisposed()) {
return;
}
descriptionText.setText(""); //$NON-NLS-1$
}
private void updateConfigureButtonEnablement(Object firstElement) {
if (firstElement instanceof ValidationRuleDefinition
&& (((ValidationRuleDefinition) firstElement).getPropertyValues().size() > 0 || ((ValidationRuleDefinition) firstElement)
.getMessageSeverities().size() > 0)) {
configureButton.setEnabled(true);
}
else {
configureButton.setEnabled(false);
}
}
public void performDefaults() {
// Reset checked state of validation definition rules in the tree
initializeCheckedState(null, true);
// Reset the validation rule definition settings
for (List<ValidationRuleDefinition> defList : validationRuleDefinitions.values()) {
for (ValidationRuleDefinition ruleDef : defList) {
// Process property values
changedPropertyValues.put(ruleDef, ruleDef.getDefaultPropertyValues());
// Process Message severities
changedMessageSeverities.put(ruleDef, ruleDef.getDefaultMessageSeverities());
}
}
}
public boolean performOk() {
final List checkElements = checkedElements != null ? Arrays.asList(checkedElements) : Collections.emptyList();
WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
@Override
protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException,
InterruptedException {
for (Map.Entry<ValidatorDefinition, List<ValidationRuleDefinition>> def : validationRuleDefinitions
.entrySet()) {
boolean enableValidator = false;
for (ValidationRuleDefinition rule : def.getValue()) {
if (checkElements.contains(rule)) {
enableValidator = true;
rule.setEnabled(true, project);
}
else {
rule.setEnabled(false, project);
}
if (changedPropertyValues.containsKey(rule) || changedMessageSeverities.containsKey(rule)) {
rule.setSpecificConfiguration(changedPropertyValues.get(rule), changedMessageSeverities
.get(rule), project);
}
}
def.getKey().setEnabled(enableValidator, project);
}
}
};
try {
operation.run(new NullProgressMonitor());
}
catch (InvocationTargetException e) {
}
catch (InterruptedException e) {
}
return true;
}
}