/* * 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.mapping; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.WorkbenchPart; import org.eclipse.zest.core.viewers.GraphViewer; import org.eclipse.zest.layouts.LayoutAlgorithm; import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import eu.esdihumboldt.hale.common.align.model.Alignment; import eu.esdihumboldt.hale.common.align.model.AlignmentUtil; import eu.esdihumboldt.hale.common.align.model.Cell; import eu.esdihumboldt.hale.common.align.model.EntityDefinition; 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.ui.HaleUI; import eu.esdihumboldt.hale.ui.common.graph.labels.GraphLabelProvider; import eu.esdihumboldt.hale.ui.selection.SchemaSelection; import eu.esdihumboldt.hale.ui.selection.SchemaSelectionHelper; import eu.esdihumboldt.hale.ui.service.align.AlignmentService; import eu.esdihumboldt.hale.ui.service.align.AlignmentServiceAdapter; import eu.esdihumboldt.hale.ui.service.align.AlignmentServiceListener; import eu.esdihumboldt.hale.ui.views.mapping.internal.MappingViewPlugin; import eu.esdihumboldt.util.Pair; /** * Mapping view. * * @author Simon Templer */ public class MappingView extends AbstractMappingView { /** * The view ID */ public static final String ID = "eu.esdihumboldt.hale.ui.views.mapping"; private ISelectionListener selectionListener; private AlignmentServiceListener alignmentListener; private final Action showCellsOnChildren; private ResizingTreeLayoutAlgorithm treeLayout; /** * Default constructor. */ public MappingView() { final String deactive = "Show cells on children"; final String active = "Hide cells on children"; showCellsOnChildren = new Action("Show cells on children", Action.AS_CHECK_BOX) { /** * @see org.eclipse.jface.action.Action#run() */ @Override public void run() { String text = isChecked() ? active : deactive; setText(text); setToolTipText(text); SchemaSelection current = SchemaSelectionHelper.getSchemaSelection(); if (current != null) { update(current); } } }; showCellsOnChildren.setChecked(false); showCellsOnChildren.setToolTipText(deactive); showCellsOnChildren .setImageDescriptor(MappingViewPlugin.getImageDescriptor("icons/sub_co.gif")); } @Override protected LayoutAlgorithm createLayout() { treeLayout = new ResizingTreeLayoutAlgorithm(TreeLayoutAlgorithm.RIGHT_LEFT, new AlignmentViewResizingStrategy()); return treeLayout; } @Override public void createViewControl(Composite parent) { super.createViewControl(parent); updateLayout(false); getSite().getWorkbenchWindow().getSelectionService() .addPostSelectionListener(selectionListener = new ISelectionListener() { @Override public void selectionChanged(IWorkbenchPart part, ISelection selection) { if (!(selection instanceof SchemaSelection)) { // only react on schema selections return; } if (part != MappingView.this) { update((SchemaSelection) selection); } } }); AlignmentService as = PlatformUI.getWorkbench().getService(AlignmentService.class); // update(); as.addListener(alignmentListener = new AlignmentServiceAdapter() { @Override public void cellsRemoved(Iterable<Cell> cells) { updateViewWithCurrentSelection(cells); } @Override public void cellsReplaced(Map<? extends Cell, ? extends Cell> cells) { List<Cell> changedCells = new ArrayList<Cell>(2); changedCells.addAll(cells.keySet()); changedCells.addAll(cells.values()); updateViewWithCurrentSelection(changedCells); } @Override public void customFunctionsChanged() { SchemaSelection current = SchemaSelectionHelper.getSchemaSelection(); if (current != null) { update(current); } } @Override public void cellsAdded(Iterable<Cell> cells) { updateViewWithCurrentSelection(cells); } @Override public void cellsPropertyChanged(Iterable<Cell> cells, String propertyName) { updateViewWithCurrentSelection(cells); } }); SchemaSelection current = SchemaSelectionHelper.getSchemaSelection(); if (current != null) { update(current); } // listen on size changes getViewer().getControl().addControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { updateLayout(true); } }); } @Override protected IBaseLabelProvider createLabelProvider(GraphViewer viewer) { return new GraphLabelProvider(viewer, HaleUI.getServiceProvider()) { @Override protected boolean isInherited(Cell cell) { // cannot inherit type cells if (AlignmentUtil.isTypeCell(cell)) return false; SchemaSelection selection = SchemaSelectionHelper.getSchemaSelection(); if (selection != null && !selection.isEmpty()) { DefaultCell dummyTypeCell = new DefaultCell(); ListMultimap<String, Type> sources = ArrayListMultimap.create(); ListMultimap<String, Type> targets = ArrayListMultimap.create(); Pair<Set<EntityDefinition>, Set<EntityDefinition>> items = getDefinitionsFromSelection( selection); for (EntityDefinition def : items.getFirst()) sources.put(null, new DefaultType(AlignmentUtil.getTypeEntity(def))); for (EntityDefinition def : items.getSecond()) targets.put(null, new DefaultType(AlignmentUtil.getTypeEntity(def))); dummyTypeCell.setSource(sources); dummyTypeCell.setTarget(targets); return AlignmentUtil.reparentCell(cell, dummyTypeCell, true) != cell; } else return false; } }; } /** * @see eu.esdihumboldt.hale.ui.views.mapping.AbstractMappingView#fillToolBar() */ @Override protected void fillToolBar() { super.fillToolBar(); IToolBarManager manager = getViewSite().getActionBars().getToolBarManager(); manager.add(showCellsOnChildren); } private void updateViewWithCurrentSelection(Iterable<Cell> cells) { SchemaSelection current = SchemaSelectionHelper.getSchemaSelection(); if (current != null && isUpdateRequired(current, cells)) { update(current); } } private boolean isUpdateRequired(SchemaSelection currentSelection, Iterable<Cell> cells) { if (cells == null || !cells.iterator().hasNext()) return false; Pair<Set<EntityDefinition>, Set<EntityDefinition>> items = getDefinitionsFromSelection( currentSelection); for (Cell cell : cells) { if ((cell.getSource() != null && associatedWith(items.getFirst(), cell)) || associatedWith(items.getSecond(), cell)) { return true; } } return false; } /** * Update the view * * @param selection the selection */ protected void update(SchemaSelection selection) { AlignmentService as = PlatformUI.getWorkbench().getService(AlignmentService.class); Alignment alignment = as.getAlignment(); List<Cell> cells = new ArrayList<Cell>(); Pair<Set<EntityDefinition>, Set<EntityDefinition>> items = getDefinitionsFromSelection( selection); // find cells associated with the selection for (Cell cell : alignment.getCells()) { if ((cell.getSource() != null && associatedWith(items.getFirst(), cell)) || associatedWith(items.getSecond(), cell)) { cells.add(cell); } } getViewer().setInput(cells); updateLayout(true); } private Pair<Set<EntityDefinition>, Set<EntityDefinition>> getDefinitionsFromSelection( SchemaSelection selection) { Set<EntityDefinition> sourceItems; Set<EntityDefinition> targetItems; if (selection instanceof IStructuredSelection) { // prefer getting information from the IStructuredSelection, which // from the Schema Explorer only contains the recently selected // elements on one side sourceItems = new HashSet<EntityDefinition>(); targetItems = new HashSet<EntityDefinition>(); for (Object object : ((IStructuredSelection) selection).toArray()) { if (object instanceof EntityDefinition) { EntityDefinition def = (EntityDefinition) object; switch (def.getSchemaSpace()) { case TARGET: targetItems.add(def); break; case SOURCE: default: sourceItems.add(def); } } } } else { sourceItems = selection.getSourceItems(); targetItems = selection.getTargetItems(); } return new Pair<Set<EntityDefinition>, Set<EntityDefinition>>(sourceItems, targetItems); } private boolean associatedWith(Collection<EntityDefinition> entityDefs, Cell cell) { for (EntityDefinition entity : entityDefs) { if (AlignmentUtil.associatedWith(entity, cell, true, showCellsOnChildren.isChecked())) { return true; } } return false; } /** * @see WorkbenchPart#dispose() */ @Override public void dispose() { if (alignmentListener != null) { AlignmentService as = PlatformUI.getWorkbench().getService(AlignmentService.class); as.removeListener(alignmentListener); } if (selectionListener != null) { getSite().getWorkbenchWindow().getSelectionService() .removePostSelectionListener(selectionListener); } super.dispose(); } /** * Show the cell with the given ID if found. * * @param cellId the cell identifier * @return if the cell was found */ public boolean selectCell(String cellId) { // try to retrieve cell AlignmentService as = PlatformUI.getWorkbench().getService(AlignmentService.class); if (as != null) { Cell cell = as.getAlignment().getCell(cellId); if (cell != null) { getViewer().setInput(Collections.singletonList(cell)); return true; } } return false; } /** * Update the layout to the view size. * * @param triggerLayout if the layout should be applied directly */ private void updateLayout(boolean triggerLayout) { int width = getViewer().getControl().getSize().x; treeLayout.setNodeSpace(new Dimension((width - 10) / 3, 30)); if (triggerLayout) { getViewer().applyLayout(); } } }