blob: bd0e92b9e47fbc4de372d79badffae42ddbad666 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 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
*
* @author Ivar Meikas
******************************************************************************/
package org.eclipse.bpmn2.modeler.core.features.containers.lane;
import java.util.List;
import org.eclipse.bpmn2.Lane;
import org.eclipse.bpmn2.modeler.core.features.GraphitiConstants;
import org.eclipse.bpmn2.modeler.core.features.containers.AbstractResizeContainerFeature;
import org.eclipse.bpmn2.modeler.core.utils.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.utils.FeatureSupport;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IResizeShapeFeature;
import org.eclipse.graphiti.features.context.IResizeShapeContext;
import org.eclipse.graphiti.features.context.impl.ResizeShapeContext;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.services.Graphiti;
public class ResizeLaneFeature extends AbstractResizeContainerFeature {
public ResizeLaneFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canResizeShape(IResizeShapeContext context) {
boolean doit = false;
boolean isLane = FeatureSupport.isLane(context.getPictogramElement());
if (isLane) {
boolean isParentLane = FeatureSupport.isLane(((ContainerShape) context
.getPictogramElement()).getContainer());
if (!isParentLane) {
doit = true;
}
else {
if (context.getHeight() == -1 && context.getWidth() == -1) {
doit = true;
}
else {
GraphicsAlgorithm ga = ((ContainerShape) context.getPictogramElement())
.getGraphicsAlgorithm();
int i = compare(ga.getHeight(), ga.getWidth(), context.getHeight(),
context.getWidth());
Lane lane = (Lane) BusinessObjectUtil.getFirstElementOfType(
context.getPictogramElement(), Lane.class);
if (i < 0) {// && lane.getFlowNodeRefs().size() == 0) {
doit = true;
}
else if (i > 0) {
doit = true;
}
}
}
if (doit && !super.canResizeShape(context))
doit = false;
}
return doit;
}
@Override
public void resizeShape(IResizeShapeContext context) {
preResizeShape(context);
resizeHeight(context);
resizeWidth(context);
postResizeShape(context);
}
protected void resizeHeight(IResizeShapeContext context) {
ContainerShape laneShape = (ContainerShape) context.getShape();
GraphicsAlgorithm ga = laneShape.getGraphicsAlgorithm();
if ((isHorizontal && ga.getHeight() != context.getHeight())
|| (!isHorizontal && ga.getWidth() != context.getWidth())) {
boolean useFirstLane = false;
Object fetchFirstProperty = context.getProperty(GraphitiConstants.RESIZE_FIRST_LANE);
if (fetchFirstProperty != null && ((Boolean) fetchFirstProperty).booleanValue()) {
useFirstLane = true;
} else {
if ((isHorizontal && context.getY() != ga.getY()) ||
(!isHorizontal && context.getX() != ga.getX())) {
useFirstLane = true;
if (laneShape.equals(rootContainer)) {
Graphiti.getGaService().setLocation(ga, context.getX(), context.getY());
}
}
}
ContainerShape lowestContainingLane = getLowestLane(laneShape, useFirstLane);
GraphicsAlgorithm lowestLaneGA = lowestContainingLane.getGraphicsAlgorithm();
int width = 0;
int height = 0;
if (isHorizontal) {
int dHeight = context.getHeight() - ga.getHeight();
height = lowestLaneGA.getHeight() + dHeight;
if (height < 100) {
height = 100;
}
width = lowestLaneGA.getWidth();
} else {
int dWidth = context.getWidth() - ga.getWidth();
width = lowestLaneGA.getWidth() + dWidth;
if (width < 100) {
width = 100;
}
height = lowestLaneGA.getHeight();
}
ResizeShapeContext newContext = new ResizeShapeContext(lowestContainingLane);
newContext.setX(lowestLaneGA.getX());
newContext.setY(lowestLaneGA.getY());
newContext.setHeight(height);
newContext.setWidth(width);
newContext.setDirection(context.getDirection());
super.resizeShape(newContext);
}
}
protected void resizeWidth(IResizeShapeContext context) {
ContainerShape laneShape = (ContainerShape) context.getShape();
GraphicsAlgorithm ga = laneShape.getGraphicsAlgorithm();
if ((isHorizontal && ga.getWidth() != context.getWidth())
|| (!isHorizontal && ga.getHeight() != context.getHeight())) {
int dWidth = 0;
int dHeight = 0;
if (isHorizontal) {
dWidth = context.getWidth() - ga.getWidth();
} else {
dHeight = context.getHeight() - ga.getHeight();
}
Object poolResizeProperty = context.getProperty(GraphitiConstants.POOL_RESIZE_PROPERTY);
if (poolResizeProperty != null && ((Boolean) poolResizeProperty).booleanValue()) {
if (isHorizontal) {
Graphiti.getGaService().setWidth(ga, context.getWidth());
} else {
Graphiti.getGaService().setHeight(ga, context.getHeight());
}
for (PictogramElement currentChild : BusinessObjectUtil.getChildElementsOfType(laneShape, Lane.class)) {
if (currentChild instanceof ContainerShape) {
ContainerShape currentContainer = (ContainerShape) currentChild;
GraphicsAlgorithm currentGA = currentChild.getGraphicsAlgorithm();
ResizeShapeContext newContext = new ResizeShapeContext(currentContainer);
newContext.setX(currentGA.getX());
newContext.setY(currentGA.getY());
newContext.setHeight(currentGA.getHeight() + dHeight);
newContext.setWidth(currentGA.getWidth() + dWidth);
newContext.setDirection(context.getDirection());
newContext.putProperty(GraphitiConstants.POOL_RESIZE_PROPERTY, true);
resizeShape(newContext);
}
}
} else {
GraphicsAlgorithm rootGA = rootContainer.getGraphicsAlgorithm();
if (FeatureSupport.isParticipant(rootContainer)) {
ResizeShapeContext newContext = new ResizeShapeContext(rootContainer);
newContext.setX(rootGA.getX());
newContext.setY(rootGA.getY());
newContext.setWidth(rootGA.getWidth() + dWidth);
newContext.setHeight(rootGA.getHeight() + dHeight);
newContext.setDirection(context.getDirection());
IResizeShapeFeature resizeFeature = getFeatureProvider().getResizeShapeFeature(newContext);
if (resizeFeature.canResizeShape(newContext)) {
resizeFeature.resizeShape(newContext);
}
} else {
ContainerShape container = null;
Object rootIsLaneProperty = context.getProperty(GraphitiConstants.LANE_RESIZE_PROPERTY);
if (rootIsLaneProperty != null && ((Boolean) rootIsLaneProperty).booleanValue()) {
Graphiti.getGaService().setWidth(ga, context.getWidth());
Graphiti.getGaService().setHeight(ga, context.getHeight());
container = laneShape;
} else {
container = rootContainer;
if (isHorizontal) {
Graphiti.getGaService().setWidth(rootGA, rootGA.getWidth() + dWidth);
} else {
Graphiti.getGaService().setHeight(rootGA, rootGA.getHeight() + dHeight);
}
if (laneShape.equals(rootContainer)) {
Graphiti.getGaService().setLocation(ga, context.getX(), context.getY());
}
}
for (PictogramElement currentChild : BusinessObjectUtil.getChildElementsOfType(container, Lane.class)) {
if (currentChild instanceof ContainerShape) {
ContainerShape currentContainer = (ContainerShape) currentChild;
GraphicsAlgorithm currentGA = currentChild.getGraphicsAlgorithm();
ResizeShapeContext newContext = new ResizeShapeContext(currentContainer);
newContext.setX(currentGA.getX());
newContext.setY(currentGA.getY());
newContext.setWidth(currentGA.getWidth() + dWidth);
newContext.setHeight(currentGA.getHeight() + dHeight);
newContext.setDirection(context.getDirection());
newContext.putProperty(GraphitiConstants.LANE_RESIZE_PROPERTY, true);
resizeShape(newContext);
}
}
}
}
}
}
/**
* This method calculates the minimum size of a container (pool or lane)
* and avoids shrinking the container if child elements are hidden
*/
@Override
protected void preResizeShape(IResizeShapeContext context) {
super.preResizeShape(context);
List<PictogramElement> children = FeatureSupport.getPoolOrLaneChildren((ContainerShape)context.getShape());
Rectangle bounds = GraphicsUtil.getBoundingRectangle(children);
// create an offset of 10px
if (bounds.x>10) {
bounds.x=bounds.x-10;
}
if (bounds.y>10) {
bounds.y=bounds.y-10;
}
bounds.width=bounds.width+20;
bounds.height=bounds.height+20;
// check if the desired dimension is possible
if (bounds.x < context.getX()) {
((ResizeShapeContext)context).setX(bounds.x);
}
if (bounds.y < context.getY()) {
// TODO this is not yet working correctly
((ResizeShapeContext)context).setY(bounds.y);
}
if (bounds.x + bounds.width > context.getWidth()) {
((ResizeShapeContext)context).setWidth(bounds.x + bounds.width);
}
if (bounds.y + bounds.height > context.getHeight()) {
((ResizeShapeContext)context).setHeight(bounds.y + bounds.height);
}
}
private ContainerShape getLowestLane(ContainerShape root, boolean useFirstLane) {
ContainerShape result;
if (useFirstLane) {
result = (ContainerShape) FeatureSupport.getFirstLaneInContainer(root);
} else {
result = (ContainerShape) FeatureSupport.getLastLaneInContainer(root);
}
if (!result.equals(root)) {
return getLowestLane(result, useFirstLane);
}
return result;
}
private int compare(int heightBefore, int widthBefore, int heightAfter,
int widthAfter) {
if (heightAfter > heightBefore || widthAfter > widthBefore) {
return 1;
}
if (heightAfter < heightBefore || widthAfter < widthBefore) {
return -1;
}
return 0;
}
}