Bug 442157 LinkLF routing: provide basic super class for connection
edit-parts, allow switching LinkLF mode on and off (for safety)

Change-Id: I53fc060f70a53aa2c934e9ab0087893adf26bb43
diff --git a/plugins/org.eclipse.gmf.tooling.runtime/META-INF/MANIFEST.MF b/plugins/org.eclipse.gmf.tooling.runtime/META-INF/MANIFEST.MF
index fec0679..b78213a 100644
--- a/plugins/org.eclipse.gmf.tooling.runtime/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.gmf.tooling.runtime/META-INF/MANIFEST.MF
@@ -36,6 +36,7 @@
  org.eclipse.gmf.tooling.runtime.edit.policies.labels,
  org.eclipse.gmf.tooling.runtime.edit.policies.reparent,
  org.eclipse.gmf.tooling.runtime.linklf,
+ org.eclipse.gmf.tooling.runtime.linklf.editparts,
  org.eclipse.gmf.tooling.runtime.linklf.labels,
  org.eclipse.gmf.tooling.runtime.linklf.policies,
  org.eclipse.gmf.tooling.runtime.linklf.router,
diff --git a/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/LinkLFConnectionNodeEditPart.java b/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/LinkLFConnectionNodeEditPart.java
new file mode 100644
index 0000000..79764d5
--- /dev/null
+++ b/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/LinkLFConnectionNodeEditPart.java
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * 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.editparts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.draw2d.Bendpoint;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ForestRouter;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.OrthogonalRouter;
+import org.eclipse.gmf.runtime.gef.ui.internal.editpolicies.LineMode;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+import org.eclipse.gmf.tooling.runtime.linklf.AbsoluteBendpointsConvention;
+import org.eclipse.gmf.tooling.runtime.linklf.policies.LinksLFConnectionBendpointEditPolicy;
+import org.eclipse.gmf.tooling.runtime.linklf.policies.LinksLFConnectionEndPointEditPolicy;
+
+/**
+ * This is a base class for LinkLF connection edit parts which allows to switch
+ * LinkLF mode on / off. When the LinkLF is switched off, the link should behave
+ * exactly like default GMF Runtime {@link ConnectionNodeEditPart}.
+ * <p/>
+ * 
+ * @since 3.3
+ */
+public abstract class LinkLFConnectionNodeEditPart extends
+		OverridableConnectionNodeEditPart {
+
+	private boolean myLinkLFEnabled;
+	private EditPolicy myOriginalEndPointsEditPolicy;
+
+	public LinkLFConnectionNodeEditPart(View view) {
+		super(view);
+	}
+
+	public void setLinkLFEnabled(boolean enabled) {
+		if (enabled != myLinkLFEnabled) {
+			myLinkLFEnabled = enabled;
+			refreshRouterChange();
+			refreshEndPointsEditPolicy();
+		}
+	}
+
+	/**
+	 * Called when LinkLF-mode for the link is changed. It is expected to happen
+	 * at max once in the link lifetime.
+	 */
+	protected void refreshEndPointsEditPolicy() {
+		if (myOriginalEndPointsEditPolicy == null) {
+			myOriginalEndPointsEditPolicy = getEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE);
+		}
+
+		EditPolicy endPoints = myLinkLFEnabled ? createEndPointsEditPolicy()
+				: myOriginalEndPointsEditPolicy;
+		installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE, endPoints);
+	}
+
+	/**
+	 * Allows subclasses to redefine an edit policy for
+	 * {@link EditPolicy#CONNECTION_ENDPOINTS_ROLE} role.
+	 */
+	protected EditPolicy createEndPointsEditPolicy() {
+		// return new DebugShowConnectionEndPointsAndAnchorsEditPolicy();
+		return new LinksLFConnectionEndPointEditPolicy();
+	}
+
+	@Override
+	protected void refreshBendpoints() {
+		if (!myLinkLFEnabled) {
+			super.refreshBendpoints();
+			return;
+		}
+
+		RelativeBendpoints bendpoints = (RelativeBendpoints) getEdge()
+				.getBendpoints();
+		List<?> modelConstraint = bendpoints.getPoints();
+		List<Bendpoint> figureConstraint = new ArrayList<Bendpoint>();
+		for (int i = 0; i < modelConstraint.size(); i++) {
+			RelativeBendpoint wbp = (RelativeBendpoint) modelConstraint.get(i);
+			float weight;
+			if (modelConstraint.size() == 1) {
+				weight = 0.5f;
+			} else {
+				weight = i / ((float) modelConstraint.size() - 1);
+			}
+			Bendpoint bp = AbsoluteBendpointsConvention.getInstance()
+					.d2dBendpoint(wbp, getConnectionFigure(), weight);
+			figureConstraint.add(bp);
+		}
+		getConnectionFigure().setRoutingConstraint(figureConstraint);
+	}
+
+	/**
+	 * When in the LinkLF mode, installs LinkLF-versions of the corresponding
+	 * {@link EditPolicy#CONNECTION_BENDPOINTS_ROLE} edit policy.
+	 */
+	protected final void installBendpointEditPolicy() {
+		if (!myLinkLFEnabled) {
+			super.installBendpointEditPolicy();
+			return;
+		}
+
+		if (getConnectionFigure().getConnectionRouter() instanceof ForestRouter) {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new LinksLFConnectionBendpointEditPolicy(
+							LineMode.ORTHOGONAL_CONSTRAINED));
+		} else if (getConnectionFigure().getConnectionRouter() instanceof OrthogonalRouter) {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new LinksLFConnectionBendpointEditPolicy(
+							LineMode.ORTHOGONAL_FREE));
+		} else {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new LinksLFConnectionBendpointEditPolicy(LineMode.OBLIQUE));
+		}
+		refreshConnectionCursor();
+	}
+
+}
diff --git a/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/OverridableConnectionNodeEditPart.java b/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/OverridableConnectionNodeEditPart.java
new file mode 100644
index 0000000..f45c8a3
--- /dev/null
+++ b/plugins/org.eclipse.gmf.tooling.runtime/src/org/eclipse/gmf/tooling/runtime/linklf/editparts/OverridableConnectionNodeEditPart.java
@@ -0,0 +1,125 @@
+package org.eclipse.gmf.tooling.runtime.linklf.editparts;
+
+import org.eclipse.draw2d.Connection;
+import org.eclipse.gef.EditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionNodeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.internal.editpolicies.ConnectionLineSegEditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.internal.editpolicies.TreeConnectionBendpointEditPolicy;
+import org.eclipse.gmf.runtime.diagram.ui.util.EditPartUtil;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.PolylineConnectionEx;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.ForestRouter;
+import org.eclipse.gmf.runtime.draw2d.ui.internal.routers.OrthogonalRouter;
+import org.eclipse.gmf.runtime.gef.ui.internal.l10n.Cursors;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.RoutingStyle;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * This class is a workaround for a bunch of private methods dealing with the
+ * default edit policies for the {@link ConnectionNodeEditPart}
+ * <p/>
+ * This class is expected to become obsolete and removed in the Mars+1 release,
+ * once the corresponding methods made protected in the super-class
+ * <p/>
+ * [GMFR make protected]
+ * 
+ * @see OverridableConnectionNodeEditPart#installBendpointEditPolicy()
+ * @since 3.3
+ */
+public abstract class OverridableConnectionNodeEditPart extends ConnectionNodeEditPart {
+
+	public OverridableConnectionNodeEditPart(View view) {
+		super(view);
+	}
+
+	/**
+	 * This method is private in {@link ConnectionEditPart} while being called
+	 * from the methods which have to be overridden in the LinkLF framework.
+	 * <p/>
+	 * This class does NOT change the logic from the super class, it only allows
+	 * to override it in subclasses
+	 */
+	protected void installBendpointEditPolicy() {
+		if (getConnectionFigure().getConnectionRouter() instanceof ForestRouter) {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new TreeConnectionBendpointEditPolicy());
+		} else if (getConnectionFigure().getConnectionRouter() instanceof OrthogonalRouter) {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new ConnectionLineSegEditPolicy());
+		} else {
+			installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE,
+					new ConnectionBendpointEditPolicy());
+		}
+		refreshConnectionCursor();
+	}
+
+	/**
+	 * This method is part of the private
+	 * {@link ConnectionEditPart#installBendpointEditPolicy}, extracted to
+	 * simplify the overriding code in the sub-classes.
+	 * 
+	 * @see OverridableConnectionNodeEditPart#installBendpointEditPolicy()
+	 */
+	protected void refreshConnectionCursor() {
+		EditPartUtil.synchronizeRunnableToMainThread(this, new Runnable() {
+
+			public void run() {
+				if (getConnectionFigure().getConnectionRouter() instanceof ForestRouter) {
+					getConnectionFigure().setCursor(Cursors.CURSOR_SEG_MOVE);
+				} else if (getConnectionFigure().getConnectionRouter() instanceof OrthogonalRouter) {
+					getConnectionFigure().setCursor(Cursors.CURSOR_SEG_MOVE);
+				} else {
+					getConnectionFigure().setCursor(Cursors.CURSOR_SEG_ADD);
+				}
+			};
+		});
+	}
+
+	/**
+	 * This method is copy-pasted from In contrast to super-class, this code
+	 * calls the local version of {@link #installBendpointEditPolicy()} which
+	 * can be overridden in sub-class
+	 */
+	@Override
+	protected void refreshRouterChange() {
+		refreshBendpoints();
+		installBendpointEditPolicy();
+	}
+
+	/**
+	 * This method is copy-pasted from the
+	 * {@link ConnectionEditPart#refreshRoutingStyles}.
+	 * <p/>
+	 * In contrast to super-class, this code calls the local version of
+	 * {@link #installBendpointEditPolicy()} which can be overridden in
+	 * sub-class.
+	 */
+	@Override
+	protected void refreshRoutingStyles() {
+		Connection connection = getConnectionFigure();
+		if (!(connection instanceof PolylineConnectionEx)) {
+			return;
+		}
+
+		PolylineConnectionEx poly = (PolylineConnectionEx) connection;
+
+		RoutingStyle style = (RoutingStyle) ((View) getModel())
+				.getStyle(NotationPackage.Literals.ROUTING_STYLE);
+		if (style != null) {
+
+			boolean closestDistance = style.isClosestDistance();
+			boolean avoidObstruction = style.isAvoidObstructions();
+
+			poly.setRoutingStyles(closestDistance, avoidObstruction);
+
+			if (avoidObstruction) {
+				installEditPolicy(EditPolicy.CONNECTION_BENDPOINTS_ROLE, null);
+			} else {
+				installBendpointEditPolicy();
+			}
+		}
+	}
+
+}