blob: 1101a86690aa59766ad732f4784298b0ef343e66 [file] [log] [blame]
/*******************************************************************************
* <copyright>
*
* Copyright (c) 2005, 2013 SAP AG.
* 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:
* SAP AG - initial API, implementation and documentation
* mwenz - Bug 415884 - Cannot query size of a multi-line text
*
* </copyright>
*
*******************************************************************************/
package org.eclipse.graphiti.ui.internal.services.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.draw2d.ExclusionSearch;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.TextUtilities;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.graphiti.datatypes.IDimension;
import org.eclipse.graphiti.datatypes.ILocation;
import org.eclipse.graphiti.internal.datatypes.impl.DimensionImpl;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.styles.Font;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.AnchorContainer;
import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator;
import org.eclipse.graphiti.mm.pictograms.FreeFormConnection;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.ILayoutService;
import org.eclipse.graphiti.ui.internal.services.IGefService;
import org.eclipse.graphiti.ui.internal.util.DataTypeTransformation;
import org.eclipse.graphiti.ui.internal.util.gef.ScalableRootEditPartAnimated;
/**
* A collection of static helper methods regarding GEF.
*
* @noinstantiate This class is not intended to be instantiated by clients.
* @noextend This class is not intended to be subclassed by clients.
*/
public class GefService implements IGefService {
protected static final String PE = "*PE* "; //$NON-NLS-1$
public void selectEditPart(EditPartViewer viewer, Object modelObject) {
if (modelObject == null)
return;
viewer.getControl().forceFocus();
Object editpart = viewer.getEditPartRegistry().get(modelObject);
if (editpart instanceof EditPart) {
viewer.flush();
viewer.select((EditPart) editpart);
}
}
public Point calculateTranslation(EditPart source, EditPart target) {
if (!(source instanceof GraphicalEditPart && target instanceof GraphicalEditPart))
throw new RuntimeException("Both EditParts must be an instance of GraphicalEditPart: " + source + " " + target); //$NON-NLS-1$ //$NON-NLS-2$
Point result = new Point(0, 0);
if (source == target) // quick-check
return result;
((GraphicalEditPart) source).getContentPane().translateToAbsolute(result);
((GraphicalEditPart) target).getContentPane().translateToRelative(result);
return result;
}
public Object getLayoutConstraint(EditPart editPart) {
if (editPart instanceof GraphicalEditPart) {
IFigure childFigure = ((GraphicalEditPart) editPart).getFigure();
if (childFigure.getParent() != null && childFigure.getParent().getLayoutManager() != null) { // should
// always be
// true
// ask the parent for the current constraints
Object constraint = childFigure.getParent().getLayoutManager().getConstraint(childFigure);
return constraint;
}
}
return null;
}
public EditPart findEditPartAt(EditPartViewer viewer, Point location, boolean includeConnections) {
EditPart editPart = findObjectAt(viewer, location, includeConnections);
if (editPart instanceof ScalableRootEditPartAnimated) {
List<EditPart> children = getEditPartChildren(editPart);
if (children.size() > 0) {
editPart = children.get(0);
}
}
return editPart;
}
private EditPart findObjectAt(final EditPartViewer viewer, Point pt, boolean includeConnections) {
class ConditionalTreeSearch extends ExclusionSearch {
ConditionalTreeSearch(Collection<?> coll) {
super(coll);
}
@Override
public boolean accept(IFigure figure) {
EditPart editpart = null;
while (editpart == null && figure != null) {
editpart = (EditPart) viewer.getVisualPartMap().get(figure);
figure = figure.getParent();
}
return editpart != null;
}
}
ScalableFreeformRootEditPart rootEditPart = (ScalableFreeformRootEditPart) viewer.getRootEditPart();
IFigure figure = null;
if (includeConnections) {
IFigure connectionLayer = rootEditPart.getLayer(LayerConstants.CONNECTION_LAYER);
figure = connectionLayer.findFigureAt(pt.x, pt.y, new ConditionalTreeSearch(Collections.EMPTY_LIST));
}
// if figure not searched or not found on connection layer try to find a
// figure on the primary layer
if (figure == null) {
IFigure primaryLayer = rootEditPart.getLayer(LayerConstants.PRIMARY_LAYER);
figure = primaryLayer.findFigureAt(pt.x, pt.y, new ConditionalTreeSearch(Collections.EMPTY_LIST));
}
EditPart part = null;
while (part == null && figure != null) {
part = (EditPart) viewer.getVisualPartMap().get(figure);
figure = figure.getParent();
}
if (part == null)
return viewer.getContents();
return part;
}
public List<EditPart> getConnectionsContainedInEditPart(EditPart ep) {
// Compute connections whose start and target are somewhere in the
// editpart sub hierarchy of ep
List<EditPart> childEditParts = getAllEditPartChildren(ep);
List<Connection> sourceConnections = new ArrayList<Connection>();
List<Connection> targetConnections = new ArrayList<Connection>();
for (EditPart cep : childEditParts) {
if (cep.getModel() instanceof AnchorContainer) {
AnchorContainer anchorContainer = (AnchorContainer) cep.getModel();
EList<Anchor> anchors = anchorContainer.getAnchors();
for (Anchor anchor : anchors) {
sourceConnections.addAll(anchor.getIncomingConnections());
targetConnections.addAll(anchor.getOutgoingConnections());
}
}
}
sourceConnections.retainAll(targetConnections);
// Extract edit parts and decorators from the connections
List<EditPart> result = new ArrayList<EditPart>();
for (Connection connection : sourceConnections) {
Object connectionEditPart = ep.getRoot().getViewer().getEditPartRegistry().get(connection);
result.add((EditPart) connectionEditPart);
EList<ConnectionDecorator> connectionDecorators = connection.getConnectionDecorators();
for (ConnectionDecorator decorator : connectionDecorators) {
Object decoratorEditPart = ep.getRoot().getViewer().getEditPartRegistry().get(decorator);
result.add((EditPart) decoratorEditPart);
}
}
return result;
}
private List<EditPart> getAllEditPartChildren(EditPart ep) {
List<EditPart> res = new ArrayList<EditPart>();
List<EditPart> children = getEditPartChildren(ep);
for (EditPart editPart : children) {
res.add(editPart);
res.addAll(getAllEditPartChildren(editPart));
}
return res;
}
public Point getConnectionPointAt(Connection c, double d) {
Point ret = null;
Anchor startAnchor = c.getStart();
final ILayoutService layoutService = Graphiti.getLayoutService();
ILocation startLocation = layoutService.getLocationRelativeToDiagram(startAnchor);
Point startPoint = new Point(startLocation.getX(), startLocation.getY());
Anchor endAnchor = c.getEnd();
ILocation endLocation = layoutService.getLocationRelativeToDiagram(endAnchor);
Point endPoint = new Point(endLocation.getX(), endLocation.getY());
// special solutions for chopbox anchors
if (startAnchor instanceof ChopboxAnchor || endAnchor instanceof ChopboxAnchor) {
if (startAnchor instanceof ChopboxAnchor) {
ChopboxAnchor cbStartAnchor = (ChopboxAnchor) startAnchor;
GraphicsAlgorithm parentGa = cbStartAnchor.getParent().getGraphicsAlgorithm();
Shape shape = (Shape) cbStartAnchor.getParent();
ILocation location = layoutService.getLocationRelativeToDiagram(shape);
Rectangle parentRect = new Rectangle(location.getX(), location.getY(), parentGa.getWidth(), parentGa.getHeight());
Point pointNextToStartAnchor = endPoint.getCopy();
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
if (!bendpoints.isEmpty()) {
org.eclipse.graphiti.mm.algorithms.styles.Point firstBendpoint = bendpoints.get(0);
pointNextToStartAnchor.setLocation(firstBendpoint.getX(), firstBendpoint.getY());
}
}
Point chopboxLocationOnBox = getChopboxLocationOnBox(pointNextToStartAnchor, parentRect);
startPoint.setLocation(chopboxLocationOnBox);
}
if (endAnchor instanceof ChopboxAnchor) {
ChopboxAnchor cbEndAnchor = (ChopboxAnchor) endAnchor;
GraphicsAlgorithm parentGa = cbEndAnchor.getParent().getGraphicsAlgorithm();
Shape shape = (Shape) cbEndAnchor.getParent();
ILocation location = layoutService.getLocationRelativeToDiagram(shape);
Rectangle parentRect = new Rectangle(location.getX(), location.getY(), parentGa.getWidth(), parentGa.getHeight());
Point pointNextToEndAnchor = startPoint.getCopy();
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
if (!bendpoints.isEmpty()) {
org.eclipse.graphiti.mm.algorithms.styles.Point lastBendpoint = bendpoints.get(bendpoints.size() - 1);
pointNextToEndAnchor.setLocation(lastBendpoint.getX(), lastBendpoint.getY());
}
}
Point chopboxLocationOnBox = getChopboxLocationOnBox(pointNextToEndAnchor, parentRect);
endPoint.setLocation(chopboxLocationOnBox);
}
}
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
Point[] draw2dPoints = new Point[bendpoints.size() + 2];
{
draw2dPoints[0] = startPoint;
int i = 1;
for (org.eclipse.graphiti.mm.algorithms.styles.Point pictogramsPoint : bendpoints) {
draw2dPoints[i] = new Point(pictogramsPoint.getX(), pictogramsPoint.getY());
i++;
}
draw2dPoints[i] = endPoint;
}
double completeDistance = getDistance(draw2dPoints);
double absDistanceToRelPoint = completeDistance * d;
double distanceSum = 0;
for (int i = 0; i < draw2dPoints.length - 1; i++) {
double oldDistanceSum = distanceSum;
Point currentPoint = draw2dPoints[i];
Point nextPoint = draw2dPoints[i + 1];
// no need to check both points
// actually this would lead to division-by-zero in the following
// calculation
if (currentPoint.equals(nextPoint))
continue;
double additionalDistanceToNext = getDistance(currentPoint, nextPoint);
distanceSum += additionalDistanceToNext;
if (distanceSum >= absDistanceToRelPoint) {
double thisRelative = ((completeDistance * d) - oldDistanceSum) / additionalDistanceToNext;
ret = getPointAt(currentPoint, nextPoint, thisRelative);
break; // or return ret;
}
}
} else {
ret = getPointAt(startPoint.x, startPoint.y, endPoint.x, endPoint.y, d);
}
return ret;
}
public Point getChopboxLocationOnBox(Point reference, Rectangle box) {
Rectangle r = Rectangle.SINGLETON;
r.setBounds(box);
r.translate(-1, -1);
r.resize(1, 1);
// getOwner().translateToAbsolute(r);
float centerX = r.x + 0.5f * r.width;
float centerY = r.y + 0.5f * r.height;
// CHANGED: returning the center in case of a divide-by-zero is not a
// good result
// if (r.isEmpty() || (reference.x == (int)centerX && reference.y ==
// (int)centerY))
// return new Point((int)centerX, (int)centerY); //This avoids
// divide-by-zero
float dx = reference.x - centerX;
float dy = reference.y - centerY;
// r.width, r.height, dx, and dy are guaranteed to be non-zero.
// CHANGED: in case of "nearly zero" (divide-by-zero or
// rounding-problems) would happen.
// Instead return a point on the border of the figure.
// Doesn't matter which one, because it is directly in the center, so
// take top-middle.
float max = Math.max(Math.abs(dx) / r.width, Math.abs(dy) / r.height);
if (max <= 0.001f) {
return new Point((int) centerX, r.y);
}
float scale = 0.5f / max;
dx *= scale;
dy *= scale;
centerX += dx;
centerY += dy;
return new Point(Math.round(centerX), Math.round(centerY));
}
public Point getAbsolutePointOnConnection(Connection c, double distance) {
Point ret = null;
Anchor startAnchor = c.getStart();
ILocation startLocation = Graphiti.getLayoutService().getLocationRelativeToDiagram(startAnchor);
Point startPoint = new Point(startLocation.getX(), startLocation.getY());
Anchor endAnchor = c.getEnd();
ILocation endLocation = Graphiti.getLayoutService().getLocationRelativeToDiagram(endAnchor);
Point endPoint = new Point(endLocation.getX(), endLocation.getY());
// special solutions for chopbox anchors
if (startAnchor instanceof ChopboxAnchor || endAnchor instanceof ChopboxAnchor) {
if (startAnchor instanceof ChopboxAnchor) {
ChopboxAnchor cbStartAnchor = (ChopboxAnchor) startAnchor;
GraphicsAlgorithm parentGa = cbStartAnchor.getParent().getGraphicsAlgorithm();
Rectangle parentRect = new Rectangle(parentGa.getX(), parentGa.getY(), parentGa.getWidth(), parentGa.getHeight());
Point pointNextToStartAnchor = endPoint.getCopy();
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
if (!bendpoints.isEmpty()) {
org.eclipse.graphiti.mm.algorithms.styles.Point firstBendpoint = bendpoints.get(0);
pointNextToStartAnchor.setLocation(firstBendpoint.getX(), firstBendpoint.getY());
}
}
Point chopboxLocationOnBox = getChopboxLocationOnBox(pointNextToStartAnchor, parentRect);
startPoint.setLocation(chopboxLocationOnBox);
}
if (endAnchor instanceof ChopboxAnchor) {
ChopboxAnchor cbEndAnchor = (ChopboxAnchor) endAnchor;
GraphicsAlgorithm parentGa = cbEndAnchor.getParent().getGraphicsAlgorithm();
Rectangle parentRect = new Rectangle(parentGa.getX(), parentGa.getY(), parentGa.getWidth(), parentGa.getHeight());
Point pointNextToEndAnchor = startPoint.getCopy();
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
if (!bendpoints.isEmpty()) {
org.eclipse.graphiti.mm.algorithms.styles.Point lastBendpoint = bendpoints.get(bendpoints.size() - 1);
pointNextToEndAnchor.setLocation(lastBendpoint.getX(), lastBendpoint.getY());
}
}
Point chopboxLocationOnBox = getChopboxLocationOnBox(pointNextToEndAnchor, parentRect);
endPoint.setLocation(chopboxLocationOnBox);
}
}
if (c instanceof FreeFormConnection) {
FreeFormConnection ffc = (FreeFormConnection) c;
List<org.eclipse.graphiti.mm.algorithms.styles.Point> bendpoints = ffc.getBendpoints();
Point[] draw2dPoints = new Point[bendpoints.size() + 2];
{
draw2dPoints[0] = startPoint;
int i = 1;
for (org.eclipse.graphiti.mm.algorithms.styles.Point pictogramsPoint : bendpoints) {
draw2dPoints[i] = new Point(pictogramsPoint.getX(), pictogramsPoint.getY());
i++;
}
draw2dPoints[i] = endPoint;
}
if (distance < 0) {
// mirror the array
mirrorArray(draw2dPoints);
}
double absDistance = Math.abs(distance);
double distanceSum = 0;
for (int i = 0; i < draw2dPoints.length - 1; i++) {
Point currentPoint = draw2dPoints[i];
Point nextPoint = draw2dPoints[i + 1];
double additionalDistanceToNext = getDistance(currentPoint, nextPoint);
distanceSum += additionalDistanceToNext;
if (distanceSum >= absDistance) {
// double thisDistance = (distance - oldDistanceSum) /
// additionalDistanceToNext;
// ret = getMidpoint(currentPoint, nextPoint, thisDistance);
ret = getDistantPoint(currentPoint, nextPoint, absDistance);
break; // or return ret;
}
}
} else {
ret = getDistantPoint(startLocation.getX(), startLocation.getY(), endLocation.getX(), endLocation.getY(), distance);
}
if (ret == null) {
ret = startPoint;
}
return ret;
}
public Point getDistantPoint(Point start, Point end, double distance) {
Point ret = getDistantPoint(start.x, start.y, end.x, end.y, distance);
return ret;
}
public Point getDistantPoint(int startX, int startY, int endX, int endY, double distance) {
Point ret;
double completeDistance = Math.sqrt(((endX - startX) * (endX - startX)) + ((endY - startY) * (endY - startY)));
double relative;
if (distance >= 0) {
relative = (distance > completeDistance) ? 1 : distance / completeDistance;
ret = getPointAt(startX, startY, endX, endY, relative);
} else {
relative = (-distance > completeDistance) ? 0 : 1 - (distance / completeDistance);
ret = getPointAt(startX, startY, endX, endY, relative);
}
return ret;
}
public Point getPointAt(int startX, int startY, int endX, int endY, double d) {
Point ret;
int midX = (int) Math.round((startX + d * (endX - startX)));
int midY = (int) Math.round((startY + d * (endY - startY)));
ret = new Point(midX, midY);
return ret;
}
public Point getPointAt(Point start, Point end, double d) {
Point ret = getPointAt(start.x, start.y, end.x, end.y, d);
return ret;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.graphiti.ui.internal.util.gef.IGefService#getDistance(org
* .eclipse.draw2d.geometry.Point[])
*/
public double getDistance(Point[] points) {
double ret = 0;
for (int i = 0; i < points.length - 1; i++) {
Point currentPoint = points[i];
Point nextPoint = points[i + 1];
ret += getDistance(currentPoint, nextPoint);
}
return ret;
}
private double getDistance(Point start, Point end) {
int xDist = end.x - start.x;
int yDist = end.y - start.y;
double ret = Math.sqrt((xDist * xDist) + (yDist * yDist));
return ret;
}
public IDimension calculateTextSize(String text, Font font) {
return calculateTextSize(text, font, false);
}
public IDimension calculateTextSize(String text, Font font, boolean handleMultiline) {
IDimension dimension = null;
if (text == null || font == null || font.getName() == null) {
return dimension;
}
org.eclipse.swt.graphics.Font swtFont = DataTypeTransformation.toSwtFont(font);
if (swtFont != null) {
Dimension se;
if (handleMultiline) {
se = TextUtilities.INSTANCE.getTextExtents(text, swtFont);
} else {
se = TextUtilities.INSTANCE.getStringExtents(text, swtFont);
}
if (se != null) {
dimension = new DimensionImpl(se.width, se.height);
}
if (!swtFont.isDisposed()) {
swtFont.dispose();
}
}
return dimension;
}
public void mirrorArray(Point[] draw2dPoints) {
int length = draw2dPoints.length;
for (int i = 0; i < length / 2; i++) {
Point pTemp = draw2dPoints[length - 1 - i];
draw2dPoints[length - 1 - i] = draw2dPoints[i];
draw2dPoints[i] = pTemp;
}
}
public List<EditPart> getEditPartChildren(EditPart editPart) {
@SuppressWarnings("unchecked")
List<EditPart> ret = editPart.getChildren();
return ret;
}
public List<GraphicalEditPart> getSourceConnections(GraphicalEditPart graphicalEditPart) {
@SuppressWarnings("unchecked")
List<GraphicalEditPart> sourceConnections = graphicalEditPart.getSourceConnections();
return sourceConnections;
}
public List<GraphicalEditPart> getTargetConnections(GraphicalEditPart graphicalEditPart) {
@SuppressWarnings("unchecked")
List<GraphicalEditPart> targetConnections = graphicalEditPart.getTargetConnections();
return targetConnections;
}
public List<EditPart> getSelectedEditParts(EditPartViewer editPartViewer) {
@SuppressWarnings("unchecked")
List<EditPart> selectedEditParts = editPartViewer.getSelectedEditParts();
return selectedEditParts;
}
}