/*
* Copyright (c) 2015 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.io.instance;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import eu.esdihumboldt.hale.common.core.io.HaleIO;
import eu.esdihumboldt.hale.common.core.io.IOProvider;
import eu.esdihumboldt.hale.common.core.io.IOProviderConfigurationException;
import eu.esdihumboldt.hale.common.core.io.extension.IOProviderDescriptor;
import eu.esdihumboldt.hale.common.core.io.supplier.Locatable;
import eu.esdihumboldt.hale.common.instance.io.InstanceValidator;
import eu.esdihumboldt.hale.common.instance.io.InstanceWriter;
import eu.esdihumboldt.hale.io.validation.ProjectValidator;
import eu.esdihumboldt.hale.ui.io.IOWizardListener;
import eu.esdihumboldt.hale.ui.io.config.AbstractConfigurationDialog;
import eu.esdihumboldt.hale.ui.io.config.ConfigurationDialogExtension;
import eu.esdihumboldt.hale.ui.io.config.ConfigurationDialogFactory;
import eu.esdihumboldt.hale.ui.io.target.FileTarget;
/**
* File target that adds instance validation. Only usable for instance export.
*
* @author Simon Templer
*/
public class FileValidateTarget extends FileTarget<InstanceWriter>
implements IOWizardListener<InstanceWriter, InstanceExportWizard> {
private static final ALogger log = ALoggerFactory.getLogger(FileValidateTarget.class);
private final List<ValidatorEntry> validators = new ArrayList<>();
private TableViewer validatorsTableViewer;
private Button configureValidatorButton;
private Button addValidatorButton;
private Button removeValidatorButton;
private SelectionListener configureButtonListener;
@Override
public InstanceExportWizard getWizard() {
return (InstanceExportWizard) super.getWizard();
}
@Override
public void createControls(Composite parent) {
super.createControls(parent);
// page has a 3-column grid layout
Group validatorGroup = new Group(parent, SWT.NONE);
validatorGroup.setText("Validation");
validatorGroup.setLayoutData(GridDataFactory.swtDefaults().align(SWT.FILL, SWT.BEGINNING)
.grab(true, false).span(3, 1).indent(8, 10).create());
validatorGroup
.setLayout(GridLayoutFactory.swtDefaults().numColumns(3).margins(10, 8).create());
// Add project validator by default
IOProviderDescriptor pvDescriptor = HaleIO.findIOProviderFactory(IOProvider.class,
getWizard().getContentType(), ProjectValidator.PROVIDER_ID);
if (pvDescriptor != null) {
ProjectValidator projectValidator = new ProjectValidator();
List<? extends Locatable> schemas = getWizard().getProvider().getValidationSchemas();
projectValidator.setSchemas(schemas.toArray(new Locatable[schemas.size()]));
ValidatorEntry entry = new ValidatorEntry(projectValidator, pvDescriptor);
validators.add(entry);
getWizard().addValidator(projectValidator);
}
// viewer with validator list
Composite tableContainer = new Composite(validatorGroup, SWT.NONE);
tableContainer.setLayoutData(GridDataFactory.swtDefaults().span(3, 1).minSize(100, 100)
.align(SWT.FILL, SWT.FILL).grab(true, true).create());
TableColumnLayout layout = new TableColumnLayout();
tableContainer.setLayout(layout);
validatorsTableViewer = new TableViewer(tableContainer,
SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
validatorsTableViewer.getTable().setLinesVisible(true);
validatorsTableViewer.getTable().setHeaderVisible(true);
validatorsTableViewer.setContentProvider(ArrayContentProvider.getInstance());
validatorsTableViewer.setInput(validators);
TableViewerColumn typeColumn = new TableViewerColumn(validatorsTableViewer, SWT.NONE);
layout.setColumnData(typeColumn.getColumn(), new ColumnWeightData(4));
typeColumn.getColumn().setText("Validator");
typeColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
ValidatorEntry validator = (ValidatorEntry) element;
return validator.getDescriptor().getDisplayName();
}
/**
* @see org.eclipse.jface.viewers.ColumnLabelProvider#getImage(java.lang.Object)
*/
@Override
public Image getImage(Object element) {
ValidatorEntry validator = (ValidatorEntry) element;
if (validator.getStatusMessage() != null
&& !validator.getStatusMessage().isEmpty()) {
return PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_DEC_FIELD_ERROR);
}
return null;
}
});
TableViewerColumn errorColumn = new TableViewerColumn(validatorsTableViewer, SWT.NONE);
layout.setColumnData(errorColumn.getColumn(), new ColumnWeightData(3));
errorColumn.getColumn().setText("Status");
errorColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
ValidatorEntry validator = (ValidatorEntry) element;
String message = validator.getStatusMessage();
if (message == null || message.trim().isEmpty()) {
message = "OK";
}
return message;
}
});
validatorsTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
updateWizard(getSelectedValidator(event.getSelection()));
}
});
// Selection dialog for adding validators to the list
final ValidatorSelectionDialog validatorSelectionDialog = new ValidatorSelectionDialog(
PlatformUI.getWorkbench().getDisplay().getActiveShell());
addValidatorButton = new Button(validatorGroup, SWT.PUSH);
addValidatorButton.setText("Add validator...");
addValidatorButton.setEnabled(false);
addValidatorButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
validatorSelectionDialog.create();
validatorSelectionDialog.setContentType(getWizard().getContentType());
if (validatorSelectionDialog.open() == Dialog.OK) {
IOProviderDescriptor selection = validatorSelectionDialog.getSelection();
addValidator(selection);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
// Remove button
removeValidatorButton = new Button(validatorGroup, SWT.PUSH);
removeValidatorButton.setText("Remove validator...");
removeValidatorButton.setEnabled(false);
removeValidatorButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
ValidatorEntry selection = getSelectedValidator();
getWizard().removeValidator(selection.getValidator());
validators.remove(selection);
updateWizard(getSelectedValidator());
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
// Configure button
configureValidatorButton = new Button(validatorGroup, SWT.PUSH);
configureValidatorButton.setText("Configure validator...");
configureValidatorButton.setEnabled(false);
getWizard().addIOWizardListener(this);
}
@Override
public void onShowPage(boolean firstShow) {
super.onShowPage(firstShow);
updateState();
}
@Override
public void contentTypeChanged(IContentType contentType) {
updateState();
}
@Override
public void providerDescriptorChanged(IOProviderDescriptor providerFactory) {
// do nothing
}
@Override
public void dispose() {
getWizard().removeIOWizardListener(this);
super.dispose();
}
private void addValidator(IOProviderDescriptor selection) {
InstanceValidator validator;
try {
validator = (InstanceValidator) selection.createExtensionObject();
// set schemas
List<? extends Locatable> schemas = getWizard().getProvider().getValidationSchemas();
validator.setSchemas(schemas.toArray(new Locatable[schemas.size()]));
getWizard().addValidator(validator);
ValidatorEntry entry = new ValidatorEntry(validator, selection);
validators.add(entry);
updateWizard(getSelectedValidator());
} catch (Exception e) {
this.getPage().setErrorMessage("Could not instantiate validator.");
log.error(MessageFormat.format("Could not instantiate validator {0}",
selection.getIdentifier(), e));
}
}
/**
* Update the wizard
*
* @param entry the current selection
*/
private void updateWizard(final ValidatorEntry entry) {
configureValidatorButton.setEnabled(false);
if (this.configureButtonListener != null) {
configureValidatorButton.removeSelectionListener(configureButtonListener);
configureButtonListener = null;
}
updateState();
if (entry == null) {
removeValidatorButton.setEnabled(false);
return;
}
removeValidatorButton.setEnabled(true);
final ConfigurationDialogFactory configDialogFactory = ConfigurationDialogExtension
.getInstance().getConfigurationDialog(entry.getDescriptor());
if (configDialogFactory != null) {
configureValidatorButton.setEnabled(true);
configureButtonListener = new SelectionListener() {
@SuppressWarnings("unchecked")
@Override
public void widgetSelected(SelectionEvent e) {
try {
@SuppressWarnings("rawtypes")
AbstractConfigurationDialog configDialog = configDialogFactory
.createExtensionObject();
configDialog.setProvider(entry.getValidator());
configDialog.create();
configDialog.open();
updateState();
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
};
configureValidatorButton.addSelectionListener(configureButtonListener);
}
}
/**
* @see eu.esdihumboldt.hale.ui.io.target.FileTarget#updateState()
*/
@Override
protected void updateState() {
if (addValidatorButton != null) {
IContentType contentType = getWizard().getContentType();
Collection<IOProviderDescriptor> factories = new ArrayList<>();
if (contentType != null) {
factories.addAll(HaleIO.getProviderFactories(InstanceValidator.class));
factories = HaleIO.filterFactories(factories, contentType);
}
if (factories.isEmpty()) {
addValidatorButton.setEnabled(false);
}
else {
addValidatorButton.setEnabled(true);
}
}
if (validatorsTableViewer != null) {
validatorsTableViewer.setInput(validators);
}
checkValidatorConfigurations();
super.updateState();
}
/**
* @see eu.esdihumboldt.hale.ui.io.target.FileTarget#isValid()
*/
@Override
protected boolean isValid() {
return super.isValid() && checkValidatorConfigurations();
}
private ValidatorEntry getSelectedValidator() {
return getSelectedValidator(validatorsTableViewer.getSelection());
}
private ValidatorEntry getSelectedValidator(ISelection selection) {
if (selection == null || selection.equals(StructuredSelection.EMPTY)) {
return null;
}
if (selection instanceof StructuredSelection) {
Object selectedObject = ((StructuredSelection) selection).getFirstElement();
if (selectedObject instanceof ValidatorEntry) {
return (ValidatorEntry) selectedObject;
}
}
return null;
}
/**
* Checks if the given {@link InstanceValidator}s are properly configured.
* If not, an error message is displayed and the owning {@link WizardPage}
* is told that is not complete.
*
* @return true if all validator are properly configured
*/
private boolean checkValidatorConfigurations() {
if (validators == null) {
return true;
}
boolean allValid = true;
for (ValidatorEntry validator : validators) {
try {
validator.getValidator().validate();
validator.setStatusMessage(null);
} catch (IOProviderConfigurationException e) {
validator.setStatusMessage(e.getMessage());
allValid = false;
}
}
if (!allValid) {
getPage().setErrorMessage("Validators are not configured properly.");
}
else {
getPage().setErrorMessage(null);
}
if (validatorsTableViewer != null) {
validatorsTableViewer.refresh();
}
return allValid;
}
private class ValidatorEntry {
private final InstanceValidator validator;
private final IOProviderDescriptor descriptor;
private String statusMessage;
/**
* Creates a new entry for the validator table
*
* @param validator the {@link InstanceValidator}
* @param descriptor the {@link IOProviderDescriptor} of this validator
*/
public ValidatorEntry(InstanceValidator validator, IOProviderDescriptor descriptor) {
this.validator = validator;
this.descriptor = descriptor;
}
/**
* @return the {@link InstanceValidator} of this entry
*/
public InstanceValidator getValidator() {
return validator;
}
/**
* @return the {@link IOProviderDescriptor} of this entry
*/
public IOProviderDescriptor getDescriptor() {
return descriptor;
}
/**
* @return the status message (can be null)
*/
public String getStatusMessage() {
return statusMessage;
}
/**
* @param statusMessage the status message to set
*/
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
}
}