/******************************************************************************* * 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; } } }