/******************************************************************************* * 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 *******************************************************************************/ package org.eclipse.bpmn2.modeler.core.features; import org.eclipse.bpmn2.BaseElement; import org.eclipse.bpmn2.modeler.core.model.ModelDecorator; import org.eclipse.bpmn2.modeler.core.runtime.CustomTaskImageProvider; import org.eclipse.bpmn2.modeler.core.runtime.CustomTaskImageProvider.IconSize; import org.eclipse.bpmn2.modeler.core.utils.FeatureSupport; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.ecore.EClass; import org.eclipse.graphiti.IExecutionInfo; import org.eclipse.graphiti.features.IAddFeature; import org.eclipse.graphiti.features.ICreateFeature; import org.eclipse.graphiti.features.IDeleteFeature; import org.eclipse.graphiti.features.IDirectEditingFeature; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.ILayoutFeature; import org.eclipse.graphiti.features.IMoveShapeFeature; import org.eclipse.graphiti.features.IRemoveFeature; import org.eclipse.graphiti.features.IResizeShapeFeature; import org.eclipse.graphiti.features.IUpdateFeature; import org.eclipse.graphiti.features.context.IAddContext; import org.eclipse.graphiti.features.context.IAreaContext; import org.eclipse.graphiti.features.context.ICreateContext; import org.eclipse.graphiti.features.context.impl.AddContext; import org.eclipse.graphiti.features.custom.ICustomFeature; import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; import org.eclipse.graphiti.mm.algorithms.Image; import org.eclipse.graphiti.mm.pictograms.ContainerShape; import org.eclipse.graphiti.mm.pictograms.PictogramElement; import org.eclipse.graphiti.services.Graphiti; import org.eclipse.osgi.util.NLS; /** * The Feature Container for Custom Shapes. * <p> * This class must be extended by contributing plug-ins that want to extend any * of the BPMN2 shape elements, e.g. {@link org.eclipse.bpmn2.Task}, {@link org.eclipse.bpmn2.Gateway}, * {@link org.eclipse.bpmn2.Event}, etc. * <p> * See the {@code <customTask>} element of the * {@code org.eclipse.bpmn2.modeler.runtime} extension point. */ public class CustomShapeFeatureContainer extends CustomElementFeatureContainer implements IShapeFeatureContainer { /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getDescription() */ public String getDescription() { if (customTaskDescriptor!=null) return customTaskDescriptor.getDescription(); return Messages.CustomShapeFeatureContainer_Description; } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#createFeatureContainer(org.eclipse.graphiti.features.IFeatureProvider) */ protected IFeatureContainer createFeatureContainer(IFeatureProvider fp) { EClass eClass = (EClass) ModelDecorator.findEClassifier( customTaskDescriptor.getRuntime().getModelDescriptor().getEPackage(), customTaskDescriptor.getType()); return ((IBpmn2FeatureProvider)fp).getFeatureContainer(eClass.getInstanceClass()); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getFeatureContainer(org.eclipse.graphiti.features.IFeatureProvider) */ protected IFeatureContainer getFeatureContainer(IFeatureProvider fp) { if (featureContainerDelegate==null) { featureContainerDelegate = createFeatureContainer(fp); } return featureContainerDelegate; } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IShapeFeatureContainer#getCreateFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public ICreateFeature getCreateFeature(IFeatureProvider fp) { return new CreateCustomShapeFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getAddFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IAddFeature getAddFeature(IFeatureProvider fp) { return new AddCustomShapeFeature(fp); } /** * Base class for Custom Shape Feature construction. * <p> * Custom Connections contributed to the editor <b>MUST</b> subclass this in * their FeatureContainer implementation. * <p> * This class is intended for creation of BPMN2 objects that have custom model * extensions. This is for any object considered to be a "shape", e.g. Activities, * Data Objects, Gateways, Events, etc. * <p> * The creation process copies the modelObject ID string into the Graphiti create * context during the construction phase, then migrates that ID into the created * PictogramElement. This is necessary because the ID must be associated with the * PE to allow our BPMNFeatureProvider to correctly identify the Custom Task. */ public class CreateCustomShapeFeature extends AbstractBpmn2CreateFeature<BaseElement> { /** The create feature delegate. */ protected AbstractBpmn2CreateFeature<BaseElement> createFeatureDelegate; /** Our own copies of create name and description because the ones in super are private **/ protected String name; protected String description; /** * Instantiates a new {@code CreateFeature} for custom shapes. If the * name and/or description are null or empty strings then they are * fetched from the Create Feature delegate when required. * * @param fp the Feature Provider * @param name the name of the element being created * @param description the description of the Create Feature */ @SuppressWarnings({ "unchecked", "rawtypes" }) public CreateCustomShapeFeature(IFeatureProvider fp, String name, String description) { super(fp); IShapeFeatureContainer fc = (IShapeFeatureContainer)getFeatureContainer(fp); createFeatureDelegate = (AbstractBpmn2CreateFeature)fc.getCreateFeature(fp); Assert.isNotNull(createFeatureDelegate); this.name = name; this.description = description; } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2CreateFeature#getCreateName() */ @Override public String getCreateName() { if (name!=null && !name.isEmpty()) return name; return createFeatureDelegate.getCreateName(); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2CreateFeature#getCreateDescription() */ @Override public String getCreateDescription() { if (description!=null && !description.isEmpty()) return description; return createFeatureDelegate.getCreateDescription(); } /** * Alternate constructor. * * @param fp the Feature Provider */ public CreateCustomShapeFeature(IFeatureProvider fp) { this(fp, customTaskDescriptor.getName(), NLS.bind(Messages.CustomElementFeatureContainer_Create, customTaskDescriptor.getName())); } /* (non-Javadoc) * @see org.eclipse.graphiti.features.impl.AbstractFeature#addGraphicalRepresentation(org.eclipse.graphiti.features.context.IAreaContext, java.lang.Object) */ @Override protected PictogramElement addGraphicalRepresentation(IAreaContext context, Object newObject) { // create a new AddContext and copy our ID into it. IAddContext addContext = new AddContext(context, newObject); setId(addContext, getId()); // create the PE and copy our ID into its properties. PictogramElement pe = getFeatureProvider().addIfPossible(addContext); FeatureSupport.setPropertyValue(pe,GraphitiConstants.CUSTOM_ELEMENT_ID,id); return pe; } /* (non-Javadoc) * @see org.eclipse.graphiti.func.ICreate#canCreate(org.eclipse.graphiti.features.context.ICreateContext) */ @Override public boolean canCreate(ICreateContext context) { // copy our ID into the CreateContext - this is where it all starts! setId(context, id); return createFeatureDelegate.canCreate(context); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2CreateFeature#createBusinessObject(org.eclipse.graphiti.features.context.ICreateContext) */ @Override public BaseElement createBusinessObject(ICreateContext context) { BaseElement businessObject = createFeatureDelegate.createBusinessObject(context); return businessObject; } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractCreateFlowElementFeature#getFlowElementClass() */ @Override public EClass getBusinessObjectClass() { return createFeatureDelegate.getBusinessObjectClass(); } /** * This delegates to the CreateFeature implementation defined by the * extension plugin. Note that the create() method of this delegate MUST * return an array of two objects: the first object is the BPMN2 * element, the second object is the ContainerShape that is the * graphical representation of that element. * * @see org.eclipse.graphiti.func.ICreate#create(org.eclipse.graphiti.features.context.ICreateContext) */ @Override public Object[] create(ICreateContext context) { // Our Custom Task ID should have already been set in canCreate() // if not, we have a problem; in other words, canCreate() MUST have // been called by the framework before create() Assert.isNotNull(getId(context)); return createFeatureDelegate.create(context); } /* (non-Javadoc) * @see org.eclipse.graphiti.features.impl.AbstractCreateFeature#getCreateImageId() */ @Override public String getCreateImageId() { String icon = customTaskDescriptor.getIcon(); if (icon!=null) { String id = customTaskDescriptor.getImageId(icon, IconSize.SMALL); if (id!=null) return id; } return createFeatureDelegate.getCreateImageId(); } /* (non-Javadoc) * @see org.eclipse.graphiti.features.impl.AbstractCreateFeature#getCreateLargeImageId() */ @Override public String getCreateLargeImageId() { String icon = customTaskDescriptor.getIcon(); if (icon!=null) { String id = customTaskDescriptor.getImageId(icon, IconSize.LARGE); if (id!=null) return id; } return createFeatureDelegate.getCreateLargeImageId(); } } /** * The {@code AddFeature} base class for creating custom shapes. * <p> * Custom shapes contributed to the editor <b>MUST</b> subclass this in * their FeatureContainer implementation. */ public class AddCustomShapeFeature extends AbstractBpmn2AddFeature<BaseElement> { /** The add feature delegate. */ protected AbstractBpmn2AddFeature<BaseElement> addFeatureDelegate; /** * Instantiates a new {@code AddConnectionFeature} for custom connections. * * @param fp the Feature Provider */ public AddCustomShapeFeature(IFeatureProvider fp) { super(fp); addFeatureDelegate = (AbstractBpmn2AddFeature)getFeatureContainer(fp).getAddFeature(fp); Assert.isNotNull(addFeatureDelegate); } /* (non-Javadoc) * @see org.eclipse.graphiti.func.IAdd#add(org.eclipse.graphiti.features.context.IAddContext) */ @Override public PictogramElement add(IAddContext context) { PictogramElement pe = addFeatureDelegate.add(context); // make sure everyone knows that this PE is a custom task if (pe!=null) FeatureSupport.setPropertyValue(pe,GraphitiConstants.CUSTOM_ELEMENT_ID,getId()); // add an icon to the top-left corner if applicable, and if the implementing // addFeatureDelegate hasn't already done so. String icon = customTaskDescriptor.getIcon(); if (icon!=null && pe instanceof ContainerShape) { boolean addImage = true; ContainerShape containerShape = (ContainerShape)pe; GraphicsAlgorithm ga = (GraphicsAlgorithm)AbstractBpmn2AddFeature.getGraphicsAlgorithm(containerShape); for (PictogramElement child : containerShape.getChildren()) { if (child.getGraphicsAlgorithm() instanceof Image) { addImage = false; break; } } if (ga!=null) { for (GraphicsAlgorithm g : ga.getGraphicsAlgorithmChildren()) { if (g instanceof Image) { addImage = false; break; } } } else addImage = false; if (addImage) { Image img = CustomTaskImageProvider.createImage(customTaskDescriptor, ga, icon, 24, 24); Graphiti.getGaService().setLocationAndSize(img, 2, 2, 24, 24); } } return pe; } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IBpmn2AddFeature#getBusinessObject(org.eclipse.graphiti.features.context.IAddContext) */ @Override public BaseElement getBusinessObject(IAddContext context) { // TODO Auto-generated method stub return addFeatureDelegate.getBusinessObject(context); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IBpmn2AddFeature#putBusinessObject(org.eclipse.graphiti.features.context.IAddContext, org.eclipse.emf.ecore.EObject) */ @Override public void putBusinessObject(IAddContext context, BaseElement businessObject) { addFeatureDelegate.putBusinessObject(context, businessObject); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IBpmn2AddFeature#postExecute(org.eclipse.graphiti.IExecutionInfo) */ @Override public void postExecute(IExecutionInfo executionInfo) { addFeatureDelegate.postExecute(executionInfo); } /* (non-Javadoc) * @see org.eclipse.graphiti.func.IAdd#canAdd(org.eclipse.graphiti.features.context.IAddContext) */ @Override public boolean canAdd(IAddContext context) { return addFeatureDelegate.canAdd(context); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2AddFeature#getAddLabelFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IAddFeature getAddLabelFeature(IFeatureProvider fp) { return addFeatureDelegate.getAddLabelFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2AddFeature#getHeight() */ @Override public int getHeight(IAddContext context) { return addFeatureDelegate.getHeight(context); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2AddFeature#getWidth() */ @Override public int getWidth(IAddContext context) { return addFeatureDelegate.getWidth(context); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.AbstractBpmn2AddFeature#getBusinessObjectType() */ @Override public Class getBusinessObjectType() { return addFeatureDelegate.getBusinessObjectType(); } } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getUpdateFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IUpdateFeature getUpdateFeature(IFeatureProvider fp) { return getFeatureContainer(fp).getUpdateFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getDirectEditingFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IDirectEditingFeature getDirectEditingFeature(IFeatureProvider fp) { return getFeatureContainer(fp).getDirectEditingFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getLayoutFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public ILayoutFeature getLayoutFeature(IFeatureProvider fp) { return getFeatureContainer(fp).getLayoutFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getRemoveFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IRemoveFeature getRemoveFeature(IFeatureProvider fp) { return getFeatureContainer(fp).getRemoveFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IShapeFeatureContainer#getMoveFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IMoveShapeFeature getMoveFeature(IFeatureProvider fp) { IShapeFeatureContainer fc = (IShapeFeatureContainer)getFeatureContainer(fp); return fc.getMoveFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.IShapeFeatureContainer#getResizeFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IResizeShapeFeature getResizeFeature(IFeatureProvider fp) { IShapeFeatureContainer fc = (IShapeFeatureContainer)getFeatureContainer(fp); return fc.getResizeFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getDeleteFeature(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public IDeleteFeature getDeleteFeature(IFeatureProvider fp) { return getFeatureContainer(fp).getDeleteFeature(fp); } /* (non-Javadoc) * @see org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer#getCustomFeatures(org.eclipse.graphiti.features.IFeatureProvider) */ @Override public ICustomFeature[] getCustomFeatures(IFeatureProvider fp) { return getFeatureContainer(fp).getCustomFeatures(fp); } }