/* * Copyright (c) 2012 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.scripting.groovy; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.source.CompositeRuler; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.LineNumberRulerColumn; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition; import eu.esdihumboldt.hale.common.align.transformation.function.PropertyValue; import eu.esdihumboldt.hale.common.align.transformation.function.impl.PropertyValueImpl; import eu.esdihumboldt.hale.common.scripting.Script; import eu.esdihumboldt.hale.ui.HaleUI; import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionLabelProvider; import eu.esdihumboldt.hale.ui.common.editors.AbstractAttributeEditor; import eu.esdihumboldt.hale.ui.util.IColorManager; import eu.esdihumboldt.hale.ui.util.groovy.GroovyColorManager; import eu.esdihumboldt.hale.ui.util.groovy.GroovySourceViewerUtil; import eu.esdihumboldt.hale.ui.util.groovy.SimpleGroovySourceViewerConfiguration; import eu.esdihumboldt.hale.ui.util.source.SourceViewerKeyBindings; /** * Editor for groovy scripts. * * @author Kai Schwierczek */ public class GroovyEditor extends AbstractAttributeEditor<String> { private final Composite composite; private final Script script; // private final Class<?> binding; private final SourceViewer viewer; private TableViewer varTable; private Collection<PropertyEntityDefinition> variables = Collections.emptySet(); private String currentValue = ""; private boolean valid; private final TestValues testValues; private final ControlDecoration decorator; private IColorManager colorManager; /** * Default constructor. * * @param parent the parent composite * @param script the script object * @param binding the target binding */ public GroovyEditor(Composite parent, Script script, Class<?> binding) { this.script = script; this.colorManager = new GroovyColorManager(); // this.binding = binding; testValues = new InstanceTestValues(); composite = new Composite(parent, SWT.NONE); composite.setLayout(GridLayoutFactory.swtDefaults().create()); viewer = createAndLayoutTextField(composite); viewer.configure(new SimpleGroovySourceViewerConfiguration(colorManager)); IDocument document = new Document(""); GroovySourceViewerUtil.setupDocument(document); viewer.setDocument(document); viewer.getControl().addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { // color manager needs to be disposed colorManager.dispose(); } }); // control decoration decorator = new ControlDecoration(viewer.getControl(), SWT.LEFT | SWT.TOP, composite); // set initial status decorator.hide(); // set image FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration( FieldDecorationRegistry.DEC_ERROR); decorator.setImage(fieldDecoration.getImage()); viewer.getDocument().addDocumentListener(new IDocumentListener() { @Override public void documentChanged(DocumentEvent event) { // update value String newValue = event.getDocument().get(); fireValueChanged(VALUE, currentValue, newValue); currentValue = newValue; validate(); } @Override public void documentAboutToBeChanged(DocumentEvent event) { // ignore } }); // variables Label label = new Label(composite, SWT.NONE); label.setText("Available variables (double click to insert)"); label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); // variables table Composite tableComposite = new Composite(composite, SWT.NONE); tableComposite.setLayoutData(GridDataFactory.fillDefaults().grab(true, true).create()); TableColumnLayout columnLayout = new TableColumnLayout(); tableComposite.setLayout(columnLayout); varTable = new TableViewer(tableComposite, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION); TableViewerColumn column = new TableViewerColumn(varTable, SWT.NONE); columnLayout.setColumnData(column.getColumn(), new ColumnWeightData(1, false)); varTable.setContentProvider(ArrayContentProvider.getInstance()); varTable.setLabelProvider(new DefinitionLabelProvider(null, true, true) { /** * @see eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionLabelProvider#getText(java.lang.Object) */ @Override public String getText(Object element) { return GroovyEditor.this.script.getVariableName((PropertyEntityDefinition) element); } }); varTable.getTable().addMouseListener(new MouseAdapter() { /** * @see MouseAdapter#mouseDoubleClick(MouseEvent) */ @Override public void mouseDoubleClick(MouseEvent e) { int index = varTable.getTable().getSelectionIndex(); if (index >= 0) { String var = varTable.getTable().getItem(index).getText(); Point selRange = viewer.getSelectedRange(); try { viewer.getDocument().replace(selRange.x, selRange.y, var); } catch (BadLocationException ble) { // ignore } } } }); validate(); } /** * Validates the current input against the currently available variables. */ private void validate() { // also the returned type isn't checked. String result = GroovyEditor.this.script.validate(currentValue, createPropertyValues(), HaleUI.getServiceProvider()); boolean oldValid = valid; valid = result == null; if (valid) decorator.hide(); else { decorator.setDescriptionText(result); decorator.show(); } if (valid != oldValid) fireStateChanged(IS_VALID, oldValid, valid); } /** * Returns an {@link Iterable} for the current variables for use with the * {@link Script}. * * @return an {@link Iterable} for the current variables for use with the * {@link Script} */ protected Iterable<PropertyValue> createPropertyValues() { Collection<PropertyValue> values = new ArrayList<PropertyValue>(variables.size()); for (PropertyEntityDefinition property : variables) values.add(new PropertyValueImpl(testValues.get(property), property)); return values; } /** * Create the text field. * * @param parent the parent composite * @return the input text field. */ private SourceViewer createAndLayoutTextField(Composite parent) { IVerticalRuler ruler = createRuler(); SourceViewer viewer = new SourceViewer(parent, ruler, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); viewer.getControl().setLayoutData( GridDataFactory.fillDefaults().grab(true, false).indent(7, 0).create()); viewer.getTextWidget().setFont(JFaceResources.getTextFont()); SourceViewerKeyBindings.installDefault(viewer); return viewer; } /** * Create the vertical ruler for the source viewer. * * @return the vertical ruler */ private IVerticalRuler createRuler() { final Display display = Display.getCurrent(); CompositeRuler ruler = new CompositeRuler(3); LineNumberRulerColumn lineNumbers = new LineNumberRulerColumn(); lineNumbers.setBackground(display.getSystemColor(SWT.COLOR_GRAY)); // SWT.COLOR_INFO_BACKGROUND)); lineNumbers.setForeground(display.getSystemColor(SWT.COLOR_BLACK)); // SWT.COLOR_INFO_FOREGROUND)); lineNumbers.setFont(JFaceResources.getTextFont()); ruler.addDecorator(0, lineNumbers); return ruler; } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#getControl() */ @Override public Control getControl() { return composite; } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#setValue(java.lang.Object) */ @Override public void setValue(String value) { viewer.getDocument().set(value); currentValue = value; } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#getValue() */ @Override public String getValue() { return currentValue; } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#setAsText(java.lang.String) */ @Override public void setAsText(String text) { setValue(text); } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#getAsText() */ @Override public String getAsText() { return getValue(); } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#isValid() */ @Override public boolean isValid() { return valid; } /** * @see eu.esdihumboldt.hale.ui.common.editors.AbstractAttributeEditor#setVariables(java.util.Collection) */ @Override public void setVariables(Collection<PropertyEntityDefinition> properties) { variables = properties; varTable.setInput(variables); validate(); } /** * @see eu.esdihumboldt.hale.ui.common.AttributeEditor#getValueType() */ @Override public String getValueType() { return script.getId(); } }