/* * 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: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.ui.style.editors; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.xml.namespace.QName; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocumentListener; import org.eclipse.jface.text.TextViewer; import org.eclipse.jface.viewers.ComboViewer; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; 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.geotools.factory.CommonFactoryFinder; import org.geotools.filter.visitor.DefaultFilterVisitor; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.PropertyIsEqualTo; import org.opengis.filter.PropertyIsGreaterThan; import org.opengis.filter.PropertyIsGreaterThanOrEqualTo; import org.opengis.filter.PropertyIsLessThan; import org.opengis.filter.PropertyIsLessThanOrEqualTo; import org.opengis.filter.PropertyIsLike; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.Literal; import org.opengis.filter.expression.PropertyName; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.common.align.model.ChildContext; import eu.esdihumboldt.hale.common.align.model.EntityDefinition; import eu.esdihumboldt.hale.common.align.model.impl.PropertyEntityDefinition; import eu.esdihumboldt.hale.common.instance.helper.PropertyResolver; import eu.esdihumboldt.hale.common.schema.model.ChildDefinition; import eu.esdihumboldt.hale.common.schema.model.DefinitionUtil; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; import eu.esdihumboldt.hale.ui.common.definition.selector.PropertyDefinitionSelector; /** * Editor for {@link Filter}s * * @author Simon Templer * @partner 01 / Fraunhofer Institute for Computer Graphics Research */ public class FilterEditor implements Editor<Filter> { /** * Filter inspector */ private abstract class FilterVisitor extends DefaultFilterVisitor { private Object visitFilter(FilterIdentifier id, Expression exp1, Expression exp2) { if (exp1 instanceof PropertyName && exp2 instanceof Literal) { visitFilter(id, ((PropertyName) exp1).getPropertyName(), ((Literal) exp2) .getValue().toString()); } else if (exp2 instanceof PropertyName && exp1 instanceof Literal) { visitFilter(id, ((PropertyName) exp2).getPropertyName(), ((Literal) exp1) .getValue().toString()); } return null; } /** * Visit a filter that matches the pattern of the {@link FilterEditor} * * @param id the filter identifier * @param propertyName the property name * @param value the value */ protected abstract void visitFilter(FilterIdentifier id, String propertyName, String value); /** * @see DefaultFilterVisitor#visit(PropertyIsEqualTo, Object) */ @Override public Object visit(PropertyIsEqualTo filter, Object data) { return visitFilter(FilterIdentifier.EQUAL, filter.getExpression1(), filter.getExpression2()); } /** * @see DefaultFilterVisitor#visit(PropertyIsLike, Object) */ @Override public Object visit(PropertyIsLike filter, Object data) { return visitFilter(FilterIdentifier.LIKE, filter.getExpression(), filterFactory.literal(filter.getLiteral())); } /** * @see DefaultFilterVisitor#visit(PropertyIsGreaterThan, Object) */ @Override public Object visit(PropertyIsGreaterThan filter, Object data) { return visitFilter(FilterIdentifier.GREATER_THAN, filter.getExpression1(), filter.getExpression2()); } /** * @see DefaultFilterVisitor#visit(PropertyIsGreaterThanOrEqualTo, * Object) */ @Override public Object visit(PropertyIsGreaterThanOrEqualTo filter, Object data) { return visitFilter(FilterIdentifier.GREATER_OR_EQUAL, filter.getExpression1(), filter.getExpression2()); } /** * @see DefaultFilterVisitor#visit(PropertyIsLessThan, Object) */ @Override public Object visit(PropertyIsLessThan filter, Object data) { return visitFilter(FilterIdentifier.LESS_THAN, filter.getExpression1(), filter.getExpression2()); } /** * @see DefaultFilterVisitor#visit(PropertyIsLessThanOrEqualTo, Object) */ @Override public Object visit(PropertyIsLessThanOrEqualTo filter, Object data) { return visitFilter(FilterIdentifier.LESS_OR_EQUAL, filter.getExpression1(), filter.getExpression2()); } } /** * Supported filters enumeration */ public enum FilterIdentifier { /** * @see FilterFactory#equals(Expression, Expression) */ EQUAL, /** * @see FilterFactory#less(Expression, Expression) */ LESS_THAN, /** * @see FilterFactory#lessOrEqual(Expression, Expression) */ LESS_OR_EQUAL, /** * @see FilterFactory#greater(Expression, Expression) */ GREATER_THAN, /** * @see FilterFactory#greaterOrEqual(Expression, Expression) */ GREATER_OR_EQUAL, /** * @see FilterFactory#like(Expression, String) */ LIKE; /** * @see Enum#toString() */ @Override public String toString() { switch (this) { case EQUAL: return "="; //$NON-NLS-1$ case LESS_THAN: return "<"; //$NON-NLS-1$ case LESS_OR_EQUAL: return "<="; //$NON-NLS-1$ case GREATER_THAN: return ">"; //$NON-NLS-1$ case GREATER_OR_EQUAL: return ">="; //$NON-NLS-1$ case LIKE: return "like"; //$NON-NLS-1$ default: return super.toString(); } } } private static final ALogger log = ALoggerFactory.getLogger(FilterEditor.class); private static final FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory(null); private final Composite page; private final PropertyDefinitionSelector propertySelect; private final ComboViewer filterSelect; private final TextViewer literal; private final Button filterEnabled; private final TypeDefinition typeDefinition; private boolean changed = false; /** * Creates a {@link Filter} editor * * @param parent the parent composite * @param typeDefinition the type definition * @param filter the initial filter */ public FilterEditor(Composite parent, TypeDefinition typeDefinition, Filter filter) { super(); this.typeDefinition = typeDefinition; page = new Composite(parent, SWT.NONE); page.setLayout(new GridLayout(4, false)); // filter enabled filterEnabled = new Button(page, SWT.CHECK); filterEnabled.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); // enable/disable controls filterEnabled.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { boolean enabled = ((Button) e.widget).getSelection(); setControlsEnabled(enabled); changed = true; } @Override public void widgetDefaultSelected(SelectionEvent e) { // ignore } }); // property select propertySelect = new PropertyDefinitionSelector(page, typeDefinition, null); propertySelect.getControl().setLayoutData( GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).minSize(100, SWT.DEFAULT) .grab(true, false).create()); // filter here // filter select filterSelect = new ComboViewer(page); filterSelect.getControl().setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); filterSelect.add(FilterIdentifier.values()); // literal editor literal = new TextViewer(page, SWT.SINGLE | SWT.BORDER); literal.getControl().setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); literal.setDocument(new Document()); // set initial values setValue(filter); // change listeners propertySelect.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { changed = true; } }); filterSelect.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { changed = true; } }); literal.getDocument().addDocumentListener(new IDocumentListener() { @Override public void documentChanged(DocumentEvent event) { changed = true; } @Override public void documentAboutToBeChanged(DocumentEvent event) { // ignore } }); } private void setControlsEnabled(boolean enabled) { propertySelect.getControl().setEnabled(enabled); filterSelect.getControl().setEnabled(enabled); literal.getControl().setEnabled(enabled); } /** * @see Editor#getControl() */ @Override public Control getControl() { return page; } /** * @see Editor#getValue() */ @Override public Filter getValue() { if (filterEnabled.getSelection()) { try { FilterIdentifier id = (FilterIdentifier) ((IStructuredSelection) filterSelect .getSelection()).getFirstElement(); String propertyName = ""; // get the selected entity from the property selector (filter // fields) // and pass it to the filter EntityDefinition entity = propertySelect.getSelectedObject(); if (entity != null) { Iterator<ChildContext> childIt = entity.getPropertyPath().iterator(); if (childIt.hasNext()) { propertyName = propertyName.concat(childIt.next().getChild().getName() .toString()); } while (childIt.hasNext()) { propertyName = propertyName.concat("." + childIt.next().getChild().getName().toString()); } } else { propertyName = "<select>"; } String valueText = literal.getDocument().get(); Expression property = filterFactory.property(propertyName); Expression value = filterFactory.literal(valueText); switch (id) { case EQUAL: return filterFactory.equals(property, value); case LESS_THAN: return filterFactory.less(property, value); case LESS_OR_EQUAL: return filterFactory.lessOrEqual(property, value); case GREATER_THAN: return filterFactory.greater(property, value); case GREATER_OR_EQUAL: return filterFactory.greaterOrEqual(property, value); case LIKE: return filterFactory.like(property, valueText); default: return null; } } catch (Exception e) { log.warn("Error getting filter", e); //$NON-NLS-1$ return null; } } else { // no filter return null; } } /** * @see Editor#isChanged() */ @Override public boolean isChanged() { return changed; } /** * @see Editor#setValue(Object) */ @Override public void setValue(final Filter filter) { filterEnabled.setSelection(false); setControlsEnabled(false); if (filter != null) { filter.accept(new FilterVisitor() { @Override protected void visitFilter(FilterIdentifier id, String propertyName, String value) { Boolean invalidProperty = false; List<ChildContext> path = new ArrayList<ChildContext>(); // set the correct selected name for the property selector List<QName> qNames = PropertyResolver.getQNamesFromPath(propertyName); ChildDefinition<?> child = typeDefinition.getChild(qNames.get(0)); if (child != null) { path.add(new ChildContext(child)); for (int i = 1; i < qNames.size(); i++) { child = DefinitionUtil.getChild(child, qNames.get(i)); if (child != null) { path.add(new ChildContext(child)); } else { invalidProperty = true; break; } } } else { invalidProperty = true; } if (!invalidProperty && !path.isEmpty()) { PropertyEntityDefinition entity = new PropertyEntityDefinition( typeDefinition, path, null, null); propertySelect.setSelection(new StructuredSelection(entity)); } else { propertySelect.setSelection(new StructuredSelection()); } // set filter filterSelect.setSelection(new StructuredSelection(id)); // set value literal.getDocument().set(value); filterEnabled.setSelection(true); setControlsEnabled(true); } }, null); } } }