/* * 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.views.data.internal.filter; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.viewers.ArrayContentProvider; 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.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.PlatformUI; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import eu.esdihumboldt.hale.common.align.model.Cell; import eu.esdihumboldt.hale.common.align.transformation.report.TransformationReport; import eu.esdihumboldt.hale.common.align.transformation.service.TransformationService; import eu.esdihumboldt.hale.common.align.transformation.service.impl.DefaultInstanceSink; import eu.esdihumboldt.hale.common.core.HalePlatform; import eu.esdihumboldt.hale.common.core.io.ProgressMonitorIndicator; import eu.esdihumboldt.hale.common.instance.model.Instance; import eu.esdihumboldt.hale.common.instance.model.InstanceCollection; import eu.esdihumboldt.hale.common.instance.model.InstanceMetadata; import eu.esdihumboldt.hale.common.instance.model.ResourceIterator; import eu.esdihumboldt.hale.common.instance.model.impl.DefaultInstanceCollection; import eu.esdihumboldt.hale.common.schema.model.TypeDefinition; import eu.esdihumboldt.hale.ui.HaleUI; import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionComparator; import eu.esdihumboldt.hale.ui.common.definition.viewer.DefinitionLabelProvider; import eu.esdihumboldt.hale.ui.service.align.AlignmentService; import eu.esdihumboldt.hale.ui.service.align.AlignmentServiceAdapter; import eu.esdihumboldt.hale.ui.service.instance.sample.InstanceSampleService; /** * Instance selector based on a transformation sample * * @author Simon Templer * @partner 01 / Fraunhofer Institute for Computer Graphics Research */ public class SampleTransformInstanceSelector implements InstanceSelector { /** * Instance selector control */ private class InstanceSelectorControl extends Composite { private final ComboViewer typesCombo; private final ListMultimap<TypeDefinition, Instance> instanceMap = ArrayListMultimap .create(); private TypeDefinition selectedType; private final Observer referenceListener; private AlignmentServiceAdapter alignmentListener; /** * @see Composite#Composite(Composite, int) */ public InstanceSelectorControl(Composite parent, int style) { super(parent, style); setLayout(new GridLayout(1, false)); // feature type selector typesCombo = new ComboViewer(this, SWT.READ_ONLY); typesCombo.setContentProvider(ArrayContentProvider.getInstance()); typesCombo.setComparator(new DefinitionComparator()); typesCombo.setLabelProvider(new DefinitionLabelProvider(null)); typesCombo.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { updateSelection(); } }); typesCombo.getControl() .setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); updateFeatureTypesSelection(); // service listeners InstanceSampleService rss = PlatformUI.getWorkbench() .getService(InstanceSampleService.class); rss.addObserver(referenceListener = new Observer() { @Override public void update(Observable arg0, Object arg1) { updateInDisplayThread(); } }); AlignmentService alService = PlatformUI.getWorkbench() .getService(AlignmentService.class); alService.addListener(alignmentListener = new AlignmentServiceAdapter() { @Override public void alignmentCleared() { updateInDisplayThread(); } @Override public void cellsRemoved(Iterable<Cell> cells) { updateInDisplayThread(); } @Override public void cellsReplaced(Map<? extends Cell, ? extends Cell> cells) { updateInDisplayThread(); } @Override public void cellsAdded(Iterable<Cell> cells) { updateInDisplayThread(); } @Override public void alignmentChanged() { updateInDisplayThread(); } @Override public void customFunctionsChanged() { updateInDisplayThread(); } @Override public void cellsPropertyChanged(Iterable<Cell> cells, String propertyName) { // property changes may affect transformation result updateInDisplayThread(); } }); } private void updateInDisplayThread() { if (Display.getCurrent() != null) { preSelectionChanged(); updateFeatureTypesSelection(); postSelectionChanged(); } else { final Display display = PlatformUI.getWorkbench().getDisplay(); display.syncExec(new Runnable() { @Override public void run() { preSelectionChanged(); updateFeatureTypesSelection(); postSelectionChanged(); } }); } } /** * Update the feature types selection */ protected void updateFeatureTypesSelection() { instanceMap.clear(); final AtomicBoolean finished = new AtomicBoolean(false); Job job = new Job("Transform samples") { @Override protected IStatus run(IProgressMonitor monitor) { try { final InstanceSampleService rss = PlatformUI.getWorkbench() .getService(InstanceSampleService.class); final AlignmentService alService = PlatformUI.getWorkbench() .getService(AlignmentService.class); final TransformationService cst = HalePlatform .getService(TransformationService.class); // get reference instances Collection<Instance> reference = rss.getReferenceInstances(); if (reference != null && !reference.isEmpty()) { // create an instance collection InstanceCollection instances = new DefaultInstanceCollection(reference); DefaultInstanceSink target = new DefaultInstanceSink(); // transform features TransformationReport report = cst.transform(alService.getAlignment(), // Alignment instances, target, HaleUI.getServiceProvider(), new ProgressMonitorIndicator(monitor)); if (!report.isSuccess()) { // TODO log message } // Sort target instances by comparing meta data IDs // of the source // instances with the SourcesIDs of the target // instances ArrayList<Instance> targetSorted = new ArrayList<Instance>(); ResourceIterator<Instance> it = instances.iterator(); try { while (it.hasNext()) { Instance inst = it.next(); for (Instance instance : target.getInstances()) { if (InstanceMetadata.getID(inst) .equals(InstanceMetadata.getSourceID(instance))) { targetSorted.add(instance); } } } } finally { it.close(); } // check if there are target instances without a // matched source id for (Instance instance : target.getInstances()) { if (!targetSorted.contains(instance)) { targetSorted.add(instance); } } // determine types for (Instance instance : targetSorted) { instanceMap.put(instance.getDefinition(), instance); } } return Status.OK_STATUS; } finally { finished.set(true); } } }; job.schedule(); if (Display.getCurrent() != null) { while (!finished.get()) { if (!Display.getCurrent().readAndDispatch()) { try { Thread.sleep(100); } catch (InterruptedException e) { // ignore } } } } try { job.join(); } catch (InterruptedException e) { // ignore } Collection<TypeDefinition> selectableTypes = instanceMap.keySet(); typesCombo.setInput(selectableTypes); if (!selectableTypes.isEmpty()) { typesCombo.setSelection(new StructuredSelection(selectableTypes.iterator().next())); typesCombo.getControl().setEnabled(true); } else { typesCombo.getControl().setEnabled(false); } layout(true, true); updateSelection(); } /** * Update the selection */ protected void updateSelection() { if (!typesCombo.getSelection().isEmpty()) { TypeDefinition featureType = (TypeDefinition) ((IStructuredSelection) typesCombo .getSelection()).getFirstElement(); selectedType = featureType; } else { selectedType = null; } for (InstanceSelectionListener listener : listeners) { listener.selectionChanged(selectedType, getSelection()); } } /** * calling pre selection change in listener */ public void preSelectionChanged() { // disable types combo box before any changes apply to transformed // data view, // enable it again after selection change completed and if combo box // has entries typesCombo.getControl().setEnabled(false); for (InstanceSelectionListener listener : listeners) { listener.preSelectionChange(); } } /** * calling post selection change in listener */ public void postSelectionChanged() { for (InstanceSelectionListener listener : listeners) { listener.postSelectionChange(); } } /** * Get the currently selected features * * @return the currently selected features */ public Iterable<Instance> getSelection() { if (selectedType == null) { return null; } else { return instanceMap.get(selectedType); } } /** * @see Widget#dispose() */ @Override public void dispose() { InstanceSampleService rss = PlatformUI.getWorkbench() .getService(InstanceSampleService.class); rss.deleteObserver(referenceListener); AlignmentService alService = PlatformUI.getWorkbench() .getService(AlignmentService.class); alService.removeListener(alignmentListener); listeners.clear(); super.dispose(); } } private final Set<InstanceSelectionListener> listeners = new HashSet<InstanceSelectionListener>(); private InstanceSelectorControl current; /** * @see InstanceSelector#addSelectionListener(InstanceSelectionListener) */ @Override public void addSelectionListener(InstanceSelectionListener listener) { listeners.add(listener); if (current != null && !current.isDisposed()) { listener.selectionChanged(current.selectedType, current.getSelection()); } } /** * @see InstanceSelector#createControl(Composite) */ @Override public Control createControl(Composite parent) { current = new InstanceSelectorControl(parent, SWT.NONE); return current; } /** * @see InstanceSelector#removeSelectionListener(InstanceSelectionListener) */ @Override public void removeSelectionListener(InstanceSelectionListener listener) { listeners.remove(listener); } }