| /******************************************************************************* |
| * Copyright (c) 2009, 2015 Kiel University and others. |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Kiel University - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.sirius.diagram.elk; |
| |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.PointList; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.gmf.runtime.common.core.command.CommandResult; |
| import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil; |
| import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand; |
| import org.eclipse.gmf.runtime.notation.Edge; |
| import org.eclipse.gmf.runtime.notation.IdentityAnchor; |
| import org.eclipse.gmf.runtime.notation.NotationFactory; |
| import org.eclipse.gmf.runtime.notation.NotationPackage; |
| import org.eclipse.gmf.runtime.notation.RelativeBendpoints; |
| import org.eclipse.gmf.runtime.notation.Routing; |
| import org.eclipse.gmf.runtime.notation.RoutingStyle; |
| import org.eclipse.gmf.runtime.notation.Smoothness; |
| import org.eclipse.gmf.runtime.notation.StringValueStyle; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint; |
| |
| /** |
| * Command used to apply layout. |
| * |
| * Copied from org.eclipse.elk.conn.gmf.GmfLayoutCommand of commit |
| * e99248e44c71a5a02fe45bc4cd5150cd7f50c559. |
| * |
| * @author msp |
| * @kieler.design proposed by msp |
| * @kieler.rating proposed yellow by msp |
| * @see org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand |
| * @see org.eclipse.gmf.runtime.diagram.ui.internal.commands.SetConnectionBendpointsCommand |
| * @see org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand |
| */ |
| @SuppressWarnings("restriction") |
| public class GmfLayoutCommand extends AbstractTransactionalCommand { |
| |
| /** Style name for serialized junction points. */ |
| public static final String JUNCTION_POINTS_STYLE_NAME = "junctionPoints"; |
| |
| /** layout data for node shapes. */ |
| private static final class ShapeLayoutData { |
| private View view; |
| |
| private Point location; |
| |
| private Dimension size; |
| |
| private ShapeLayoutData() { |
| } |
| } |
| |
| /** layout data for edges. */ |
| private static final class EdgeLayoutData { |
| private Edge edge; |
| |
| private PointList bends; |
| |
| private String junctionPoints; |
| |
| private String sourceTerminal; |
| |
| private String targetTerminal; |
| |
| private EdgeLayoutData() { |
| } |
| } |
| |
| /** adapter for the view of the base diagram. */ |
| private IAdaptable diagramViewAdapter; |
| |
| /** list of shape layouts to be applied to nodes. */ |
| private List<ShapeLayoutData> shapeLayouts = new LinkedList<ShapeLayoutData>(); |
| |
| /** list of edge layouts to be applied to edges. */ |
| private List<EdgeLayoutData> edgeLayouts = new LinkedList<EdgeLayoutData>(); |
| |
| /** indicates whether oblique routing style shall be enforced. */ |
| private boolean obliqueRouting = false; |
| |
| /** |
| * Creates a command to apply layout. |
| * |
| * @param domain |
| * the editing domain through which model changes are made |
| * @param label |
| * the command label |
| * @param adapter |
| * an adapter to the {@code View} of the base diagram |
| */ |
| public GmfLayoutCommand(final TransactionalEditingDomain domain, final String label, final IAdaptable adapter) { |
| super(domain, label, null); |
| this.diagramViewAdapter = adapter; |
| } |
| |
| /** |
| * Adds the given shape layout data to this command. |
| * |
| * @param view |
| * view from the GMF notation model |
| * @param location |
| * new location for the view, or {@code null} if the location |
| * shall not be changed |
| * @param size |
| * new size for the view, or {@code null} if the size shall not |
| * be changed |
| */ |
| public void addShapeLayout(final View view, final Point location, final Dimension size) { |
| assert view != null; |
| ShapeLayoutData layout = new ShapeLayoutData(); |
| layout.view = view; |
| layout.location = location; |
| layout.size = size; |
| shapeLayouts.add(layout); |
| } |
| |
| /** |
| * Adds the given edge layout data to this command. |
| * |
| * @param edge |
| * edge from the GMF notation model |
| * @param bends |
| * list of bend points for the edge, or {@code null} if the bend |
| * points shall not be changed |
| * @param junctionPoints |
| * list of junction points to draw on the edge, encoded as |
| * string, or {@code null} if no junction points shall be drawn |
| * @param sourceTerminal |
| * new source terminal, encoded as string, or {@code null} if the |
| * source terminal shall not be changed |
| * @param targetTerminal |
| * new target terminal, encoded as string, or {@code null} if the |
| * target terminal shall not be changed |
| */ |
| public void addEdgeLayout(final Edge edge, final PointList bends, final String sourceTerminal, final String targetTerminal, final String junctionPoints) { |
| assert edge != null; |
| EdgeLayoutData layout = new EdgeLayoutData(); |
| layout.edge = edge; |
| layout.bends = bends; |
| layout.junctionPoints = junctionPoints; |
| layout.sourceTerminal = sourceTerminal; |
| layout.targetTerminal = targetTerminal; |
| edgeLayouts.add(layout); |
| } |
| |
| /** |
| * Enforces all edges to be drawn with oblique routing style. |
| * |
| * @param theobliqueRouting |
| * whether oblique routing stlye shall be used or not |
| */ |
| public void setObliqueRouting(final boolean theobliqueRouting) { |
| this.obliqueRouting = theobliqueRouting; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @SuppressWarnings("unchecked") |
| @Override |
| protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException { |
| monitor.beginTask(getLabel(), 1); |
| // process shape layout data |
| for (ShapeLayoutData shapeLayout : shapeLayouts) { |
| // set new location of the element |
| if (shapeLayout.location != null) { |
| ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getLocation_X(), Integer.valueOf(shapeLayout.location.x)); |
| ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getLocation_Y(), Integer.valueOf(shapeLayout.location.y)); |
| } |
| // set new size of the element |
| if (shapeLayout.size != null) { |
| ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getSize_Width(), Integer.valueOf(shapeLayout.size.width)); |
| ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getSize_Height(), Integer.valueOf(shapeLayout.size.height)); |
| } |
| } |
| shapeLayouts.clear(); |
| |
| // process edge layout data |
| for (EdgeLayoutData edgeLayout : edgeLayouts) { |
| // set new bend points of the edge |
| if (edgeLayout.bends != null) { |
| List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>(edgeLayout.bends.size()); |
| Point sourcePoint = edgeLayout.bends.getFirstPoint(); |
| Point targetPoint = edgeLayout.bends.getLastPoint(); |
| for (int i = 0; i < edgeLayout.bends.size(); i++) { |
| Point bend = edgeLayout.bends.getPoint(i); |
| newBendpoints.add(new RelativeBendpoint(bend.x - sourcePoint.x, bend.y - sourcePoint.y, bend.x - targetPoint.x, bend.y - targetPoint.y)); |
| } |
| RelativeBendpoints points = (RelativeBendpoints) edgeLayout.edge.getBendpoints(); |
| points.setPoints(newBendpoints); |
| } |
| |
| // set new source anchor point of the edge |
| if (edgeLayout.sourceTerminal != null) { |
| IdentityAnchor anchor = (IdentityAnchor) edgeLayout.edge.getSourceAnchor(); |
| if (anchor == null) { |
| anchor = NotationFactory.eINSTANCE.createIdentityAnchor(); |
| edgeLayout.edge.setSourceAnchor(anchor); |
| } |
| anchor.setId(edgeLayout.sourceTerminal); |
| } |
| // set new target anchor point of the edge |
| if (edgeLayout.targetTerminal != null) { |
| IdentityAnchor anchor = (IdentityAnchor) edgeLayout.edge.getTargetAnchor(); |
| if (anchor == null) { |
| anchor = NotationFactory.eINSTANCE.createIdentityAnchor(); |
| edgeLayout.edge.setTargetAnchor(anchor); |
| } |
| anchor.setId(edgeLayout.targetTerminal); |
| } |
| |
| // set junction points as style |
| StringValueStyle style = (StringValueStyle) edgeLayout.edge.getNamedStyle(NotationPackage.eINSTANCE.getStringValueStyle(), JUNCTION_POINTS_STYLE_NAME); |
| if (edgeLayout.junctionPoints == null) { |
| if (style != null) { |
| edgeLayout.edge.getStyles().remove(style); |
| } |
| } else { |
| if (style == null) { |
| style = NotationFactory.eINSTANCE.createStringValueStyle(); |
| style.setName(JUNCTION_POINTS_STYLE_NAME); |
| edgeLayout.edge.getStyles().add(style); |
| } |
| style.setStringValue(edgeLayout.junctionPoints); |
| } |
| |
| // set routing style to oblique |
| if (obliqueRouting) { |
| RoutingStyle routingStyle = (RoutingStyle) edgeLayout.edge.getStyle(NotationPackage.eINSTANCE.getRoutingStyle()); |
| if (routingStyle != null) { |
| routingStyle.setRouting(Routing.MANUAL_LITERAL); |
| routingStyle.setSmoothness(Smoothness.NONE_LITERAL); |
| } |
| } |
| } |
| edgeLayouts.clear(); |
| |
| monitor.done(); |
| return CommandResult.newOKCommandResult(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public List<?> getAffectedFiles() { |
| if (diagramViewAdapter != null) { |
| View view = diagramViewAdapter.getAdapter(View.class); |
| if (view != null) { |
| return getWorkspaceFiles(view); |
| } |
| } |
| return super.getAffectedFiles(); |
| } |
| |
| } |