/***************************************************************************** * 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 org.eclipse.draw2d.AbstractPointListShape; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.ScalablePolygonShape; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.PointList; import org.eclipse.draw2d.geometry.PrecisionPoint; import org.eclipse.gef.EditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart; import org.eclipse.gmf.runtime.diagram.ui.editparts.IBorderItemEditPart; import org.eclipse.gmf.runtime.draw2d.ui.figures.BaseSlidableAnchor; import org.eclipse.gmf.runtime.draw2d.ui.figures.IBorderItemLocator; import org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure; import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor; /** * Extends {@link DefaultSizeNodeFigure} with ability to create custom * {@link SlidableAnchor} which are snapped to grid. * <p/> * * @since 3.3 */ public class LinkLFNodeFigure extends DefaultSizeNodeFigure { protected static final double AVOID_DEFAULT_ANCHOR_AREA = 1.0; private final GraphicalEditPart myHost; public LinkLFNodeFigure(GraphicalEditPart hostEP, int width, int height) { super(width, height); myHost = hostEP; } @Override protected ConnectionAnchor createAnchor(PrecisionPoint p) { if (p == null) { // If the old terminal for the connection anchor cannot be resolved // (by SlidableAnchor) a null // PrecisionPoint will passed in - this is handled here return createDefaultAnchor(); } SlidableSnapToGridAnchor result = new SlidableSnapToGridAnchor(this, p); result.setEditPartViewer(myHost.getViewer()); return result; } @Override public ConnectionAnchor getSourceConnectionAnchorAt(Point p) { return super.getSourceConnectionAnchorAt(p); } @Override public ConnectionAnchor getTargetConnectionAnchorAt(Point p) { return super.getTargetConnectionAnchorAt(p); } @Override protected double getSlidableAnchorArea() { return AVOID_DEFAULT_ANCHOR_AREA; } protected ConnectionAnchor createConnectionAnchor(Point p) { if (p == null) { return getConnectionAnchor(szAnchor); } else { Point temp = p.getCopy(); translateToRelative(temp); PrecisionPoint pt = BaseSlidableAnchor.getAnchorRelativeLocation( temp, getBounds()); if (isDefaultAnchorArea(pt)) { return getConnectionAnchor(szAnchor); } forceSideForBorderItemAnchorLocation(myHost, pt); return createAnchor(pt); } } @Override public PointList getPolygonPoints() { if (getChildren().size() == 1) { IFigure primaryShape = (IFigure) getChildren().get(0); if (primaryShape instanceof ScalablePolygonShape) { ScalablePolygonShape scalable = (ScalablePolygonShape) primaryShape; PointList result = scalable.getScaledPoints().getCopy(); result.translate(scalable.getLocation()); return result; } if (primaryShape instanceof AbstractPointListShape) { return ((AbstractPointListShape) primaryShape).getPoints() .getCopy(); } } return super.getPolygonPoints(); } /** * Utility method which, in case if the host editpart is * {@link IBorderItemEditPart} resets the anchor location to the side * parallel to the parent side this affixed item is attached to. */ public static void forceSideForBorderItemAnchorLocation(EditPart hostEP, PrecisionPoint pt) { if (hostEP instanceof IBorderItemEditPart) { IBorderItemLocator locator = ((IBorderItemEditPart) hostEP) .getBorderItemLocator(); switch (locator.getCurrentSideOfParent()) { case PositionConstants.WEST: case PositionConstants.EAST: pt.setPreciseX(pt.preciseX() > 0.5 ? 1.0 : 0.0); break; case PositionConstants.SOUTH: case PositionConstants.NORTH: pt.setPreciseY(pt.preciseY() > 0.5 ? 1.0 : 0.0); break; } } } }