/*******************************************************************************
* 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.core.utils;
import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.Lane;
import org.eclipse.bpmn2.Participant;
import org.eclipse.bpmn2.SubProcess;
import org.eclipse.bpmn2.TextAnnotation;
import org.eclipse.bpmn2.modeler.core.ModelHandler;
import org.eclipse.bpmn2.modeler.core.ModelHandlerLocator;
import org.eclipse.bpmn2.modeler.core.di.DIUtils;
import org.eclipse.bpmn2.modeler.core.features.BusinessObjectUtil;
import org.eclipse.emf.common.util.ECollections;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.graphiti.features.context.IPictogramElementContext;
import org.eclipse.graphiti.features.context.ITargetContext;
import org.eclipse.graphiti.mm.algorithms.AbstractText;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.algorithms.Text;
import org.eclipse.graphiti.mm.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.Diagram;
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;
public class FeatureSupport {
public static boolean isTargetSubProcess(ITargetContext context) {
return BusinessObjectUtil.containsElementOfType(context.getTargetContainer(), SubProcess.class);
}
public static boolean isTargetLane(ITargetContext context) {
return isLane(context.getTargetContainer());
}
public static boolean isLane(PictogramElement element) {
return BusinessObjectUtil.containsElementOfType(element, Lane.class);
}
public static boolean isTargetParticipant(ITargetContext context) {
return isParticipant(context.getTargetContainer());
}
public static boolean isParticipant(PictogramElement element) {
return BusinessObjectUtil.containsElementOfType(element, Participant.class);
}
public static boolean isLaneOnTop(Lane lane) {
return lane.getChildLaneSet() == null || lane.getChildLaneSet().getLanes().isEmpty();
}
public static boolean isTargetLaneOnTop(ITargetContext context) {
Lane lane = BusinessObjectUtil.getFirstElementOfType(context.getTargetContainer(), Lane.class);
return lane.getChildLaneSet() == null || lane.getChildLaneSet().getLanes().isEmpty();
}
/**
* Use ModelHandler.getInstance(diagram) instead
*
* @param diagram
* @return
* @throws IOException
*/
@Deprecated
public static ModelHandler getModelHanderInstance(Diagram diagram) throws IOException {
return ModelHandlerLocator.getModelHandler(diagram.eResource());
}
public static void redraw(ContainerShape container) {
ContainerShape root = getRootContainer(container);
resizeRecursively(root);
postResizeFixLenghts(root);
updateDI(root);
}
private static void updateDI(ContainerShape root) {
Diagram diagram = Graphiti.getPeService().getDiagramForPictogramElement(root);
Class<?> instanceClass = BusinessObjectUtil.getFirstElementOfType(root, BaseElement.class).eClass()
.getInstanceClass();
DIUtils.updateDIShape(root);
}
private static ContainerShape getRootContainer(ContainerShape container) {
ContainerShape parent = container.getContainer();
EObject bo = BusinessObjectUtil.getFirstElementOfType(parent, BaseElement.class);
if (bo != null && (bo instanceof Lane || bo instanceof Participant)) {
return getRootContainer(parent);
}
return container;
}
private static Dimension resize(ContainerShape container) {
EObject elem = BusinessObjectUtil.getFirstElementOfType(container, BaseElement.class);
IGaService service = Graphiti.getGaService();
int height = 0;
int width = container.getGraphicsAlgorithm().getWidth() - 15;
EList<Shape> children = container.getChildren();
ECollections.sort(children, new SiblingLaneComparator());
for (Shape s : children) {
Object bo = BusinessObjectUtil.getFirstElementOfType(s, BaseElement.class);
if (bo != null && (bo instanceof Lane || bo instanceof Participant) && !bo.equals(elem)) {
GraphicsAlgorithm ga = s.getGraphicsAlgorithm();
service.setLocation(ga, 15, height);
height += ga.getHeight() - 1;
if (ga.getWidth() >= width) {
width = ga.getWidth();
} else {
service.setSize(ga, width, ga.getHeight());
}
}
}
GraphicsAlgorithm ga = container.getGraphicsAlgorithm();
if (height == 0) {
return new Dimension(ga.getWidth(), ga.getHeight());
} else {
int newWidth = width + 15;
int newHeight = height + 1;
service.setSize(ga, newWidth, newHeight);
for (Shape s : children) {
GraphicsAlgorithm childGa = s.getGraphicsAlgorithm();
if (childGa instanceof Text) {
s.getGraphicsAlgorithm().setHeight(newHeight);
} else if (childGa instanceof Polyline) {
Polyline line = (Polyline) childGa;
Point firstPoint = line.getPoints().get(0);
Point newPoint = service.createPoint(firstPoint.getX(), newHeight);
line.getPoints().set(1, newPoint);
}
}
return new Dimension(newWidth, newHeight);
}
}
private static Dimension resizeRecursively(ContainerShape root) {
BaseElement elem = BusinessObjectUtil.getFirstElementOfType(root, BaseElement.class);
List<Dimension> dimensions = new ArrayList<Dimension>();
IGaService service = Graphiti.getGaService();
int foundContainers = 0;
for (Shape s : root.getChildren()) {
Object bo = BusinessObjectUtil.getFirstElementOfType(s, BaseElement.class);
if (checkForResize(elem, s, bo)) {
foundContainers += 1;
Dimension d = resizeRecursively((ContainerShape) s);
if (d != null) {
dimensions.add(d);
}
}
}
if (dimensions.isEmpty()) {
GraphicsAlgorithm ga = root.getGraphicsAlgorithm();
for (Shape s : root.getChildren()) {
GraphicsAlgorithm childGa = s.getGraphicsAlgorithm();
if (childGa instanceof Text) {
s.getGraphicsAlgorithm().setHeight(ga.getHeight());
} else if (childGa instanceof Polyline) {
Polyline line = (Polyline) childGa;
Point firstPoint = line.getPoints().get(0);
Point newPoint = service.createPoint(firstPoint.getX(), ga.getHeight());
line.getPoints().set(1, newPoint);
}
}
return new Dimension(ga.getWidth(), ga.getHeight());
}
if (foundContainers > 0) {
return resize(root);
}
return getMaxDimension(dimensions);
}
/**
* One can only resize lanes and participants
*/
private static boolean checkForResize(BaseElement currentBo, Shape s, Object bo) {
if (!(s instanceof ContainerShape)) {
return false;
}
if (bo == null) {
return false;
}
if (!(bo instanceof Lane || bo instanceof Participant)) {
return false;
}
return !bo.equals(currentBo);
}
private static Dimension getMaxDimension(List<Dimension> dimensions) {
if (dimensions.isEmpty()) {
return null;
}
int height = 0;
int width = 0;
for (Dimension d : dimensions) {
height += d.height;
if (d.width > width) {
width = d.width;
}
}
return new Dimension(width, height);
}
private static void postResizeFixLenghts(ContainerShape root) {
IGaService service = Graphiti.getGaService();
BaseElement elem = BusinessObjectUtil.getFirstElementOfType(root, BaseElement.class);
int width = root.getGraphicsAlgorithm().getWidth() - 15;
for (Shape s : root.getChildren()) {
Object o = BusinessObjectUtil.getFirstElementOfType(s, BaseElement.class);
if (checkForResize(elem, s, o)) {
GraphicsAlgorithm ga = s.getGraphicsAlgorithm();
service.setSize(ga, width, ga.getHeight());
postResizeFixLenghts((ContainerShape) s);
}
}
}
public static String getShapeValue(IPictogramElementContext context) {
String value = null;
PictogramElement pe = context.getPictogramElement();
if (pe instanceof ContainerShape) {
ContainerShape cs = (ContainerShape) pe;
for (Shape shape : cs.getChildren()) {
if (shape.getGraphicsAlgorithm() instanceof AbstractText) {
AbstractText text = (AbstractText) shape.getGraphicsAlgorithm();
value = text.getValue();
}
}
}
return value;
}
public static String getBusinessValue(IPictogramElementContext context) {
Object o = BusinessObjectUtil.getFirstElementOfType(context.getPictogramElement(), BaseElement.class);
if (o instanceof FlowElement) {
FlowElement e = (FlowElement) o;
return e.getName();
} else if (o instanceof TextAnnotation) {
TextAnnotation a = (TextAnnotation) o;
return a.getText();
} else if (o instanceof Participant) {
Participant p = (Participant) o;
return p.getName();
} else if (o instanceof Lane) {
Lane l = (Lane) o;
return l.getName();
}
return null;
}
public static Participant getTargetParticipant(ITargetContext context, ModelHandler handler) {
if (context.getTargetContainer() instanceof Diagram) {
return handler.getInternalParticipant();
}
Object bo = BusinessObjectUtil.getFirstElementOfType(context.getTargetContainer(), BaseElement.class);
if (bo instanceof Participant) {
return (Participant) bo;
}
return handler.getParticipant(bo);
}
public static Shape getShape(ContainerShape container, String property, String expectedValue) {
IPeService peService = Graphiti.getPeService();
Iterator<Shape> iterator = peService.getAllContainedShapes(container).iterator();
while (iterator.hasNext()) {
Shape shape = iterator.next();
String value = peService.getPropertyValue(shape, property);
if (value != null && value.equals(expectedValue)) {
return shape;
}
}
return null;
}
@SuppressWarnings("unchecked")
public static <T extends EObject> T getChildElementOfType(PictogramElement container, String property, String expectedValue, Class<T> clazz) {
IPeService peService = Graphiti.getPeService();
Iterator<PictogramElement> iterator = peService.getAllContainedPictogramElements(container).iterator();
while (iterator.hasNext()) {
PictogramElement pe = iterator.next();
String value = peService.getPropertyValue(pe, property);
if (value != null && value.equals(expectedValue) && clazz.isInstance(pe)) {
return (T) pe;
}
}
return null;
}
}