/*******************************************************************************
* Copyright (c) 2011 Red Hat, Inc.
* All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.eclipse.bpmn2.modeler.ui.features.choreography;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.ENVELOPE_HEIGHT_MODIFIER;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.ENV_H;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.ENV_W;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.MARKER_H;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.MESSAGE_LINK;
import static org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties.R;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.bpmn2.ChoreographyActivity;
import org.eclipse.bpmn2.ChoreographyLoopType;
import org.eclipse.bpmn2.ChoreographyTask;
import org.eclipse.bpmn2.InteractionNode;
import org.eclipse.bpmn2.MessageFlow;
import org.eclipse.bpmn2.Participant;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.bpmn2.di.BPMNShape;
import org.eclipse.bpmn2.di.ParticipantBandKind;
import org.eclipse.bpmn2.modeler.core.di.DIUtils;
import org.eclipse.bpmn2.modeler.core.features.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyProperties;
import org.eclipse.bpmn2.modeler.core.utils.AnchorUtil;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.bpmn2.modeler.core.utils.StyleUtil;
import org.eclipse.bpmn2.modeler.core.utils.Tuple;
import org.eclipse.bpmn2.modeler.core.utils.AnchorUtil.AnchorLocation;
import org.eclipse.bpmn2.modeler.core.utils.AnchorUtil.BoundaryAnchor;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil.Envelope;
import org.eclipse.dd.dc.Bounds;
import org.eclipse.dd.di.DiagramElement;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.graphiti.datatypes.IDimension;
import org.eclipse.graphiti.datatypes.ILocation;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.mm.PropertyContainer;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.algorithms.Rectangle;
import org.eclipse.graphiti.mm.algorithms.RoundedRectangle;
import org.eclipse.graphiti.mm.algorithms.Text;
import org.eclipse.graphiti.mm.algorithms.styles.LineStyle;
import org.eclipse.graphiti.mm.algorithms.styles.Orientation;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.FreeFormConnection;
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.services.GraphitiUi;
import org.eclipse.graphiti.util.IColorConstant;
public class ChoreographyUtil {
private static IGaService gaService = Graphiti.getGaService();
private static IPeService peService = Graphiti.getPeService();
public static List<ContainerShape> getParticipantBandContainerShapes(
ContainerShape choreographyActivityContainerShape) {
List<ContainerShape> containers = new ArrayList<ContainerShape>();
Collection<Shape> shapes = peService.getAllContainedShapes(choreographyActivityContainerShape);
for (Shape s : shapes) {
String property = peService.getPropertyValue(s, ChoreographyProperties.BAND);
if (property != null && new Boolean(property)) {
containers.add((ContainerShape) s);
}
}
return containers;
}
public static List<BPMNShape> getParicipantBandBpmnShapes(ContainerShape choreographyActivityContainerShape) {
List<BPMNShape> bpmnShapes = new ArrayList<BPMNShape>();
List<ContainerShape> containers = getParticipantBandContainerShapes(choreographyActivityContainerShape);
for (ContainerShape container : containers) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(container, BPMNShape.class);
bpmnShapes.add(bpmnShape);
}
return bpmnShapes;
}
public static boolean isChoreographyParticipantBand(PictogramElement element) {
EObject container = element.eContainer();
if (container instanceof PictogramElement) {
PictogramElement containerElem = (PictogramElement) container;
if (BusinessObjectUtil.containsElementOfType(containerElem, ChoreographyActivity.class)) {
return true;
}
}
return false;
}
public static Tuple<List<ContainerShape>, List<ContainerShape>> getTopAndBottomBands(
List<ContainerShape> participantBands) {
List<ContainerShape> top = new ArrayList<ContainerShape>();
List<ContainerShape> bottom = new ArrayList<ContainerShape>();
if (participantBands.size() == 1) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(participantBands.get(0), BPMNShape.class);
ParticipantBandKind bandKind = bpmnShape.getParticipantBandKind();
if (bandKind == ParticipantBandKind.TOP_INITIATING || bandKind == ParticipantBandKind.TOP_NON_INITIATING) {
top.add(participantBands.get(0));
} else if (bandKind == ParticipantBandKind.BOTTOM_INITIATING
|| bandKind == ParticipantBandKind.BOTTOM_NON_INITIATING) {
bottom.add(participantBands.get(0));
} else {
top.add(participantBands.get(0));
}
} else {
Collections.sort(participantBands, getParticipantBandComparator());
int n = participantBands.size();
int divider = n / 2;
top.addAll(participantBands.subList(0, divider));
bottom.addAll(participantBands.subList(divider, n));
}
return new Tuple<List<ContainerShape>, List<ContainerShape>>(top, bottom);
}
private static Comparator<ContainerShape> getParticipantBandComparator() {
return new Comparator<ContainerShape>() {
@Override
public int compare(ContainerShape c1, ContainerShape c2) {
BPMNShape bpmnShape1 = BusinessObjectUtil.getFirstElementOfType(c1, BPMNShape.class);
Bounds bounds1 = bpmnShape1.getBounds();
BPMNShape bpmnShape2 = BusinessObjectUtil.getFirstElementOfType(c2, BPMNShape.class);
Bounds bounds2 = bpmnShape2.getBounds();
return new Float(bounds1.getY()).compareTo(new Float(bounds2.getY()));
}
};
}
public static void resizePartipantBandContainerShapes(int w, int h, List<ContainerShape> top,
List<ContainerShape> bottom, Diagram diagram) {
int y = 0;
for (ContainerShape container : top) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(container, BPMNShape.class);
Bounds bounds = bpmnShape.getBounds();
int hAcc = (int) bounds.getHeight();
gaService.setLocationAndSize(container.getGraphicsAlgorithm(), 0, y, w, hAcc);
y += hAcc;
resizeParticipantBandChildren(container, w);
DIUtils.updateDIShape(container);
AnchorUtil.relocateFixPointAnchors(container, w, (int) bounds.getHeight());
AnchorUtil.reConnect(bpmnShape, diagram);
}
Collections.reverse(bottom); // start from bottom towards center
y = h;
for (ContainerShape container : bottom) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(container, BPMNShape.class);
Bounds bounds = bpmnShape.getBounds();
y -= bounds.getHeight();
gaService.setLocationAndSize(container.getGraphicsAlgorithm(), 0, y, w, (int) bounds.getHeight());
resizeParticipantBandChildren(container, w);
DIUtils.updateDIShape(container);
AnchorUtil.relocateFixPointAnchors(container, w, (int) bounds.getHeight());
AnchorUtil.reConnect(bpmnShape, diagram);
}
}
private static void resizeParticipantBandChildren(ContainerShape container, int w) {
for (Shape s : container.getChildren()) {
GraphicsAlgorithm ga = s.getGraphicsAlgorithm();
if (ga instanceof Text) {
gaService.setSize(ga, w, ga.getHeight());
} else if (ga instanceof Rectangle) {
gaService.setLocation(ga, (w / 2) - (ga.getWidth() / 2), ga.getY());
}
}
}
public static String getParticipantRefIds(ChoreographyActivity choreography) {
if (choreography.getParticipantRefs() == null) {
return new String();
}
Iterator<Participant> iterator = choreography.getParticipantRefs().iterator();
String delim = ":";
StringBuilder sb = new StringBuilder();
while (iterator.hasNext()) {
Participant participant = iterator.next();
sb.append(participant.getId());
if (iterator.hasNext()) {
sb.append(delim);
}
}
return sb.toString();
}
public static String getMessageRefIds(ChoreographyTask choreography) {
if (choreography.getMessageFlowRef() == null) {
return new String();
}
Iterator<MessageFlow> iterator = choreography.getMessageFlowRef().iterator();
String delim = ":";
StringBuilder sb = new StringBuilder();
while (iterator.hasNext()) {
MessageFlow message = iterator.next();
sb.append(message.getId());
if (iterator.hasNext()) {
sb.append(delim);
}
}
return sb.toString();
}
public static void updateParticipantReferences(ContainerShape choreographyContainer,
List<ContainerShape> currentParticipantContainers, List<Participant> newParticipants, IFeatureProvider fp,
boolean showNames) {
Diagram diagram = peService.getDiagramForShape(choreographyContainer);
ChoreographyActivity choreography = BusinessObjectUtil.getFirstElementOfType(choreographyContainer,
ChoreographyActivity.class);
BPMNDiagram dia = BusinessObjectUtil.getFirstElementOfType(diagram, BPMNDiagram.class);
List<DiagramElement> diElements = dia.getPlane().getPlaneElement();
for (int i = 0; i < currentParticipantContainers.size(); i++) {
ContainerShape container = currentParticipantContainers.get(i);
for (Connection c : peService.getOutgoingConnections(container)) {
EObject parent = c.getEnd().eContainer();
if (parent instanceof PictogramElement) {
peService.deletePictogramElement((PictogramElement) parent);
}
}
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(container, BPMNShape.class);
diElements.remove(bpmnShape);
peService.deletePictogramElement(container);
}
GraphicsAlgorithm ga = choreographyContainer.getGraphicsAlgorithm();
IDimension size = gaService.calculateSize(ga);
List<ContainerShape> newContainers = new ArrayList<ContainerShape>();
int y = 0;
boolean first = true;
List<InteractionNode> sources = new ArrayList<InteractionNode>();
if (choreography instanceof ChoreographyTask) {
for (MessageFlow message : ((ChoreographyTask) choreography).getMessageFlowRef()) {
sources.add(message.getSourceRef());
}
}
Iterator<Participant> iterator = newParticipants.iterator();
while (iterator.hasNext()) {
Participant participant = iterator.next();
ContainerShape bandShape = peService.createContainerShape(choreographyContainer, true);
ParticipantBandKind bandKind = getNewParticipantBandKind(choreography, participant, first,
!iterator.hasNext());
boolean multiple = participant.getParticipantMultiplicity() != null
&& participant.getParticipantMultiplicity().getMaximum() > 1;
int w = size.getWidth();
int h = multiple ? 40 : 20;
BPMNShape bpmnShape = DIUtils.createDIShape(bandShape, participant, 0, y + h, w, h, fp, diagram);
bpmnShape.setChoreographyActivityShape(BusinessObjectUtil.getFirstElementOfType(choreographyContainer,
BPMNShape.class));
bpmnShape.setIsMarkerVisible(multiple);
bpmnShape.setParticipantBandKind(bandKind);
bpmnShape.setIsMessageVisible(sources.contains(participant));
createParticipantBandContainerShape(bandKind, choreographyContainer, bandShape, bpmnShape, showNames);
if (multiple) {
drawMultiplicityMarkers(bandShape);
}
newContainers.add(bandShape);
y += h;
first = false;
}
Tuple<List<ContainerShape>, List<ContainerShape>> topAndBottom = getTopAndBottomBands(newContainers);
resizePartipantBandContainerShapes(size.getWidth(), size.getHeight(), topAndBottom.getFirst(),
topAndBottom.getSecond(), diagram);
}
private static ContainerShape createTopShape(ContainerShape parent, ContainerShape bandShape, BPMNShape bpmnShape,
boolean initiating, boolean showNames) {
if (bandShape == null) {
bandShape = peService.createContainerShape(parent, true);
}
Bounds bounds = bpmnShape.getBounds();
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
Diagram diagram = peService.getDiagramForPictogramElement(parent);
RoundedRectangle band = gaService.createRoundedRectangle(bandShape, R, R);
band.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
band.setBackground(initiating ? gaService.manageColor(diagram, IColorConstant.WHITE) : gaService.manageColor(
diagram, IColorConstant.LIGHT_GRAY));
gaService.setLocationAndSize(band, 0, 0, w, h);
Participant p = (Participant) bpmnShape.getBpmnElement();
if (showNames) {
addBandLabel(bandShape, p.getName(), w, h);
}
AnchorUtil.addFixedPointAnchors(bandShape, band);
peService.setPropertyValue(bandShape, ChoreographyProperties.BAND, Boolean.toString(true));
peService.setPropertyValue(bandShape, ChoreographyProperties.MESSAGE_VISIBLE,
Boolean.toString(bpmnShape.isIsMessageVisible()));
return bandShape;
}
private static ContainerShape createBottomShape(ContainerShape parent, ContainerShape bandShape,
BPMNShape bpmnShape, boolean initiating, boolean showNames) {
if (bandShape == null) {
bandShape = peService.createContainerShape(parent, true);
}
Bounds bounds = bpmnShape.getBounds();
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
ILocation parentLoc = peService.getLocationRelativeToDiagram(parent);
int y = (int) bounds.getY() - parentLoc.getY();
Diagram diagram = peService.getDiagramForPictogramElement(parent);
RoundedRectangle band = gaService.createRoundedRectangle(bandShape, R, R);
band.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
band.setBackground(initiating ? gaService.manageColor(diagram, IColorConstant.WHITE) : gaService.manageColor(
diagram, IColorConstant.LIGHT_GRAY));
gaService.setLocationAndSize(band, 0, y, w, h);
Participant p = (Participant) bpmnShape.getBpmnElement();
if (showNames) {
addBandLabel(bandShape, p.getName(), w, h);
}
AnchorUtil.addFixedPointAnchors(bandShape, band);
peService.setPropertyValue(bandShape, ChoreographyProperties.BAND, Boolean.toString(true));
peService.setPropertyValue(bandShape, ChoreographyProperties.MESSAGE_VISIBLE,
Boolean.toString(bpmnShape.isIsMessageVisible()));
return bandShape;
}
private static ContainerShape createMiddleShape(ContainerShape parent, ContainerShape bandShape,
BPMNShape bpmnShape, boolean initiating, boolean showNames) {
if (bandShape == null) {
bandShape = peService.createContainerShape(parent, true);
}
Bounds bounds = bpmnShape.getBounds();
int w = (int) bounds.getWidth();
int h = (int) bounds.getHeight();
ILocation parentLoc = peService.getLocationRelativeToDiagram(parent);
int y = (int) bounds.getY() - parentLoc.getY();
Diagram diagram = peService.getDiagramForPictogramElement(parent);
Rectangle band = gaService.createRectangle(bandShape);
band.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
band.setBackground(initiating ? gaService.manageColor(diagram, IColorConstant.WHITE) : gaService.manageColor(
diagram, IColorConstant.LIGHT_GRAY));
gaService.setLocationAndSize(band, 0, y, w, h);
Participant p = (Participant) bpmnShape.getBpmnElement();
if (showNames) {
addBandLabel(bandShape, p.getName(), w, h);
}
AnchorUtil.addFixedPointAnchors(bandShape, band);
peService.setPropertyValue(bandShape, ChoreographyProperties.BAND, Boolean.toString(true));
peService.setPropertyValue(bandShape, ChoreographyProperties.MESSAGE_VISIBLE,
Boolean.toString(bpmnShape.isIsMessageVisible()));
return bandShape;
}
private static void addBandLabel(ContainerShape container, String name, int w, int h) {
Diagram diagram = peService.getDiagramForShape(container);
Shape labelShape = peService.createShape(container, false);
Text label = gaService.createDefaultText(diagram, labelShape);
label.setValue(name);
gaService.setLocationAndSize(label, 0, 0, w, h);
label.setStyle(StyleUtil.getStyleForText(peService.getDiagramForPictogramElement(container)));
label.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER);
label.setVerticalAlignment(Orientation.ALIGNMENT_CENTER);
}
private static ParticipantBandKind getNewParticipantBandKind(ChoreographyActivity choreography,
Participant participant, boolean first, boolean last) {
boolean initiating = choreography.getInitiatingParticipantRef() != null
&& choreography.getInitiatingParticipantRef().equals(participant);
if (first) {
return initiating ? ParticipantBandKind.TOP_INITIATING : ParticipantBandKind.TOP_NON_INITIATING;
} else if (last) {
return initiating ? ParticipantBandKind.BOTTOM_INITIATING : ParticipantBandKind.BOTTOM_NON_INITIATING;
} else {
return initiating ? ParticipantBandKind.MIDDLE_INITIATING : ParticipantBandKind.MIDDLE_NON_INITIATING;
}
}
private static void drawMessageLink(String name, BoundaryAnchor boundaryAnchor, int x, int y, boolean filled) {
Diagram diagram = peService.getDiagramForAnchor(boundaryAnchor.anchor);
FreeFormConnection connection = peService.createFreeFormConnection(diagram);
Polyline connectionLine = gaService.createPolyline(connection);
connectionLine.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
connectionLine.setLineStyle(LineStyle.DOT);
connectionLine.setLineWidth(2);
ContainerShape envelope = peService.createContainerShape(diagram, true);
Rectangle invisibleRectangle = gaService.createInvisibleRectangle(envelope);
gaService.setLocation(invisibleRectangle, x, y);
gaService.setSize(invisibleRectangle, ENV_W + 50, ENV_H);
Shape envelopeShape = peService.createShape(envelope, false);
Envelope envelopeGa = GraphicsUtil.createEnvelope(envelopeShape, 0, 0, ENV_W, ENV_H);
IColorConstant color = filled ? IColorConstant.LIGHT_GRAY : IColorConstant.WHITE;
envelopeGa.rect.setFilled(true);
envelopeGa.rect.setBackground(gaService.manageColor(diagram, color));
envelopeGa.rect.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
envelopeGa.line.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
AnchorUtil.addFixedPointAnchors(envelope, envelopeGa.rect);
Shape textShape = peService.createShape(envelope, false);
Text text = gaService.createDefaultText(diagram, textShape);
IDimension size = GraphitiUi.getUiLayoutService().calculateTextSize(name, text.getFont());
gaService.setLocationAndSize(text, ENV_W + 3, 3, size.getWidth(), size.getHeight());
text.setValue(name);
gaService.setSize(invisibleRectangle, ENV_W + size.getWidth() + 3, ENV_H);
AnchorLocation envelopeAnchorLoc = null;
if (boundaryAnchor.locationType == AnchorLocation.TOP) {
envelopeAnchorLoc = AnchorLocation.BOTTOM;
} else {
envelopeAnchorLoc = AnchorLocation.TOP;
}
connection.setStart(boundaryAnchor.anchor);
connection.setEnd(AnchorUtil.getBoundaryAnchors(envelope).get(envelopeAnchorLoc).anchor);
peService.setPropertyValue(envelope, MESSAGE_LINK, Boolean.toString(true));
}
public static void drawMultiplicityMarkers(ContainerShape container) {
Diagram diagram = peService.getDiagramForPictogramElement(container);
Shape multiplicityShape = peService.createShape(container, false);
Rectangle rect = gaService.createInvisibleRectangle(multiplicityShape);
IDimension size = gaService.calculateSize(container.getGraphicsAlgorithm());
int w = 10;
int h = 10;
int x = (size.getWidth() / 2) - (w / 2);
int y = size.getHeight() - h - 1;
gaService.setLocationAndSize(rect, x, y, w, h);
int[][] coorinates = { new int[] { 0, 0, 0, h }, new int[] { 4, 0, 4, h }, new int[] { 8, 0, 8, h } };
for (int[] xy : coorinates) {
Polyline line = gaService.createPolyline(rect, xy);
line.setLineWidth(2);
line.setForeground(gaService.manageColor(diagram, StyleUtil.CLASS_FOREGROUND));
}
}
public static ContainerShape createParticipantBandContainerShape(ParticipantBandKind bandKind,
ContainerShape container, ContainerShape bandContainer, BPMNShape bpmnShape, boolean showNames) {
switch (bandKind) {
case TOP_INITIATING:
return createTopShape(container, bandContainer, bpmnShape, true, showNames);
case TOP_NON_INITIATING:
return createTopShape(container, bandContainer, bpmnShape, false, showNames);
case MIDDLE_INITIATING:
return createMiddleShape(container, bandContainer, bpmnShape, true, showNames);
case MIDDLE_NON_INITIATING:
return createMiddleShape(container, bandContainer, bpmnShape, false, showNames);
case BOTTOM_INITIATING:
return createBottomShape(container, bandContainer, bpmnShape, true, showNames);
case BOTTOM_NON_INITIATING:
return createBottomShape(container, bandContainer, bpmnShape, false, showNames);
}
return bandContainer;
}
public static ContainerShape createParticipantBandContainerShape(ParticipantBandKind bandKind,
ContainerShape container, BPMNShape bpmnShape, boolean showNames) {
return createParticipantBandContainerShape(bandKind, container, null, bpmnShape, showNames);
}
public static void drawMessageLinks(ContainerShape choreographyContainer) {
List<MessageFlow> messageFlows = new ArrayList<MessageFlow>();
ChoreographyTask choreography = BusinessObjectUtil.getFirstElementOfType(choreographyContainer,
ChoreographyTask.class);
if (choreography != null) {
messageFlows.addAll(choreography.getMessageFlowRef());
}
List<ContainerShape> bandContainers = getParticipantBandContainerShapes(choreographyContainer);
Tuple<List<ContainerShape>, List<ContainerShape>> topAndBottom = getTopAndBottomBands(bandContainers);
List<ContainerShape> shapesWithVisileMessages = new ArrayList<ContainerShape>();
Map<AnchorLocation, BoundaryAnchor> boundaryAnchors = AnchorUtil.getBoundaryAnchors(choreographyContainer);
BoundaryAnchor topBoundaryAnchor = boundaryAnchors.get(AnchorLocation.TOP);
BoundaryAnchor bottomBoundaryAnchor = boundaryAnchors.get(AnchorLocation.BOTTOM);
int topConnectionIndex = 0;
int bottomConnectionIndex = 0;
boolean hasTopMessage = false;
EList<Connection> topConnections = topBoundaryAnchor.anchor.getOutgoingConnections();
for (int i = 0; i < topConnections.size(); i++) {
Connection connection = topConnections.get(i);
EObject container = connection.getEnd().eContainer();
if (container instanceof PropertyContainer) {
String property = peService.getPropertyValue((PropertyContainer) container, MESSAGE_LINK);
if (property != null && new Boolean(property)) {
topConnectionIndex = i;
hasTopMessage = true;
break;
}
}
}
boolean hasBottomMessage = false;
EList<Connection> bottomConnections = bottomBoundaryAnchor.anchor.getOutgoingConnections();
for (int i = 0; i < bottomConnections.size(); i++) {
Connection connection = bottomConnections.get(i);
EObject container = connection.getEnd().eContainer();
if (container instanceof PropertyContainer) {
String property = peService.getPropertyValue((PropertyContainer) container, MESSAGE_LINK);
if (property != null && new Boolean(property)) {
bottomConnectionIndex = i;
hasBottomMessage = true;
break;
}
}
}
Iterator<ContainerShape> iterator = bandContainers.iterator();
while (iterator.hasNext()) {
ContainerShape bandContainer = iterator.next();
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(bandContainer, BPMNShape.class);
if (bpmnShape.isIsMessageVisible()) {
shapesWithVisileMessages.add(bandContainer);
}
}
boolean shouldDrawTopMessage = !Collections.disjoint(topAndBottom.getFirst(), shapesWithVisileMessages);
boolean shouldDrawBottomMessage = !Collections.disjoint(topAndBottom.getSecond(), shapesWithVisileMessages);
String topMessageName = null;
String bottomMessageName = null;
if (shouldDrawTopMessage) {
topMessageName = getMessageName(messageFlows, topAndBottom.getFirst());
}
if (topMessageName == null) {
topMessageName = new String();
}
if (shouldDrawBottomMessage) {
bottomMessageName = getMessageName(messageFlows, topAndBottom.getSecond());
}
if (bottomMessageName == null) {
bottomMessageName = new String();
}
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(choreographyContainer, BPMNShape.class);
Bounds bounds = bpmnShape.getBounds();
int x = (int) ((bounds.getX() + bounds.getWidth() / 2) - (ENV_W / 2));
if (!hasTopMessage && shouldDrawTopMessage) {
int y = (int) (bounds.getY() - ENVELOPE_HEIGHT_MODIFIER - ENV_H);
drawMessageLink(topMessageName, topBoundaryAnchor, x, y, isFilled(topAndBottom.getFirst()));
} else if (hasTopMessage && !shouldDrawTopMessage) {
PictogramElement envelope = (PictogramElement) topConnections.get(topConnectionIndex).getEnd().eContainer();
peService.deletePictogramElement(topConnections.get(topConnectionIndex));
peService.deletePictogramElement(envelope);
} else if (hasTopMessage && shouldDrawTopMessage) {
PictogramElement envelope = (PictogramElement) topConnections.get(topConnectionIndex).getEnd().eContainer();
setMessageLabel(topMessageName, envelope);
}
if (!hasBottomMessage && shouldDrawBottomMessage) {
int y = (int) (bounds.getY() + bounds.getHeight() + ENVELOPE_HEIGHT_MODIFIER);
drawMessageLink(bottomMessageName, bottomBoundaryAnchor, x, y, isFilled(topAndBottom.getSecond()));
} else if (hasBottomMessage && !shouldDrawBottomMessage) {
PictogramElement envelope = (PictogramElement) bottomConnections.get(bottomConnectionIndex).getEnd()
.eContainer();
peService.deletePictogramElement(bottomConnections.get(bottomConnectionIndex));
peService.deletePictogramElement(envelope);
} else if (hasBottomMessage && shouldDrawBottomMessage) {
PictogramElement envelope = (PictogramElement) bottomConnections.get(bottomConnectionIndex).getEnd()
.eContainer();
setMessageLabel(bottomMessageName, envelope);
}
return;
}
private static boolean isFilled(List<ContainerShape> bands) {
boolean filled = true;
for (ContainerShape band : bands) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(band, BPMNShape.class);
if (!bpmnShape.isIsMessageVisible()) {
continue;
}
ParticipantBandKind bandKind = bpmnShape.getParticipantBandKind();
if (bandKind == ParticipantBandKind.TOP_INITIATING || bandKind == ParticipantBandKind.BOTTOM_INITIATING
|| bandKind == ParticipantBandKind.MIDDLE_INITIATING) {
filled = false;
break;
}
}
return filled;
}
private static void setMessageLabel(String label, PictogramElement message) {
ContainerShape containerShape = (ContainerShape) message;
Iterator<Shape> iterator = peService.getAllContainedShapes(containerShape).iterator();
while (iterator.hasNext()) {
Shape shape = iterator.next();
if (shape.getGraphicsAlgorithm() instanceof Text) {
Text text = (Text) shape.getGraphicsAlgorithm();
text.setValue(label);
IDimension size = GraphitiUi.getUiLayoutService().calculateTextSize(label, text.getFont());
gaService.setSize(containerShape.getGraphicsAlgorithm(), ENV_W + size.getWidth() + 3, ENV_H);
gaService.setSize(text, size.getWidth(), size.getHeight());
break;
}
}
}
private static String getMessageName(List<MessageFlow> messageFlows, List<ContainerShape> bands) {
for (ContainerShape band : bands) {
Participant participant = BusinessObjectUtil.getFirstElementOfType(band, Participant.class);
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(band, BPMNShape.class);
if (bpmnShape.isIsMessageVisible()) {
for (MessageFlow flow : messageFlows) {
if (flow.getSourceRef().equals(participant)) {
return flow.getName();
}
}
}
}
return null;
}
public static void moveChoreographyMessageLinks(ContainerShape choreographyContainer) {
BPMNShape bpmnShape = BusinessObjectUtil.getFirstElementOfType(choreographyContainer, BPMNShape.class);
Bounds bounds = bpmnShape.getBounds();
int x = (int) ((bounds.getX() + bounds.getWidth() / 2) - (ENV_W / 2));
Map<AnchorLocation, BoundaryAnchor> boundaryAnchors = AnchorUtil.getBoundaryAnchors(choreographyContainer);
BoundaryAnchor topBoundaryAnchor = boundaryAnchors.get(AnchorLocation.TOP);
BoundaryAnchor bottomBoundaryAnchor = boundaryAnchors.get(AnchorLocation.BOTTOM);
for (Connection connection : topBoundaryAnchor.anchor.getOutgoingConnections()) {
EObject container = connection.getEnd().eContainer();
if (container instanceof PropertyContainer) {
String property = peService.getPropertyValue((PropertyContainer) container, MESSAGE_LINK);
if (property != null && new Boolean(property)) {
int y = (int) (bounds.getY() - ENVELOPE_HEIGHT_MODIFIER - ENV_H);
gaService.setLocation(((ContainerShape) container).getGraphicsAlgorithm(), x, y);
break;
}
}
}
for (Connection connection : bottomBoundaryAnchor.anchor.getOutgoingConnections()) {
EObject container = connection.getEnd().eContainer();
if (container instanceof PropertyContainer) {
String property = peService.getPropertyValue((PropertyContainer) container, MESSAGE_LINK);
if (property != null && new Boolean(property)) {
int y = (int) (bounds.getY() + bounds.getHeight() + ENVELOPE_HEIGHT_MODIFIER);
gaService.setLocation(((ContainerShape) container).getGraphicsAlgorithm(), x, y);
break;
}
}
}
}
public static void drawChoreographyLoopType(ContainerShape markerShape, ChoreographyLoopType type) {
Collection<Shape> shapes = peService.getAllContainedShapes(markerShape);
Shape drawingShape = null;
if (shapes.size() == 1) { // remove previous shape
Iterator<Shape> iterator = shapes.iterator();
while (iterator.hasNext()) {
Shape shape = iterator.next();
drawingShape = shape;
break;
}
}
if (drawingShape != null) {
peService.deletePictogramElement(drawingShape);
}
drawingShape = peService.createShape(markerShape, false);
Rectangle rectangle = gaService.createInvisibleRectangle(drawingShape);
gaService.setLocationAndSize(rectangle, 0, 0, MARKER_H, MARKER_H);
if (type == null || type == ChoreographyLoopType.NONE) {
return;
}
switch (type) {
case STANDARD:
// TODO implement when property editors supports enums
break;
case MULTI_INSTANCE_PARALLEL:
// TODO implement when property editors supports enums
break;
case MULTI_INSTANCE_SEQUENTIAL:
// TODO implement when property editors supports enums
break;
}
}
}