blob: 9755f286df92a85eeb3f8171e11408ac2256df9a [file] [log] [blame]
package org.eclipse.bpmn2.modeler.core.features;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.eclipse.bpmn2.modeler.core.features.RouteSolver.Aisle.Adjacence;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.graphiti.datatypes.IDimension;
import org.eclipse.graphiti.datatypes.ILocation;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.IAddConnectionContext;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.impl.AddConnectionContext;
import org.eclipse.graphiti.features.context.impl.AddContext;
import org.eclipse.graphiti.features.context.impl.DeleteContext;
import org.eclipse.graphiti.features.impl.AbstractAddShapeFeature;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.algorithms.RoundedRectangle;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.FixPointAnchor;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.IGaService;
import org.eclipse.graphiti.services.IPeService;
import org.eclipse.graphiti.ui.features.DefaultDeleteFeature;
import org.eclipse.graphiti.util.ColorConstant;
import org.eclipse.graphiti.util.IColorConstant;
public class RouteSolver {
protected final static IGaService gaService = Graphiti.getGaService();
protected static final IPeService peService = Graphiti.getPeService();
static final int topMargin = 50;
static final int bottomMargin = 50;
static final int leftMargin = 50;
static final int rightMargin = 50;
IFeatureProvider fp;
List<ContainerShape> allShapes;
ContainerShape source;
ContainerShape target;
int top, left, bottom, right;
AisleList verticalAisles;
AisleList horizontalAisles;
private boolean rotate = false;
/**
* This class represents an "aisle" or blank space between shapes, which can
* be used to lay connection lines. Aisles are linked together in a network;
* the linkage is created when two Aisle nodes share a common left or right
* edge. See also AisleList.
*/
public static class Aisle {
protected final static AisleList EMPTY_LIST = new AisleList();
protected Rectangle rect;
protected List<Aisle> leftAdjacent;
protected List<Aisle> rightAdjacent;
public String type;
protected ContainerShape shape;
public static enum Adjacence { LEFT, TOP, BOTTOM, RIGHT, NONE };
public Aisle(String type, int x, int y, int width, int height) {
this(new Rectangle(x,y,width,height));
this.type = type;
}
public Aisle(Rectangle r) {
rect = new Rectangle(r);
}
public Adjacence adjacent(Aisle node) {
return adjacent(node.rect);
}
public Adjacence adjacent(Rectangle other) {
if (rect.y==other.bottom()) {
if (rect.right()<=other.x || other.right()<=rect.x)
return Adjacence.NONE;
return Adjacence.TOP;
}
if (rect.x==other.right()) {
if (rect.bottom()<=other.y || other.bottom()<=rect.y)
return Adjacence.NONE;
return Adjacence.LEFT;
}
if (rect.right()==other.x) {
if (rect.bottom()<=other.y || other.bottom()<=rect.y)
return Adjacence.NONE;
return Adjacence.RIGHT;
}
if (rect.bottom()==other.y) {
if (rect.right()<=other.x || other.right()<=rect.x)
return Adjacence.NONE;
return Adjacence.BOTTOM;
}
return Adjacence.NONE;
}
public void addLeft(Aisle node) {
if (leftAdjacent==null)
leftAdjacent = new ArrayList<Aisle>();
if (!leftAdjacent.contains(node))
leftAdjacent.add(node);
if (node.rightAdjacent==null)
node.rightAdjacent = new ArrayList<Aisle>();
if (!node.rightAdjacent.contains(this))
node.rightAdjacent.add(this);
}
public boolean hasLeft() {
return leftAdjacent!=null && leftAdjacent.size()>0;
}
public List<Aisle> getLeft() {
if (hasLeft())
return leftAdjacent;
return EMPTY_LIST;
}
public void addRight(Aisle node) {
if (rightAdjacent==null)
rightAdjacent = new ArrayList<Aisle>();
if (!rightAdjacent.contains(node))
rightAdjacent.add(node);
if (node.leftAdjacent==null)
node.leftAdjacent = new ArrayList<Aisle>();
if (!node.leftAdjacent.contains(this))
node.leftAdjacent.add(this);
}
public boolean hasRight() {
return rightAdjacent!=null && rightAdjacent.size()>0;
}
public List<Aisle> getRight() {
if (hasRight())
return rightAdjacent;
return EMPTY_LIST;
}
public int getX() {
return rect.x;
}
public int getY() {
return rect.y;
}
public void setX(int i) {
rect.x = i;
}
public void setY(int i) {
rect.y = i;
}
public int getWidth() {
return rect.width;
}
public int getHeight() {
return rect.height;
}
public void setWidth(int i) {
rect.width = i;
}
public void setHeight(int i) {
rect.height = i;
}
public void setShape(PictogramElement shape) {
this.shape = (ContainerShape)shape;
}
public ContainerShape getShape() {
return shape;
}
@Override
public boolean equals(Object that) {
if (that instanceof Aisle)
return this.rect.equals(((Aisle)that).rect);
return false;
}
public void rotate(boolean b) {
rotateRectangle(rect);
}
}
/**
* This class manages a network of Aisle nodes. The nodes are linked if their
* physical rectangles share an edge. Depending on the orientation in which the net was created,
* only the left/right (for a "vertical" or non-rotated net) or top/bottom (a "horizontal"
* or rotated net) edges are tested for adjacency.
*/
protected static class AisleList extends ArrayList<Aisle> {
private static final long serialVersionUID = -3041403111796385182L;
boolean isRotated = false;
ContainerShape source;
ContainerShape target;
List<Aisle> sourceAdjacentAisles = new ArrayList<Aisle>();
List<Aisle> targetAdjacentAisles = new ArrayList<Aisle>();
@Override
public boolean add(Aisle a) {
if (!contains(a) && a.getWidth()>0 && a.getHeight()>0)
return super.add(a);
return false;
}
public void link(ContainerShape source, ContainerShape target) {
this.source = source;
this.target = target;
Rectangle sourceBounds = getBounds(isRotated, source);
Rectangle targetBounds = getBounds(isRotated, target);
sourceAdjacentAisles.clear();
targetAdjacentAisles.clear();
for (Aisle a1 : this) {
for (Aisle a2 : this) {
if (a1!=a2) {
switch (a1.adjacent(a2)) {
case LEFT:
case TOP:
a1.addLeft(a2);
break;
case RIGHT:
case BOTTOM:
a1.addRight(a2);
break;
case NONE:
break;
}
}
}
if (a1.adjacent(sourceBounds) != Aisle.Adjacence.NONE) {
sourceAdjacentAisles.add(a1);
}
if (a1.adjacent(targetBounds) != Aisle.Adjacence.NONE) {
targetAdjacentAisles.add(a1);
}
}
}
public void rotate(boolean b) {
if (isRotated!=b) {
for (Aisle node : this) {
node.rotate(b);
}
isRotated = b;
}
}
public List<Aisle> getAislesAdjacentTo(ContainerShape shape, Adjacence adjacence) {
List<Aisle> adjacentAisles;
List<Aisle> list = new ArrayList<Aisle>();
if (shape==source) {
adjacentAisles = sourceAdjacentAisles;
}
else if (shape==target) {
adjacentAisles = targetAdjacentAisles;
}
else
return list;
Rectangle bounds = getBounds(isRotated, shape);
for (Aisle a : adjacentAisles) {
if (a.adjacent(bounds) == adjacence)
list.add(a);
}
return list;
}
}
/**
* RouteSolver constructor.
*
* @param fp - Graphiti Feature Provider
* @param allShapes - a list of all shapes that are considered in the routing solution.
*/
public RouteSolver(IFeatureProvider fp, List<ContainerShape> allShapes) {
this.fp = fp;
this.allShapes = new ArrayList<ContainerShape>();
this.allShapes.addAll(allShapes);
initialize();
}
protected void clear() {
Diagram diagram = fp.getDiagramTypeProvider().getDiagram();
List<ContainerShape> delete = new ArrayList<ContainerShape>();
TreeIterator iter = diagram.eAllContents();
while (iter.hasNext()) {
Object o = iter.next();
if (o instanceof ContainerShape) {
ContainerShape s = (ContainerShape)o;
if (peService.getPropertyValue(s, "CONNECTION_ROUTING_AISLE")!=null) {
delete.add(s);
}
}
}
for (ContainerShape s : delete) {
DeleteContext context = new DeleteContext(s);
DeleteAisleFeature feature = new DeleteAisleFeature(fp);
feature.delete(context);
}
}
public boolean solve(ContainerShape source, ContainerShape target) {
this.source = source;
this.target = target;
verticalAisles.link(source, target);
List<Aisle> list = verticalAisles.getAislesAdjacentTo(source, Adjacence.RIGHT);
drawAisles(verticalAisles);
drawAisleConnections(verticalAisles);
horizontalAisles.link(source, target);
drawAisles(horizontalAisles);
drawAisleConnections(horizontalAisles);
return true;
}
public boolean initialize() {
clear();
if (allShapes.size()<2)
return false;
rotate = false;
Rectangle r = calculateDiagramBounds();
sortAllShapes();
top = r.y;
left = r.x;
bottom = top + r.height;
right = left + r.width;
verticalAisles = calculateAisles();
rotate = true;
r = calculateDiagramBounds();
sortAllShapes();
top = r.y;
left = r.x;
bottom = top + r.height;
right = left + r.width;
horizontalAisles = calculateAisles();
rotate = false;
return true;
}
protected Rectangle calculateDiagramBounds() {
// find bounding rectangle that contains all shapes
int left = Integer.MAX_VALUE;
int right = Integer.MIN_VALUE;
int top = Integer.MAX_VALUE;
int bottom = Integer.MIN_VALUE;
int x, y;
for (ContainerShape s : allShapes) {
Rectangle r = getBounds(s);
x = r.x;
if (x < left)
left = x;
x = r.right();
if (x > right)
right = x;
y = r.y;
if (y < top)
top = y;
y = r.bottom();
if (y > bottom)
bottom = y;
}
left -= leftMargin;
top -= topMargin;
bottom += bottomMargin;
right += rightMargin;
return new Rectangle(left, top, right-left, bottom-top);
}
protected AisleList calculateAisles() {
AisleList aisles = new AisleList();
aisles.add(new Aisle("start", left, top, leftMargin, bottom-top));
for (int i=0; i<allShapes.size(); ++i) {
ContainerShape shape = allShapes.get(i);
if (GraphicsUtil.getDebugText(shape).contains("Task_1")) {
GraphicsUtil.debug = true;
}
else
GraphicsUtil.debug = false;
// get bounding rectangle for current shape
Rectangle shapeBounds = getBounds(shape);
// The rectangular region below the current shape will be sliced
// into smaller rectangles (a.k.a. "aisle"). To do this we'll
// create a horizontal slicer that keeps track of the location
// and width of each void defined by the top edge of the current
// shape, and the left/right edges of the shapes below it.
Slice slice = new Slice(shapeBounds.x, shapeBounds.right());
List<ContainerShape> below = getShapesBelow(shape);
for (ContainerShape shapeBelow : below) {
Rectangle shapeBelowBounds = getBounds(shapeBelow);
if (slice.remove(shapeBelowBounds.x, shapeBelowBounds.right()) == 0)
break;
}
List<Integer> cuts = slice.getCuts();
int c1 = cuts.get(0);
for (int ic=1; ic<cuts.size(); ++ic) {
int c2 = cuts.get(ic);
Aisle newAisle = new Aisle("below",c1,shapeBounds.y+shapeBounds.height,c2-c1,Integer.MIN_VALUE);
for (ContainerShape shapeBelow : below) {
Rectangle shapeBelowBounds = getBounds(shapeBelow);
if (shapeBelowBounds.x<=c1 && c1<shapeBelowBounds.right()) {
newAisle.setHeight(shapeBelowBounds.y - shapeBounds.y - shapeBounds.height);
break;
}
}
if (newAisle.getHeight()==Integer.MIN_VALUE) {
newAisle.setHeight(bottom - shapeBounds.y - shapeBounds.height);
}
aisles.add(newAisle);
c1 = c2;
}
// calculate aisle above the current shape
slice = new Slice(shapeBounds.x, shapeBounds.right());
List<ContainerShape> above = getShapesAbove(shape);
for (ContainerShape shapeAbove : above) {
Rectangle shapeAboveBounds = getBounds(shapeAbove);
if (slice.remove(shapeAboveBounds.x, shapeAboveBounds.right()) == 0)
break;
}
// Now we'll do the same thing for aisle above the current shape,
// but only those that extend all the way to the top of the diagram.
// We don't want any overlapping aisle.
cuts = slice.getCuts();
c1 = cuts.get(0);
for (int ic=1; ic<cuts.size(); ++ic) {
int c2 = cuts.get(ic);
Aisle newAisle = new Aisle("above",c1,top,c2-c1,Integer.MIN_VALUE);
for (ContainerShape shapeAbove : above) {
Rectangle shapeAboveBounds = getBounds(shapeAbove);
if (shapeAboveBounds.x<=c1 && c1<shapeAboveBounds.right()) {
newAisle.setHeight(shapeAboveBounds.y - shapeBounds.y - shapeBounds.height);
break;
}
}
if (newAisle.getHeight()==Integer.MIN_VALUE) {
newAisle.setHeight(shapeBounds.y - top);
// only add the void if there is no shape above this region.
aisles.add(newAisle);
}
c1 = c2;
}
Aisle a = getTrailingAisle(shape);
if (a!=null)
aisles.add(a);
}
aisles.add(new Aisle("end",right-rightMargin, top, rightMargin, bottom-top));
// rotate the horizontal aisle nodes
aisles.rotate(rotate);
return aisles;
}
protected Aisle getTrailingAisle(ContainerShape shape) {
Rectangle shapeBounds = getBounds(shape);
int x = shapeBounds.right();
int size = allShapes.size();
for (int i=0; i<size; ++i) {
ContainerShape s = allShapes.get(i);
if (s!=shape) {
Rectangle b = getBounds(s);
if (b.x<=x && x<b.right())
return null;
}
}
for (int i=0; i<size; ++i) {
ContainerShape s = allShapes.get(i);
if (s==shape) {
for (int n=i+1; n<size; ++n) {
ContainerShape nextShape = allShapes.get(n);
Rectangle nextShapeBounds = getBounds(nextShape);
if (nextShapeBounds.x>shapeBounds.right()) {
return new Aisle("trailing",shapeBounds.right(),top, nextShapeBounds.x - shapeBounds.right(), bottom-top);
}
}
}
}
return null;
}
protected List<ContainerShape> getShapesBelow(ContainerShape shape) {
final Rectangle bounds = getBounds(shape);
List<ContainerShape> shapes = new ArrayList<ContainerShape>();
for (ContainerShape s : allShapes) {
if (s!=shape) {
Rectangle b = getBounds(s);
if (b.x>bounds.right())
break;
int d = b.y - bounds.y;
if (
d>=0 && (
(bounds.x<=b.x && b.x<=bounds.right()) ||
(bounds.x<=b.right() && b.right()<=bounds.right()) ||
(b.x<=bounds.x && bounds.right()<=b.right())
)
) {
shapes.add(s);
}
}
}
// sort the rectangles by increasing distance from the bottom of the given shape
Collections.sort(shapes, new Comparator<ContainerShape>() {
@Override
public int compare(ContainerShape s1, ContainerShape s2) {
Rectangle b1 = getBounds(s1);
Rectangle b2 = getBounds(s2);
int d1 = b1.y - bounds.bottom();
int d2 = b2.y - bounds.bottom();
int i = d1 - d2;
if (i==0) {
i = b1.x - b2.x;
}
return i;
}
});
for (int i=0; i<shapes.size(); ++i) {
ContainerShape s = shapes.get(i);
Rectangle b = getBounds(s);
if (b.x<=bounds.x && b.right()>=bounds.right()) {
++i;
while (i<shapes.size()) {
shapes.remove(i);
}
}
}
return shapes;
}
protected List<ContainerShape> getShapesAbove(ContainerShape shape) {
final Rectangle bounds = getBounds(shape);
List<ContainerShape> shapes = new ArrayList<ContainerShape>();
for (ContainerShape s : allShapes) {
if (s!=shape) {
Rectangle b = getBounds(s);
if (b.x>bounds.right())
break;
int d = b.y - bounds.y;
if (
d<=0 && (
(bounds.x<=b.x && b.x<=bounds.right()) ||
(bounds.x<=b.right() && b.right()<=bounds.right()) ||
(b.x<=bounds.x && bounds.right()<=b.right())
)
) {
shapes.add(s);
}
}
}
// sort the rectangles by increasing distance from the top of the given shape
Collections.sort(shapes, new Comparator<ContainerShape>() {
@Override
public int compare(ContainerShape s1, ContainerShape s2) {
Rectangle b1 = getBounds(s1);
Rectangle b2 = getBounds(s2);
int d1 = b1.y - bounds.y;
int d2 = b2.y - bounds.y;
int i = d1 - d2;
if (i==0) {
i = b1.x - b2.x;
}
return i;
}
});
for (int i=0; i<shapes.size(); ++i) {
ContainerShape s = shapes.get(i);
Rectangle b = getBounds(s);
if (b.x<=bounds.x && b.right()>=bounds.right()) {
++i;
while (i<shapes.size()) {
shapes.remove(i);
}
}
}
return shapes;
}
class Slice {
protected Slice parent;
protected int left, right;
List<Integer> cuts = new ArrayList<Integer>();
List<Slice> children = new ArrayList<Slice>();
public Slice(int left, int right) {
this(null,left,right);
}
protected Slice(Slice parent, int left, int right) {
this.parent = parent;
this.left = left;
this.right = right;
cuts.add(left);
cuts.add(right);
}
public int remove(int l, int r) {
if (r<left || right<l) {
for (Slice s : children) {
s.remove(l, r);
}
}
else if (l<=left && left<=r && r<=right) {
for (Slice s : children) {
s.remove(l, r);
}
cut(left);
left = r;
}
else if (l<=left && right<=r) {
for (Slice s : children) {
s.remove(l, left);
s.remove(right, r);
}
cut(left);
cut(right);
right = left;
}
else if (l>left && r<right) {
children.add(new Slice(this,left,l));
children.add(new Slice(this,r,right));
cut(left);
left = l;
cut(right);
right = r;
}
else if (left<=l && l<=right && r>=right) {
for (Slice s : children) {
s.remove(r, right);
}
cut(right);
right = l;
}
return length();
}
public int length() {
int length = right - left;
for (Slice s : children) {
length += s.length();
}
return length;
}
protected void cut(int point) {
if (!cuts.contains(point))
cuts.add(point);
}
public List<Integer> getCuts() {
cut(left);
cut(right);
for (Slice s : children) {
for (Integer p : s.getCuts())
cut(p);
}
if (parent==null) {
Collections.sort(cuts);
}
return cuts;
}
}
protected void sortAllShapes() {
Collections.sort(allShapes, new Comparator<ContainerShape>() {
@Override
public int compare(ContainerShape s1, ContainerShape s2) {
Rectangle r1 = getBounds(s1);
Rectangle r2 = getBounds(s2);
int i = r1.x - r2.x;
if (i==0) {
i = r1.y - r2.y;
}
return i;
}
});
}
private Rectangle getBounds(ContainerShape shape) {
return getBounds(rotate,shape);
}
protected static Rectangle getBounds(boolean rotate, ContainerShape shape) {
ILocation loc = peService.getLocationRelativeToDiagram(shape);
IDimension size = GraphicsUtil.calculateSize(shape);
if (rotate) {
return rotateRectangle(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
}
return new Rectangle(loc.getX(), loc.getY(), size.getWidth(), size.getHeight());
}
protected static Rectangle rotateRectangle(int x, int y, int width, int height) {
return rotateRectangle(new Rectangle(x,y,width,height));
}
public static Rectangle rotateRectangle(Rectangle r) {
int y = r.x;
int x = r.y;
int w = r.height;
int h = r.width;
r.x = x;
r.y = y;
r.width = w;
r.height = h;
return r;
}
protected void drawAisles(AisleList aisle) {
Diagram diagram = fp.getDiagramTypeProvider().getDiagram();
for (Aisle node : aisle) {
AddContext context = new AddContext();
context.setTargetContainer(diagram);
context.setNewObject(node);
context.setX(node.getX());
context.setY(node.getY());
context.setSize(node.getWidth(), node.getHeight());
AddAisleFeature feature = new AddAisleFeature(fp);
node.setShape(feature.add(context));
}
}
protected void drawAisleConnections(AisleList aisles) {
Diagram diagram = fp.getDiagramTypeProvider().getDiagram();
ContainerShape sourceShape;
Anchor sourceAnchor;
ContainerShape targetShape;
Anchor targetAnchor;
for (Aisle n1 : aisles) {
for (Aisle n2 : n1.getRight()) {
if (n1!=n2) {
sourceShape = n1.getShape();
targetShape = n2.getShape();
if (sourceShape!=null && targetShape!=null) {
if (sourceShape.getAnchors().size()>0)
sourceAnchor = sourceShape.getAnchors().get(0);
else {
FixPointAnchor a = peService.createFixPointAnchor(sourceShape);
Rectangle r = getBounds(sourceShape);
a.setLocation(GraphicsUtil.createPoint(r.width/2, r.height/2));
gaService.createInvisibleRectangle(a);
sourceAnchor = a;
}
if (targetShape.getAnchors().size()>0)
targetAnchor = targetShape.getAnchors().get(0);
else {
FixPointAnchor a = peService.createFixPointAnchor(targetShape);
Rectangle r = getBounds(targetShape);
a.setLocation(GraphicsUtil.createPoint(r.width/2, r.height/2));
gaService.createInvisibleRectangle(a);
targetAnchor = a;
}
AddConnectionContext context = new AddConnectionContext(sourceAnchor, targetAnchor);
context.setTargetContainer(diagram);
context.setNewObject(new Object[] {n1, n2});
AddAisleConnectionFeature feature = new AddAisleConnectionFeature(fp);
feature.add(context);
}
}
}
}
}
protected class AddAisleFeature extends AbstractAddShapeFeature {
public AddAisleFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canAdd(IAddContext context) {
return true;
}
@Override
public PictogramElement add(IAddContext context) {
int x = context.getX();
int y = context.getY();
int width = context.getWidth();
int height = context.getHeight();
IColorConstant foreground = new ColorConstant(0,0,255);
Aisle aisle = (Aisle)context.getNewObject();
IColorConstant background = new ColorConstant(128,128,128);
double transparency = 0.75;
// if ("start".equals(aisle.type))
// background = new ColorConstant(0,255,150);
// if ("end".equals(aisle.type))
// background = new ColorConstant(150,255,0);
// if ("above".equals(aisle.type))
// background = new ColorConstant(0,0,255);
// if ("below".equals(aisle.type))
// background = new ColorConstant(150,150,0);
// if ("trailing".equals(aisle.type))
// background = new ColorConstant(250,200,50);
Rectangle bounds = getBounds(source);
boolean sourceAdjacent = false;
if (aisle.adjacent(bounds) != Aisle.Adjacence.NONE) {
background = new ColorConstant(0,255,0);
transparency = 0.25;
sourceAdjacent = true;
}
bounds = getBounds(target);
if (aisle.adjacent(bounds) != Aisle.Adjacence.NONE) {
if (sourceAdjacent) {
background = new ColorConstant(255,255,0);
}
else {
background = new ColorConstant(255,0,0);
}
transparency = 0.25;
}
Diagram diagram = getDiagram();
ContainerShape containerShape = peService.createContainerShape(context.getTargetContainer(), true);
org.eclipse.graphiti.mm.algorithms.Rectangle invisibleRect = gaService.createInvisibleRectangle(containerShape);
gaService.setLocationAndSize(invisibleRect, x, y, width, height);
Shape rectShape = peService.createShape(containerShape, false);
RoundedRectangle roundedRect = gaService.createRoundedRectangle(rectShape, 1, 1);
roundedRect.setForeground(gaService.manageColor(diagram, foreground));
roundedRect.setBackground(gaService.manageColor(diagram, background));
roundedRect.setFilled(true);
roundedRect.setTransparency(transparency);
roundedRect.setLineWidth(2);
// link(rectShape, context.getNewObject());
peService.setPropertyValue(containerShape, "CONNECTION_ROUTING_AISLE", "true");
gaService.setLocationAndSize(roundedRect, 0, 0, width, height);
peService.sendToFront(containerShape);
return containerShape;
}
}
private class DeleteAisleFeature extends DefaultDeleteFeature {
public DeleteAisleFeature(IFeatureProvider fp) {
super(fp);
}
}
private class AddAisleConnectionFeature extends AbstractAddShapeFeature {
public AddAisleConnectionFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canAdd(IAddContext ac) {
return true;
}
@Override
public PictogramElement add(IAddContext ac) {
IAddConnectionContext context = (IAddConnectionContext) ac;
Anchor sourceAnchor = context.getSourceAnchor();
Anchor targetAnchor = context.getTargetAnchor();
ContainerShape sourceShape = (ContainerShape) sourceAnchor.getParent();
ContainerShape targetShape = (ContainerShape) targetAnchor.getParent();
Object[] newObject = (Object[]) context.getNewObject();
Aisle sourceNode = (Aisle)newObject[0];
Aisle targetNode = (Aisle)newObject[1];
Diagram diagram = getDiagram();
Connection connection = peService.createFreeFormConnection(diagram);
connection.setStart(sourceAnchor);
connection.setEnd(targetAnchor);
peService.setPropertyValue(connection, "CONNECTION_ROUTING_LINK", "true");
Polyline connectionLine = Graphiti.getGaService().createPolyline(connection);
connectionLine.setLineWidth(1);
IColorConstant foreground = new ColorConstant(0,0,255);
int w = 3;
int l = 15;
ConnectionDecorator decorator = peService.createConnectionDecorator(connection, false, 1.0, true);
Polyline arrowhead = gaService.createPolygon(decorator, new int[] { -l, w, 0, 0, -l, -w, -l, w });
arrowhead.setForeground(gaService.manageColor(diagram, foreground));
connectionLine.setForeground(gaService.manageColor(diagram, foreground));
return connection;
}
}
}