| /***************************************************************************** |
| * Copyright (c) 2014-15 CEA LIST, Montages AG and others. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Michael Golubev (Montages) - Initial API and implementation |
| * |
| *****************************************************************************/ |
| package org.eclipse.gmf.tooling.runtime.linklf; |
| |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.draw2d.AbsoluteBendpoint; |
| import org.eclipse.draw2d.Bendpoint; |
| import org.eclipse.draw2d.Connection; |
| import org.eclipse.draw2d.ConnectionAnchor; |
| import org.eclipse.draw2d.geometry.Dimension; |
| import org.eclipse.draw2d.geometry.Point; |
| import org.eclipse.draw2d.geometry.PointList; |
| import org.eclipse.gmf.runtime.notation.Edge; |
| import org.eclipse.gmf.runtime.notation.RelativeBendpoints; |
| import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint; |
| |
| /** |
| * This class defines when to enable the enhanced link anchors and bendpoints |
| * behavior, which implementation is based on storing the fixed bendpoints |
| * coordinates instead of their relative locations to anchors. |
| * |
| * @since 3.3 |
| */ |
| public abstract class AbsoluteBendpointsConvention { |
| |
| private static AbsoluteBendpointsConvention ourInstance; |
| |
| public static AbsoluteBendpointsConvention getInstance() { |
| if (ourInstance == null) { |
| // ourInstance = new OnlyForNewLinks(); |
| ourInstance = new ForAllLinks(); |
| } |
| return ourInstance; |
| } |
| |
| public abstract RelativeBendpoint createAbsoluteBendpointStoredAsRelative( |
| Point point); |
| |
| public abstract boolean isAbsoluteStoredAsRelative(RelativeBendpoint modelBP); |
| |
| public abstract Bendpoint d2dBendpoint(RelativeBendpoint modelBP, |
| Connection connection, float weight); |
| |
| public abstract boolean hasAbsoluteStoredAsRelativeBendpoints(Edge edge); |
| |
| public abstract PointList getPointList(Edge edge, Object linkConstraint); |
| |
| private abstract static class ConventionBase extends |
| AbsoluteBendpointsConvention { |
| |
| private static final int MAGIC = -643984; |
| |
| @Override |
| public RelativeBendpoint createAbsoluteBendpointStoredAsRelative( |
| Point point) { |
| return new RelativeBendpoint(point.x, point.y, MAGIC, MAGIC); |
| } |
| |
| @Override |
| public boolean isAbsoluteStoredAsRelative(RelativeBendpoint modelBP) { |
| return modelBP.getTargetX() == MAGIC |
| && modelBP.getTargetY() == MAGIC; |
| } |
| |
| @Override |
| public Bendpoint d2dBendpoint(RelativeBendpoint modelBP, |
| Connection connection, float weight) { |
| if (isAbsoluteStoredAsRelative(modelBP)) { |
| return new AbsoluteBendpoint(modelBP.getSourceX(), |
| modelBP.getSourceY()); |
| } |
| return null; |
| } |
| |
| @Override |
| public PointList getPointList(Edge edge, Object linkConstraint) { |
| PointList result = new PointList(); |
| List<?> d2dBendpoints = linkConstraint instanceof List<?> ? (List<?>) linkConstraint |
| : Collections.emptyList(); |
| RelativeBendpoints allModelBendpoints = (RelativeBendpoints) edge |
| .getBendpoints(); |
| @SuppressWarnings("unchecked") |
| List<RelativeBendpoint> modelBendpoints = allModelBendpoints |
| .getPoints(); |
| for (int i = 0; i < modelBendpoints.size(); i++) { |
| RelativeBendpoint nextModel = modelBendpoints.get(i); |
| Object nextD2d = d2dBendpoints.size() > i ? d2dBendpoints |
| .get(i) : null; |
| |
| Point nextPoint = getLocation(nextModel, nextD2d); |
| if (nextPoint == null) { |
| throw new IllegalStateException( |
| "Can't extract location: modelBP: " + nextModel |
| + ", d2dBP: " + nextD2d); |
| } |
| result.addPoint(nextPoint); |
| } |
| return result; |
| } |
| |
| protected static org.eclipse.draw2d.RelativeBendpoint newRelativeBendpointD2d( |
| RelativeBendpoint modelBP, Connection connection, float weight) { |
| org.eclipse.draw2d.RelativeBendpoint rbp = new org.eclipse.draw2d.RelativeBendpoint( |
| connection); |
| rbp.setRelativeDimensions(new Dimension(modelBP.getSourceX(), |
| modelBP.getSourceY()), // |
| new Dimension(modelBP.getTargetX(), modelBP.getTargetY())); |
| rbp.setWeight(weight); |
| return rbp; |
| } |
| |
| protected abstract Point getLocation(RelativeBendpoint modelBendpoint, |
| Object d2dbendpoint); |
| |
| } |
| |
| protected static class OnlyForNewLinks extends ConventionBase { |
| |
| @Override |
| public Bendpoint d2dBendpoint(RelativeBendpoint modelBP, |
| Connection connection, float weight) { |
| Bendpoint result = super.d2dBendpoint(modelBP, connection, weight); |
| if (result == null) { |
| result = newRelativeBendpointD2d(modelBP, connection, weight); |
| } |
| return result; |
| } |
| |
| @Override |
| public boolean hasAbsoluteStoredAsRelativeBendpoints(Edge edge) { |
| List<?> bendpoints = ((RelativeBendpoints) edge.getBendpoints()) |
| .getPoints(); |
| for (Object o : bendpoints) { |
| if (o instanceof RelativeBendpoint |
| && isAbsoluteStoredAsRelative((RelativeBendpoint) o)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| protected Point getLocation(RelativeBendpoint modelBendpoint, |
| Object d2dbendpoint) { |
| if (isAbsoluteStoredAsRelative(modelBendpoint)) { |
| return new Point(modelBendpoint.getSourceX(), |
| modelBendpoint.getSourceY()); |
| } |
| if (d2dbendpoint instanceof Bendpoint) { |
| return ((Bendpoint) d2dbendpoint).getLocation(); |
| } |
| return null; |
| } |
| |
| } |
| |
| protected static class ForAllLinks extends ConventionBase { |
| |
| @Override |
| public Bendpoint d2dBendpoint(RelativeBendpoint modelBP, |
| Connection connection, float weight) { |
| Bendpoint result = super.d2dBendpoint(modelBP, connection, weight); |
| if (result == null) { |
| org.eclipse.draw2d.RelativeBendpoint rbp = newRelativeBendpointD2d( |
| modelBP, connection, weight); |
| // if(connection.getSourceAnchor() != null && |
| // connection.getTargetAnchor() != null) { |
| result = new RelativeBendpointWrapper(rbp, connection); |
| // } |
| } |
| return result; |
| } |
| |
| @Override |
| public boolean hasAbsoluteStoredAsRelativeBendpoints(Edge edge) { |
| List<?> bendpoints = ((RelativeBendpoints) edge.getBendpoints()) |
| .getPoints(); |
| return !bendpoints.isEmpty(); |
| } |
| |
| @Override |
| protected Point getLocation(RelativeBendpoint modelBendpoint, |
| Object d2dBendpoint) { |
| if (isAbsoluteStoredAsRelative(modelBendpoint)) { |
| return new Point(modelBendpoint.getSourceX(), |
| modelBendpoint.getSourceY()); |
| } |
| if (d2dBendpoint instanceof AbsoluteBendpoint) { |
| AbsoluteBendpoint wrapper = (AbsoluteBendpoint) d2dBendpoint; |
| return wrapper.getLocation(); |
| } |
| throw new IllegalStateException( |
| "I had to create AbsoluteBendpointWrapper for this: " |
| + modelBendpoint + ", " + d2dBendpoint); |
| } |
| |
| /** |
| * Provides implicit migration of the diagrams created before the |
| * LinksLF. |
| * <p/> |
| * Idea is to create the same "absolute" bendpoints for the old relative |
| * bendpoints created with previous version, and only update the |
| * persistence on the first modification of the link. |
| * <p/> |
| * However, positions of the {@link RelativeBendpoint} depends on the |
| * anchors and, more generally on the bounds of link ends, so they can't |
| * be computed immediately at the time of creation. This class |
| * introduced the deferred replacement, that is, once the |
| * {@link RelativeBendpoint} can compute its positions, their |
| * coordinates are saved and don't depend on the source or target |
| * anchors anymore. |
| */ |
| @SuppressWarnings("serial") |
| private static class RelativeBendpointWrapper extends AbsoluteBendpoint { |
| |
| private Point myLocation = null; |
| |
| private org.eclipse.draw2d.RelativeBendpoint myRelativeBendpoint; |
| |
| private Connection myConnection; |
| |
| /** |
| * Wraps the {@link RelativeBendpoint} and defers computation of its |
| * positions until it is ready. |
| * |
| * @param relativeBendpoint |
| * @param conn |
| */ |
| public RelativeBendpointWrapper( |
| org.eclipse.draw2d.RelativeBendpoint relativeBendpoint, |
| Connection conn) { |
| super(new Point()); |
| myRelativeBendpoint = relativeBendpoint; |
| myConnection = conn; |
| } |
| |
| @Override |
| public Point getLocation() { |
| if (myLocation == null && isReadyToComputeLocation()) { |
| myLocation = new Point(myRelativeBendpoint.getLocation()); |
| myRelativeBendpoint = null; |
| myConnection = null; |
| } |
| return myLocation != null ? myLocation : myRelativeBendpoint |
| .getLocation(); |
| } |
| |
| private boolean isReadyToComputeLocation() { |
| if (myConnection == null) { |
| return false; |
| } |
| ConnectionAnchor source = myConnection.getSourceAnchor(); |
| ConnectionAnchor target = myConnection.getTargetAnchor(); |
| if (source == null || target == null) { |
| return false; |
| } |
| return hasLocation(source.getReferencePoint()) |
| && hasLocation(target.getReferencePoint()); |
| } |
| |
| private boolean hasLocation(Point point) { |
| return point != null && (point.x() != 0 || point.y() != 0); |
| } |
| |
| @Override |
| public int x() { |
| return getLocation().x(); |
| } |
| |
| @Override |
| public int y() { |
| return getLocation().y(); |
| } |
| } |
| } |
| } |