/*******************************************************************************
* 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 Bob Brodt
******************************************************************************/
package org.eclipse.bpmn2.modeler.ui.features.choreography;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.bpmn2.Choreography;
import org.eclipse.bpmn2.ChoreographyActivity;
import org.eclipse.bpmn2.Participant;
import org.eclipse.bpmn2.modeler.core.features.choreography.ChoreographyUtil;
import org.eclipse.bpmn2.modeler.core.model.Bpmn2ModelerFactory;
import org.eclipse.bpmn2.modeler.core.utils.FeatureSupport;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.modeler.ui.ImageProvider;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IResizeShapeFeature;
import org.eclipse.graphiti.features.context.IContext;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.context.IResizeShapeContext;
import org.eclipse.graphiti.features.context.impl.ResizeShapeContext;
import org.eclipse.graphiti.features.custom.AbstractCustomFeature;
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;
import org.eclipse.graphiti.ui.internal.util.ui.PopupMenu;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
/**
* @author Bob Brodt
*
*/
public class AddChoreographyParticipantFeature extends AbstractCustomFeature {
protected boolean changesDone = false;
private static ILabelProvider labelProvider = new ILabelProvider() {
public void removeListener(ILabelProviderListener listener) {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {
}
public void addListener(ILabelProviderListener listener) {
}
public String getText(Object element) {
return ((Participant)element).getName();
}
public Image getImage(Object element) {
return null;
}
};
/**
* @param fp
*/
public AddChoreographyParticipantFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public String getName() {
return Messages.AddChoreographyParticipantFeature_Name;
}
@Override
public String getDescription() {
return Messages.AddChoreographyParticipantFeature_Description;
}
@Override
public String getImageId() {
return ImageProvider.IMG_16_ADD_PARTICIPANT;
}
@Override
public boolean isAvailable(IContext context) {
return true;
}
@Override
public boolean canExecute(ICustomContext context) {
PictogramElement[] pes = context.getPictogramElements();
if (pes != null && pes.length == 1) {
PictogramElement pe = pes[0];
Object bo = getBusinessObjectForPictogramElement(pe);
if (bo instanceof ChoreographyActivity) {
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse.graphiti.features.context.ICustomContext)
*/
@Override
public void execute(ICustomContext context) {
PictogramElement[] pes = context.getPictogramElements();
if (pes != null && pes.length == 1) {
PictogramElement pe = pes[0];
ContainerShape choreographyActivityShape = null;
Object bo = getBusinessObjectForPictogramElement(pe);
if (pe instanceof ContainerShape && bo instanceof ChoreographyActivity) {
choreographyActivityShape = (ContainerShape)pe;
ChoreographyActivity choreographyActivity = (ChoreographyActivity)bo;
Participant participant = null;
List<Participant> participantList = new ArrayList<Participant>();
participant = Bpmn2ModelerFactory.createObject(choreographyActivity.eResource(), Participant.class);
participant.setName(Messages.AddChoreographyParticipantFeature_New_Participant);
ModelUtil.setID(participant, choreographyActivity.eResource());
participantList.add(participant);
TreeIterator<EObject> iter = ModelUtil.getDefinitions(choreographyActivity).eAllContents();
while (iter.hasNext()) {
EObject obj = iter.next();
if (obj instanceof Participant && !choreographyActivity.getParticipantRefs().contains(obj))
participantList.add((Participant)obj);
}
Participant result = participant;
if (participantList.size()>1) {
PopupMenu popupMenu = new PopupMenu(participantList, labelProvider);
changesDone = popupMenu.show(Display.getCurrent().getActiveShell());
if (changesDone) {
result = (Participant) popupMenu.getResult();
}
}
else
changesDone = true;
if (changesDone) {
if (result==participant) { // the new one
participant.setName( ModelUtil.toCanonicalString(participant.getId()) );
Choreography choreography = (Choreography)choreographyActivity.eContainer();
choreography.getParticipants().add(result);
/*
Finish this later after we figure out how to deal with multiple BPMNDiagrams and BPMNPlanes
Process process = (Process) PropertyUtil.createObject(task.eResource(), Bpmn2Package.eINSTANCE.getProcess());
// NOTE: this is needed because it fires the InsertionAdapter, which adds the new Process
// to Definitions.rootElements, otherwise the Process would be a dangling object
process.setName(participant.getName()+" Process");
participant.setProcessRef(process);
*/
}
if (choreographyActivity.getInitiatingParticipantRef() == null) {
choreographyActivity.setInitiatingParticipantRef(result);
}
int index = choreographyActivity.getParticipantRefs().size();
if (index>1)
--index;
choreographyActivity.getParticipantRefs().add(index, result);
// if the Choreography Activity is too short to fit all of the Participant Bands
// then we need to resize it first.
List<ContainerShape> bandShapes = FeatureSupport.getParticipantBandContainerShapes(choreographyActivityShape);
int bandHeight = 0;
for (ContainerShape s : bandShapes) {
bandHeight += Graphiti.getGaLayoutService().calculateSize(s.getGraphicsAlgorithm()).getHeight();
}
GraphicsAlgorithm choreographyActivityGA = choreographyActivityShape.getGraphicsAlgorithm();
int containerHeight = choreographyActivityGA.getHeight();
int w = choreographyActivityGA.getWidth();
int x = choreographyActivityGA.getX();
int y = choreographyActivityGA.getY();
if (bandHeight + 100 > containerHeight) {
ResizeShapeContext resizeContext = new ResizeShapeContext(choreographyActivityShape);
resizeContext.setSize(w, bandHeight + 100);
resizeContext.setLocation(x, y);
resizeContext.setDirection(IResizeShapeContext.DIRECTION_SOUTH);
IResizeShapeFeature resizeFeature = getFeatureProvider().getResizeShapeFeature(resizeContext);
resizeFeature.resizeShape(resizeContext);
}
else {
ChoreographyUtil.updateParticipantBands(getFeatureProvider(), choreographyActivityShape);
}
}
}
}
}
@Override
public boolean hasDoneChanges() {
return changesDone;
}
}