/*******************************************************************************
* 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.activity.subprocess;
import java.util.Iterator;
import org.eclipse.bpmn2.Activity;
import org.eclipse.bpmn2.CallActivity;
import org.eclipse.bpmn2.CallableElement;
import org.eclipse.bpmn2.GlobalBusinessRuleTask;
import org.eclipse.bpmn2.GlobalManualTask;
import org.eclipse.bpmn2.GlobalScriptTask;
import org.eclipse.bpmn2.GlobalTask;
import org.eclipse.bpmn2.GlobalUserTask;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.modeler.core.ModelHandler;
import org.eclipse.bpmn2.modeler.core.features.AbstractCreateFlowElementFeature;
import org.eclipse.bpmn2.modeler.core.features.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.features.MultiUpdateFeature;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil;
import org.eclipse.bpmn2.modeler.core.utils.StyleUtil;
import org.eclipse.bpmn2.modeler.core.utils.GraphicsUtil.Expand;
import org.eclipse.bpmn2.modeler.ui.ImageProvider;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.ICreateFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.ILayoutFeature;
import org.eclipse.graphiti.features.IReason;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.ICreateContext;
import org.eclipse.graphiti.features.context.IUpdateContext;
import org.eclipse.graphiti.features.impl.AbstractUpdateFeature;
import org.eclipse.graphiti.features.impl.Reason;
import org.eclipse.graphiti.mm.algorithms.Image;
import org.eclipse.graphiti.mm.algorithms.RoundedRectangle;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
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 CallActivityFeatureContainer extends AbstractSubProcessFeatureContainer {
private static final int MARKER_OFFSET = 4;
private static final String CALL_ACTIITY_REF_PROPERTY = "call.activity.ref";
private static final String GLOBAL_TASK_SHAPE_PROPERTY = "global.task.shape";
@Override
public boolean canApplyTo(Object o) {
return super.canApplyTo(o) && o instanceof CallActivity;
}
@Override
public ICreateFeature getCreateFeature(IFeatureProvider fp) {
return new CreateCallActivityFeatureContainer(fp);
}
@Override
public IAddFeature getAddFeature(IFeatureProvider fp) {
return new AddExpandedSubProcessFeature(fp) {
@Override
protected void hook(Activity activity, ContainerShape container, IAddContext context, int width, int height) {
super.hook(activity, container, context, width, height);
CallActivity callActivity = (CallActivity) activity;
Graphiti.getPeService().setPropertyValue(container, CALL_ACTIITY_REF_PROPERTY,
getCallableElementStringValue(callActivity.getCalledElementRef()));
}
@Override
protected void decorateActivityRectangle(RoundedRectangle rect) {
rect.setLineWidth(4);
}
@Override
protected int getMarkerContainerOffset() {
return MARKER_OFFSET;
}
@Override
protected int getWidth() {
return 100;
}
@Override
protected int getHeight() {
return 100;
}
};
}
@Override
public ILayoutFeature getLayoutFeature(IFeatureProvider fp) {
return new SubProcessLayoutFeature(fp) {
@Override
protected int getMarkerContainerOffset() {
return MARKER_OFFSET;
}
};
}
@Override
public MultiUpdateFeature getUpdateFeature(IFeatureProvider fp) {
MultiUpdateFeature multiUpdate = super.getUpdateFeature(fp);
multiUpdate.addUpdateFeature(new UpdateCallActivityFeature(fp));
return multiUpdate;
}
public static class CreateCallActivityFeatureContainer extends AbstractCreateFlowElementFeature<CallActivity> {
public CreateCallActivityFeatureContainer(IFeatureProvider fp) {
super(fp, "Call Activity",
"Identifies a point in the Process where a global Process or a Global Task is used");
}
@Override
protected CallActivity createFlowElement(ICreateContext context) {
CallActivity callActivity = ModelHandler.FACTORY.createCallActivity();
callActivity.setName("Call Activity");
return callActivity;
}
@Override
public String getCreateImageId() {
return ImageProvider.IMG_16_CALL_ACTIVITY;
}
@Override
public String getCreateLargeImageId() {
return getCreateImageId();
}
}
private class UpdateCallActivityFeature extends AbstractUpdateFeature {
public UpdateCallActivityFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canUpdate(IUpdateContext context) {
CallActivity callActivity = BusinessObjectUtil.getFirstElementOfType(context.getPictogramElement(),
CallActivity.class);
return callActivity != null && context.getPictogramElement() instanceof ContainerShape;
}
@Override
public IReason updateNeeded(IUpdateContext context) {
IPeService peService = Graphiti.getPeService();
PictogramElement element = context.getPictogramElement();
String property = peService.getPropertyValue(element, CALL_ACTIITY_REF_PROPERTY);
if (property == null) {
return Reason.createFalseReason();
}
CallActivity callActivity = BusinessObjectUtil.getFirstElementOfType(context.getPictogramElement(),
CallActivity.class);
String value = getCallableElementStringValue(callActivity.getCalledElementRef());
boolean changed = !value.equals(property);
return changed ? Reason.createTrueReason() : Reason.createFalseReason();
}
@Override
public boolean update(IUpdateContext context) {
IPeService peService = Graphiti.getPeService();
IGaService gaService = Graphiti.getGaService();
ContainerShape container = (ContainerShape) context.getPictogramElement();
CallActivity callActivity = BusinessObjectUtil.getFirstElementOfType(context.getPictogramElement(),
CallActivity.class);
ContainerShape markerContainer = (ContainerShape) getShape(container,
GraphicsUtil.ACTIVITY_MARKER_CONTAINER);
Shape globalTaskShape = getShape(container, GLOBAL_TASK_SHAPE_PROPERTY);
if (callActivity.getCalledElementRef() == null) {
GraphicsUtil.clearActivityMarker(markerContainer, GraphicsUtil.ACTIVITY_MARKER_EXPAND);
if (globalTaskShape != null) {
peService.deletePictogramElement(globalTaskShape);
}
}
else if (callActivity.getCalledElementRef() instanceof GlobalTask) {
GraphicsUtil.clearActivityMarker(markerContainer, GraphicsUtil.ACTIVITY_MARKER_EXPAND);
GlobalTask t = (GlobalTask) callActivity.getCalledElementRef();
if (globalTaskShape == null) {
globalTaskShape = peService.createShape(container, false);
peService.setPropertyValue(globalTaskShape, GLOBAL_TASK_SHAPE_PROPERTY, Boolean.toString(true));
}
String imageId = getImageId(t);
if (imageId != null) {
Image image = gaService.createImage(globalTaskShape, imageId);
gaService.setLocationAndSize(image, MARKER_OFFSET + 2, MARKER_OFFSET + 2, 16, 16);
}
}
else if (callActivity.getCalledElementRef() instanceof Process) {
if (globalTaskShape != null) {
peService.deletePictogramElement(globalTaskShape);
}
Expand expand = GraphicsUtil.createActivityMarkerExpand(markerContainer);
expand.rect.setForeground(manageColor(StyleUtil.CLASS_FOREGROUND));
expand.horizontal.setForeground(manageColor(StyleUtil.CLASS_FOREGROUND));
expand.vertical.setForeground(manageColor(StyleUtil.CLASS_FOREGROUND));
}
peService.setPropertyValue(container, CALL_ACTIITY_REF_PROPERTY,
getCallableElementStringValue(callActivity.getCalledElementRef()));
return true;
}
}
private String getCallableElementStringValue(CallableElement element) {
if (element == null) {
return "null";
}
return element.getClass().getSimpleName();
}
private String getImageId(GlobalTask task) {
if (task instanceof GlobalBusinessRuleTask) {
return ImageProvider.IMG_16_BUSINESS_RULE_TASK;
} else if (task instanceof GlobalManualTask) {
return ImageProvider.IMG_16_MANUAL_TASK;
} else if (task instanceof GlobalScriptTask) {
return ImageProvider.IMG_16_SCRIPT_TASK;
} else if (task instanceof GlobalUserTask) {
return ImageProvider.IMG_16_USER_TASK;
} else {
return null;
}
}
private Shape getShape(ContainerShape container, String propertyKey) {
IPeService peService = Graphiti.getPeService();
Iterator<Shape> iterator = peService.getAllContainedShapes(container).iterator();
while (iterator.hasNext()) {
Shape shape = iterator.next();
String property = peService.getPropertyValue(shape, propertyKey);
if (property != null && new Boolean(property)) {
return shape;
}
}
return null;
}
}