/* * Copyright (c) 2013 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.function.common; import org.eclipse.core.runtime.ListenerList; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; 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.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; 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 com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import eu.esdihumboldt.hale.common.align.extension.function.FunctionDefinition; import eu.esdihumboldt.hale.common.align.extension.function.FunctionUtil; import eu.esdihumboldt.hale.common.align.model.AlignmentUtil; import eu.esdihumboldt.hale.common.align.model.Cell; import eu.esdihumboldt.hale.common.align.model.CellUtil; import eu.esdihumboldt.hale.common.align.model.Entity; import eu.esdihumboldt.hale.common.align.model.Type; import eu.esdihumboldt.hale.common.align.model.impl.DefaultCell; import eu.esdihumboldt.hale.common.align.model.impl.DefaultType; import eu.esdihumboldt.hale.common.align.model.impl.TypeEntityDefinition; import eu.esdihumboldt.hale.common.schema.SchemaSpaceID; import eu.esdihumboldt.hale.ui.HaleUI; import eu.esdihumboldt.hale.ui.common.function.viewer.FunctionLabelProvider; import eu.esdihumboldt.hale.ui.internal.HALEUIPlugin; /** * Creates a control for selection of source and target type entity definitions. * The selection can happen one by one, but also by selecting a type cell.<br> * Listeners can be added individually to the source and target selectors or to * this selector, which provides (incomplete) cells. * * @author Kai Schwierczek */ public class SourceTargetTypeSelector implements ISelectionProvider { // TODO This selector for now only supports one source type! private final Composite main; private final TypeEntitySelector targetTypeSelector; private final TypeEntitySelector sourceTypeSelector; private final Button selectCellButton; private Cell selectedCell; private final FunctionLabelProvider functionLabels = new FunctionLabelProvider(); private final ListenerList selectionChangedListeners = new ListenerList(); boolean inUpdate = false; /** * Creates a new selector. * * @param parent the parent composite */ public SourceTargetTypeSelector(Composite parent) { main = new Composite(parent, SWT.NONE); main.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { functionLabels.dispose(); } }); main.setLayout(new GridLayout(4, false)); ISelectionChangedListener listener = new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { if (!inUpdate) fireSelectionChanged(); } }; GridDataFactory selectorgd = GridDataFactory.fillDefaults().grab(true, false) .hint(200, SWT.DEFAULT); sourceTypeSelector = new TypeEntitySelector(SchemaSpaceID.SOURCE, null, main, false); selectorgd.applyTo(sourceTypeSelector.getControl()); sourceTypeSelector.addSelectionChangedListener(listener); selectCellButton = new Button(main, SWT.PUSH); selectCellButton.setText("Select cell"); selectCellButton.setToolTipText("Select a type cell"); selectCellButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { TypeCellSelectionDialog dialog = new TypeCellSelectionDialog(main.getShell() .getShell(), "Select a type cell", selectedCell); if (dialog.open() == TypeCellSelectionDialog.OK) { Cell selected = dialog.getObject(); inUpdate = true; setSelection(selected); inUpdate = false; fireSelectionChanged(); } } }); Button resetSelectionButton = new Button(main, SWT.PUSH); resetSelectionButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setSelection(StructuredSelection.EMPTY); } }); final Image resetSelectionImage = HALEUIPlugin.getImageDescriptor("icons/remove.gif") .createImage(); resetSelectionButton.setImage(resetSelectionImage); resetSelectionButton.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { resetSelectionImage.dispose(); } }); resetSelectionButton.setToolTipText("Reset selection"); targetTypeSelector = new TypeEntitySelector(SchemaSpaceID.TARGET, null, main, false); selectorgd.applyTo(targetTypeSelector.getControl()); targetTypeSelector.addSelectionChangedListener(listener); } /** * Adds a listener for selection changes in the specified selection. Has no * effect if an identical listener is already registered. * * @param listener a selection changed listener * @param ssid the selection to add the listener to */ public void addSelectionChangedListener(ISelectionChangedListener listener, SchemaSpaceID ssid) { if (ssid == SchemaSpaceID.SOURCE) sourceTypeSelector.addSelectionChangedListener(listener); else targetTypeSelector.addSelectionChangedListener(listener); } /** * Removes the given selection change listener from the specified selection * provider. Has no effect if an identical listener is not registered. * * @param listener a selection changed listener * @param ssid the selection to remove the listener from */ public void removeSelectionChangedListener(ISelectionChangedListener listener, SchemaSpaceID ssid) { if (ssid == SchemaSpaceID.SOURCE) sourceTypeSelector.removeSelectionChangedListener(listener); else targetTypeSelector.removeSelectionChangedListener(listener); } /** * Returns the selected type entity definition of the given schema space. * * @param ssid the schema space in question * @return the selected type entity definition, may be <code>null</code> */ public TypeEntityDefinition getSelection(SchemaSpaceID ssid) { if (ssid == SchemaSpaceID.SOURCE) return (TypeEntityDefinition) sourceTypeSelector.getSelectedObject(); else return (TypeEntityDefinition) targetTypeSelector.getSelectedObject(); } /** * Returns the selected cell. If no cell is selected a dummy cell with the * selected source and target is returned. Both source and target may or may * not be empty in that case. * * @return the selected cell (or a dummy) */ public Cell getSelectedCell() { if (selectedCell != null) return selectedCell; DefaultCell cell = new DefaultCell(); if (sourceTypeSelector.getSelectedObject() != null) { ListMultimap<String, Type> sources = ArrayListMultimap.create(1, 1); sources.put(null, new DefaultType((TypeEntityDefinition) sourceTypeSelector.getSelectedObject())); cell.setSource(sources); } if (targetTypeSelector.getSelectedObject() != null) { ListMultimap<String, Type> targets = ArrayListMultimap.create(1, 1); targets.put(null, new DefaultType((TypeEntityDefinition) targetTypeSelector.getSelectedObject())); cell.setTarget(targets); } return cell; } /** * Returns whether an existing cell is selected. * * @return whether an existing cell is selected */ public boolean isCellSelected() { return selectedCell != null; } /** * Sets the selected type entity definitions.<br> * If an existing cell was selected, that selection is undone. * * @param type the type to select, may be <code>null</code> * @param ssid the schema space to set the type to (needed because type may * be null) */ public void setSelection(TypeEntityDefinition type, SchemaSpaceID ssid) { inUpdate = true; // undo cell selection setSelection((Cell) null); ISelection selection = (type == null) ? StructuredSelection.EMPTY : new StructuredSelection(type); if (ssid == SchemaSpaceID.SOURCE) sourceTypeSelector.setSelection(selection); else if (ssid == SchemaSpaceID.TARGET) targetTypeSelector.setSelection(selection); inUpdate = false; fireSelectionChanged(); } /** * Sets the selection according to the given cell.<br> * If the cell is a property cell, it will select the types whom the * properties belong to.<br> * If <code>cell</code> is <code>null</code> the selected types aren't * changed, but is an existing type cell was selected, that selection is * undone. * * @param cell the cell to set the selection to */ private void setSelection(Cell cell) { if (cell != null) { // in case of a real join cell there are multiple source types if (cell.getSource() == null || cell.getSource().isEmpty()) sourceTypeSelector.setSelection(StructuredSelection.EMPTY); else if (cell.getSource().size() > 1) sourceTypeSelector.showText("<multiple types>"); else { Entity source = CellUtil.getFirstEntity(cell.getSource()); ISelection selection = new StructuredSelection(AlignmentUtil.getTypeEntity(source .getDefinition())); sourceTypeSelector.setSelection(selection); } // target can only be one or none Entity target = CellUtil.getFirstEntity(cell.getTarget()); ISelection selection = (target == null) ? StructuredSelection.EMPTY : new StructuredSelection(AlignmentUtil.getTypeEntity(target.getDefinition())); targetTypeSelector.setSelection(selection); } if (cell != null && AlignmentUtil.isTypeCell(cell) && cell.getId() != null) { // a real type cell selectedCell = cell; String label; String functionId = cell.getTransformationIdentifier(); FunctionDefinition<?> function = FunctionUtil.getFunction(functionId, HaleUI.getServiceProvider()); if (function != null) label = functionLabels.getText(function); else label = functionId; selectCellButton.setText(label); sourceTypeSelector.getControl().setEnabled(false); targetTypeSelector.getControl().setEnabled(false); } else { selectedCell = null; selectCellButton.setText("Select cell"); sourceTypeSelector.getControl().setEnabled(true); targetTypeSelector.getControl().setEnabled(true); } } /** * Returns the main selector control. * * @return the main selector control */ public Control getControl() { return main; } /** * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void addSelectionChangedListener(ISelectionChangedListener listener) { selectionChangedListeners.add(listener); } /** * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() */ @Override public ISelection getSelection() { return new StructuredSelection(getSelectedCell()); } /** * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) */ @Override public void removeSelectionChangedListener(ISelectionChangedListener listener) { selectionChangedListeners.remove(listener); } /** * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) */ @Override public void setSelection(ISelection selection) { inUpdate = true; if (selection.isEmpty()) { setSelection((Cell) null); sourceTypeSelector.setSelection(selection); targetTypeSelector.setSelection(selection); } else if (selection instanceof IStructuredSelection) setSelection((Cell) ((IStructuredSelection) selection).getFirstElement()); inUpdate = false; fireSelectionChanged(); } /** * Fire a selection changed event to all listeners. */ private void fireSelectionChanged() { SelectionChangedEvent event = new SelectionChangedEvent(this, new StructuredSelection( getSelectedCell())); for (Object listener : selectionChangedListeners.getListeners()) ((ISelectionChangedListener) listener).selectionChanged(event); } }