blob: 4ae0dbd03c2776089881c69a585328c8efc95dd8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are 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:
* Thomas Schuetz and Henrik Rentz-Reichert (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.ui.behavior.fsm.support;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.etrice.core.fsm.fSM.EntryPoint;
import org.eclipse.etrice.core.fsm.fSM.ExitPoint;
import org.eclipse.etrice.core.fsm.fSM.FSMFactory;
import org.eclipse.etrice.core.fsm.fSM.ModelComponent;
import org.eclipse.etrice.core.fsm.fSM.State;
import org.eclipse.etrice.core.fsm.fSM.StateGraph;
import org.eclipse.etrice.core.fsm.fSM.TrPoint;
import org.eclipse.etrice.core.fsm.fSM.TransitionPoint;
import org.eclipse.etrice.ui.behavior.fsm.dialogs.IFSMDialogFactory;
import org.eclipse.etrice.ui.behavior.fsm.dialogs.ITrPointPropertyDialog;
import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMEditor;
import org.eclipse.etrice.ui.behavior.fsm.editor.DecoratorUtil;
import org.eclipse.etrice.ui.behavior.fsm.provider.IInjectorProvider;
import org.eclipse.etrice.ui.behavior.fsm.provider.ImageProvider;
import org.eclipse.etrice.ui.common.base.support.ChangeAwareCreateFeature;
import org.eclipse.etrice.ui.common.base.support.ChangeAwareCustomFeature;
import org.eclipse.etrice.ui.common.base.support.CommonSupportUtil;
import org.eclipse.etrice.ui.common.base.support.DeleteWithoutConfirmFeature;
import org.eclipse.etrice.ui.common.base.support.NoResizeFeature;
import org.eclipse.graphiti.dt.IDiagramTypeProvider;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.ICreateConnectionFeature;
import org.eclipse.graphiti.features.ICreateFeature;
import org.eclipse.graphiti.features.IDeleteFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IMoveShapeFeature;
import org.eclipse.graphiti.features.IReason;
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.ICreateContext;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.context.IDeleteContext;
import org.eclipse.graphiti.features.context.IDoubleClickContext;
import org.eclipse.graphiti.features.context.ILocationContext;
import org.eclipse.graphiti.features.context.IMoveShapeContext;
import org.eclipse.graphiti.features.context.IPictogramElementContext;
import org.eclipse.graphiti.features.context.IRemoveContext;
import org.eclipse.graphiti.features.context.IResizeShapeContext;
import org.eclipse.graphiti.features.context.ITargetContext;
import org.eclipse.graphiti.features.context.IUpdateContext;
import org.eclipse.graphiti.features.context.impl.AddContext;
import org.eclipse.graphiti.features.context.impl.CreateConnectionContext;
import org.eclipse.graphiti.features.context.impl.RemoveContext;
import org.eclipse.graphiti.features.custom.ICustomFeature;
import org.eclipse.graphiti.features.impl.AbstractAddFeature;
import org.eclipse.graphiti.features.impl.AbstractUpdateFeature;
import org.eclipse.graphiti.features.impl.DefaultMoveShapeFeature;
import org.eclipse.graphiti.features.impl.DefaultRemoveFeature;
import org.eclipse.graphiti.features.impl.Reason;
import org.eclipse.graphiti.mm.algorithms.Ellipse;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.Polygon;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.algorithms.Rectangle;
import org.eclipse.graphiti.mm.algorithms.Text;
import org.eclipse.graphiti.mm.algorithms.styles.Color;
import org.eclipse.graphiti.mm.algorithms.styles.Orientation;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.AnchorContainer;
import org.eclipse.graphiti.mm.pictograms.ChopboxAnchor;
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.IPeCreateService;
import org.eclipse.graphiti.tb.ContextButtonEntry;
import org.eclipse.graphiti.tb.DefaultToolBehaviorProvider;
import org.eclipse.graphiti.tb.IContextButtonPadData;
import org.eclipse.graphiti.tb.IDecorator;
import org.eclipse.graphiti.tb.IToolBehaviorProvider;
import org.eclipse.graphiti.tb.ImageDecorator;
import org.eclipse.graphiti.ui.features.DefaultFeatureProvider;
import org.eclipse.graphiti.util.ColorConstant;
import org.eclipse.graphiti.util.IColorConstant;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import com.google.inject.Injector;
public class TrPointSupport {
public static final int ITEM_SIZE = StateGraphSupport.MARGIN/2;
public static final int ITEM_SIZE_SMALL = (int) (StateSupport.MARGIN*0.375);
public static final int MARGIN = StateGraphSupport.MARGIN;
public static final int MARGIN_SMALL = StateSupport.MARGIN;
protected static final int LINE_WIDTH = 2;
public static final IColorConstant DARK_COLOR = new ColorConstant(0, 0, 0);
public static final IColorConstant INHERITED_COLOR = new ColorConstant(100, 100, 100);
protected static final IColorConstant BRIGHT_COLOR = new ColorConstant(255, 255, 255);
protected static final String PROP_KIND = "item-kind";
enum Type { TRANS_POINT, ENTRY_POINT, EXIT_POINT }
private static class FeatureProvider extends DefaultFeatureProvider {
private static class CreateFeature extends ChangeAwareCreateFeature {
protected Type type;
public CreateFeature(IFeatureProvider fp, Type type, String name, String description) {
super(fp, name, description);
this.type = type;
}
@Override
public String getCreateImageId() {
switch (type) {
case ENTRY_POINT:
return ImageProvider.IMG_ENTRYPOINT;
case EXIT_POINT:
return ImageProvider.IMG_EXITPOINT;
case TRANS_POINT:
return ImageProvider.IMG_TRPOINT;
}
return null;
}
@Override
public Object[] doCreate(ICreateContext context) {
ContainerShape targetContainer = context.getTargetContainer();
ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram());
StateGraph sg = (StateGraph) targetContainer.getLink().getBusinessObjects().get(0);
boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg);
if (inherited) {
sg = FSMSupportUtil.getInstance().insertRefinedState(sg, mc, targetContainer, getFeatureProvider());
}
// create transition point
TrPoint tp = null;
switch (type) {
case ENTRY_POINT:
tp = FSMFactory.eINSTANCE.createEntryPoint();
break;
case EXIT_POINT:
tp = FSMFactory.eINSTANCE.createExitPoint();
break;
case TRANS_POINT:
tp = FSMFactory.eINSTANCE.createTransitionPoint();
break;
}
tp.setName(FSMSupportUtil.getInstance().getFSMUtil().getUniqueTrPointName(sg));
sg.getTrPoints().add(tp);
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector();
IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class);
ITrPointPropertyDialog dlg = factory.createTrPointPropertyDialog(shell, tp, false);
if (dlg.open()==Window.OK) {
// do the add
addGraphicalRepresentation(context, tp);
// return newly created business object(s)
return new Object[] { tp };
}
return null;
}
@Override
public boolean canCreate(ICreateContext context) {
if (context.getTargetContainer().getLink()!=null)
if (context.getTargetContainer().getLink().getBusinessObjects().size()==1) {
EObject obj = context.getTargetContainer().getLink().getBusinessObjects().get(0);
if (obj instanceof StateGraph) {
StateGraph sg = (StateGraph) obj;
if (sg.eContainer() instanceof ModelComponent)
if (type!=Type.TRANS_POINT)
return false;
return isValidPosition(context, context, StateGraphSupport.MARGIN);
}
}
return false;
}
}
private class AddFeature extends AbstractAddFeature {
public AddFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canAdd(IAddContext context) {
if (context.getNewObject() instanceof TrPoint) {
if (context.getTargetContainer().getLink().getBusinessObjects().size()==1) {
EObject obj = context.getTargetContainer().getLink().getBusinessObjects().get(0);
if (obj instanceof StateGraph) {
return true;
}
if (obj instanceof State) {
return true;
}
}
}
return false;
}
@Override
public PictogramElement add(IAddContext context) {
TrPoint tp = (TrPoint) context.getNewObject();
ContainerShape parentShape = context.getTargetContainer();
Object bo = getBusinessObjectForPictogramElement(parentShape);
boolean subtp = (bo instanceof State);
boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), tp);
int margin = subtp?MARGIN_SMALL:MARGIN;
int size = subtp?ITEM_SIZE_SMALL:ITEM_SIZE;
// CONTAINER SHAPE WITH RECTANGLE
IPeCreateService peCreateService = Graphiti.getPeCreateService();
ContainerShape containerShape =
peCreateService.createContainerShape(parentShape, true);
Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.TRP_TYPE);
String kind = getItemKind(tp);
Graphiti.getPeService().setPropertyValue(containerShape, PROP_KIND, kind);
// the context point is the midpoint relative to the invisible rectangle
int x = context.getX();
int y = context.getY();
int width = parentShape.getGraphicsAlgorithm().getWidth();
int height = parentShape.getGraphicsAlgorithm().getHeight();
if (context.getWidth()>0)
x += context.getWidth()/2;
if (context.getHeight()>0)
y += context.getHeight()/2;
{
int dx = (x<=width/2)? x:width-x;
int dy = (y<=height/2)? y:height-y;
if (dx>dy) {
// keep x, project y
if (y<=height/2)
y = margin;
else
y = height-margin;
if (x<margin)
x = margin;
else if (x>width-margin)
x = width-margin;
}
else {
// keep y, project x
if (x<=width/2)
x = margin;
else
x = width-margin;
if (y<margin)
y = margin;
else if (y>height-margin)
y = height-margin;
}
// finally we subtract the midpoint to get coordinates of the upper left corner
x -= margin;
y -= margin;
}
Color dark = manageColor(inherited? INHERITED_COLOR:DARK_COLOR);
IGaService gaService = Graphiti.getGaService();
{
final Rectangle invisibleRectangle = gaService.createInvisibleRectangle(containerShape);
gaService.setLocationAndSize(invisibleRectangle, x, y, 2*margin, 2*margin);
createFigure(tp, subtp,
containerShape,
invisibleRectangle,
dark,
manageColor(BRIGHT_COLOR));
// create link and wire it
link(containerShape, tp);
}
{
Shape labelShape = peCreateService.createShape(containerShape, false);
Text label = gaService.createDefaultText(getDiagram(), labelShape, tp.getName());
label.setForeground(dark);
label.setBackground(dark);
label.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER);
label.setVerticalAlignment(Orientation.ALIGNMENT_CENTER);
gaService.setLocationAndSize(label, 0, margin+size/2, 2*margin, margin/2);
adjustLabel(label, x, y, width, margin, size);
}
if (!subtp)
createParentTP(tp, containerShape, parentShape);
// call the layout feature
layoutPictogramElement(containerShape);
return containerShape;
}
/**
* @param tp
* @param tpShape
* @param subGraphShape
*/
private void createParentTP(TrPoint tp, ContainerShape tpShape, ContainerShape subGraphShape) {
if ((tp instanceof TransitionPoint))
return;
if (!(tp.eContainer().eContainer() instanceof State))
return;
State s = (State) tp.eContainer().eContainer();
List<PictogramElement> elements = Graphiti.getLinkService().getPictogramElements(getDiagram(), s);
if (elements.isEmpty()) {
Object bo = getBusinessObjectForPictogramElement(subGraphShape);
assert(bo instanceof StateGraph): "expected state graph";
assert(((StateGraph)bo).eContainer() instanceof State): "expected state";
s = (State) ((StateGraph)bo).eContainer();
elements = Graphiti.getLinkService().getPictogramElements(getDiagram(), s);
}
if (elements.isEmpty()) {
ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram());
s = FSMSupportUtil.getInstance().getFSMHelpers().getTargettingState(s, mc);
assert(s!=null): "a refined state should point to our parent state";
elements = Graphiti.getLinkService().getPictogramElements(getDiagram(), s);
}
assert(elements.size()==1): "expected unique pe";
assert(elements.get(0) instanceof ContainerShape): "expected state shape";
ContainerShape stateShape = (ContainerShape) elements.get(0);
GraphicsAlgorithm invisibleRect = stateShape.getGraphicsAlgorithm();
GraphicsAlgorithm borderRect = invisibleRect.getGraphicsAlgorithmChildren().get(0);
GraphicsAlgorithm invisibleSubRect = subGraphShape.getGraphicsAlgorithm();
GraphicsAlgorithm borderSubRect = invisibleSubRect.getGraphicsAlgorithmChildren().get(0);
double scaleX = borderRect.getWidth() /(double)borderSubRect.getWidth();
double scaleY = borderRect.getHeight()/(double)borderSubRect.getHeight();
// use midpoint coordinates relative to border rectangle
// result is again in midpoint coordinates relative to the parent border rectangle
int mp = StateGraphSupport.MARGIN+ITEM_SIZE/2;
int x = (int) ((tpShape.getGraphicsAlgorithm().getX()+mp-StateGraphSupport.MARGIN)*scaleX);
int y = (int) ((tpShape.getGraphicsAlgorithm().getY()+mp-StateGraphSupport.MARGIN)*scaleY);
// pass coordinates relative to invisible rectangle
addItem(tp, x+StateSupport.MARGIN, y+StateSupport.MARGIN, stateShape, fp);
}
}
protected class MoveShapeFeature extends DefaultMoveShapeFeature {
public MoveShapeFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canMoveShape(IMoveShapeContext context) {
boolean canMove = super.canMoveShape(context);
if (canMove) {
Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement());
if (bo instanceof TrPoint) {
TrPoint tp = (TrPoint) bo;
if (FSMSupportUtil.getInstance().isInherited(getDiagram(), tp))
return false;
if (isSubTP(context.getPictogramElement()))
return true;
return isValidPosition(context, context, StateGraphSupport.MARGIN);
}
return false;
}
return canMove;
}
@Override
protected void postMoveShape(IMoveShapeContext context) {
ContainerShape shapeToMove = (ContainerShape) context.getShape();
boolean subtp = isSubTP(context.getPictogramElement());
int margin = subtp?MARGIN_SMALL:MARGIN;
int size = subtp?ITEM_SIZE_SMALL:ITEM_SIZE;
int x = context.getX();
int y = context.getY();
int width = context.getTargetContainer().getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
int height = context.getTargetContainer().getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getHeight();
// project onto boundary
{
int dx = (x<=width/2)? x:width-x;
int dy = (y<=height/2)? y:height-y;
if (dx>dy) {
// keep x, project y
if (y<=height/2)
y = 0;
else
y = height-0;
if (x<0)
x = 0;
else if (x>width-0)
x = width-0;
}
else {
// keep y, project x
if (x<=width/2)
x = 0;
else
x = width-0;
if (y<0)
y = 0;
else if (y>height-0)
y = height-0;
}
}
Graphiti.getGaService().setLocation(shapeToMove.getGraphicsAlgorithm(), x, y, avoidNegativeCoordinates());
GraphicsAlgorithm ga = shapeToMove.getChildren().get(0).getGraphicsAlgorithm();
if (ga instanceof Text) {
adjustLabel((Text) ga, x, y, width, margin, size);
}
// as of https://bugs.eclipse.org/bugs/show_bug.cgi?id=347509
// the position of the sub tp shall not be adjusted
// if (!subtp)
// adjustSubTPs(shapeToMove);
}
/**
* @param shapeToMove
*/
@SuppressWarnings("unused")
private void adjustSubTPs(ContainerShape shapeToMove) {
EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(shapeToMove);
if (!(bo instanceof TrPoint)) {
assert(false): "expected TrPoint";
return;
}
if (bo instanceof TransitionPoint)
return;
List<PictogramElement> elements = Graphiti.getLinkService().getPictogramElements(getDiagram(), bo);
if (elements.size()!=2) {
assert(false): "should be this TrPoint and one sub TrPoint";
return;
}
PictogramElement subTpShape = elements.get(0);
if (subTpShape==shapeToMove)
subTpShape = elements.get(1);
// for the coordinate transformation we need the border rectangles of our
// state graph and that of the states state graph which contains the sub tp
GraphicsAlgorithm invisibleRect = shapeToMove.getContainer().getGraphicsAlgorithm();
GraphicsAlgorithm borderRect = invisibleRect.getGraphicsAlgorithmChildren().get(0);
GraphicsAlgorithm invisibleSubRect = ((ContainerShape)subTpShape.eContainer()).getGraphicsAlgorithm();
GraphicsAlgorithm borderSubRect = invisibleSubRect.getGraphicsAlgorithmChildren().get(0);
double scaleX = borderSubRect.getWidth() /(double)borderRect.getWidth();
double scaleY = borderSubRect.getHeight()/(double)borderRect.getHeight();
// transform mid point into target coordinates
int x = (int) (shapeToMove.getGraphicsAlgorithm().getX()*scaleX);
int y = (int) (shapeToMove.getGraphicsAlgorithm().getY()*scaleY);
// mid point relative to border rectangle -> upper left corner relative to invisible rectangle
// (doesn't change anything)
Graphiti.getGaService().setLocation(subTpShape.getGraphicsAlgorithm(), x, y, avoidNegativeCoordinates());
GraphicsAlgorithm ga = ((ContainerShape)subTpShape).getChildren().get(0).getGraphicsAlgorithm();
if (ga instanceof Text) {
adjustLabel((Text) ga, x, y, borderRect.getWidth(), StateGraphSupport.MARGIN, ITEM_SIZE_SMALL);
}
}
}
private static class PropertyFeature extends ChangeAwareCustomFeature {
private String name;
private String description;
public PropertyFeature(IFeatureProvider fp) {
super(fp);
this.name = "Edit Transition Point";
this.description = "Edit Transition Point";
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public boolean canExecute(ICustomContext context) {
PictogramElement[] pes = context.getPictogramElements();
if (pes != null && pes.length == 1 && pes[0] instanceof ContainerShape) {
Object bo = getBusinessObjectForPictogramElement(pes[0]);
if (bo instanceof TrPoint) {
return !FSMSupportUtil.getInstance().isInherited(getDiagram(), (TrPoint) bo);
}
}
return false;
}
@Override
public boolean doExecute(ICustomContext context) {
PictogramElement pe = context.getPictogramElements()[0];
TrPoint tp = (TrPoint) getBusinessObjectForPictogramElement(pe);
boolean subtp = isSubTP(pe);
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector();
IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class);
ITrPointPropertyDialog dlg = factory.createTrPointPropertyDialog(shell, tp, subtp);
if (dlg.open()==Window.OK){
String kind = getItemKind(tp);
Graphiti.getPeService().setPropertyValue(pe, PROP_KIND, kind);
updateTrPointFigure(tp, pe, manageColor(DARK_COLOR), manageColor(BRIGHT_COLOR));
return true;
}
return false;
}
}
private class UpdateFeature extends AbstractUpdateFeature {
public UpdateFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canUpdate(IUpdateContext context) {
Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement());
if (bo instanceof EObject && ((EObject)bo).eIsProxy())
return true;
return bo instanceof TrPoint;
}
@Override
public IReason updateNeeded(IUpdateContext context) {
Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement());
if (bo instanceof EObject && ((EObject)bo).eIsProxy()) {
return Reason.createTrueReason("Transition Point deleted from model");
}
TrPoint tp = (TrPoint) bo;
ContainerShape containerShape = (ContainerShape)context.getPictogramElement();
GraphicsAlgorithm ga = containerShape.getChildren().get(0).getGraphicsAlgorithm();
if (ga instanceof Text) {
if (!tp.getName().equals(((Text)ga).getValue()))
return Reason.createTrueReason("Name is out of date");
String kind = getItemKind(tp);
if (!kind.equals(Graphiti.getPeService().getPropertyValue(context.getPictogramElement(), PROP_KIND)))
return Reason.createTrueReason("Figure is out of date");
}
return Reason.createFalseReason();
}
@Override
public boolean update(IUpdateContext context) {
ContainerShape containerShape = (ContainerShape)context.getPictogramElement();
Object bo = getBusinessObjectForPictogramElement(containerShape);
if (bo instanceof EObject && ((EObject)bo).eIsProxy()) {
IRemoveContext rc = new RemoveContext(containerShape);
IFeatureProvider featureProvider = getFeatureProvider();
IRemoveFeature removeFeature = featureProvider.getRemoveFeature(rc);
if (removeFeature != null) {
removeFeature.remove(rc);
}
EcoreUtil.delete((EObject) bo);
return true;
}
TrPoint tp = (TrPoint) bo;
boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), tp);
Color dark = manageColor(inherited? INHERITED_COLOR:DARK_COLOR);
updateTrPointFigure(tp, containerShape, dark, manageColor(BRIGHT_COLOR));
String kind = getItemKind(tp);
Graphiti.getPeService().setPropertyValue(containerShape, PROP_KIND, kind);
return true;
}
}
protected static class RemoveFeature extends DefaultRemoveFeature {
public RemoveFeature(IFeatureProvider fp) {
super(fp);
}
public boolean canRemove(IRemoveContext context) {
return false;
}
}
protected static class DeleteFeature extends DeleteWithoutConfirmFeature {
public DeleteFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public boolean canDelete(IDeleteContext context) {
if (isSubTP(context.getPictogramElement()))
return false;
ContainerShape containerShape = (ContainerShape) context.getPictogramElement();
TrPoint tp = (TrPoint) getBusinessObjectForPictogramElement(containerShape);
if (FSMSupportUtil.getInstance().isInherited(getDiagram(), tp))
return false;
if (FSMSupportUtil.getInstance().getFSMValidationUtil().isConnectedOutside(tp))
return false;
return true;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.ui.features.DefaultDeleteFeature#preDelete(org.eclipse.graphiti.features.context.IDeleteContext)
*/
@Override
public void preDelete(IDeleteContext context) {
super.preDelete(context);
// remove all associated pictogram elements except the doomed one
IFeatureProvider featureProvider = getFeatureProvider();
EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(context.getPictogramElement());
List<PictogramElement> elements = Graphiti.getLinkService().getPictogramElements(getDiagram(), bo);
for (PictogramElement pe : elements) {
if (pe==context.getPictogramElement())
continue;
IRemoveContext rc = new RemoveContext(pe);
IRemoveFeature removeFeature = featureProvider.getRemoveFeature(rc);
if (removeFeature != null) {
removeFeature.remove(rc);
}
}
// delete connections (inside this state machine since isn't connected outside)
ContainerShape container = (ContainerShape) context.getPictogramElement();
CommonSupportUtil.deleteConnectionsRecursive(container, getFeatureProvider());
}
}
protected IFeatureProvider fp;
protected FeatureProvider(IDiagramTypeProvider dtp, IFeatureProvider fp) {
super(dtp);
this.fp = fp;
}
@Override
public ICreateFeature[] getCreateFeatures() {
return new ICreateFeature[] {
new CreateFeature(fp, Type.TRANS_POINT, "Transition Point", "Create Transition Point"),
new CreateFeature(fp, Type.ENTRY_POINT, "Entry Point", "Create Entry Point"),
new CreateFeature(fp, Type.EXIT_POINT, "Exit Point", "Create Exit Point")
};
}
@Override
public IAddFeature getAddFeature(IAddContext context) {
return new AddFeature(fp);
}
@Override
public IMoveShapeFeature getMoveShapeFeature(IMoveShapeContext context) {
return new MoveShapeFeature(fp);
}
@Override
public IResizeShapeFeature getResizeShapeFeature(IResizeShapeContext context) {
return new NoResizeFeature(fp);
}
@Override
public ICustomFeature[] getCustomFeatures(ICustomContext context) {
PictogramElement pe = context.getPictogramElements()[0];
Object bo = getBusinessObjectForPictogramElement(pe);
ArrayList<ICustomFeature> result = new ArrayList<ICustomFeature>();
result.add(new PropertyFeature(fp));
// Provide quick fix feature only for those edit parts which have
// errors, warnings or infos.
ArrayList<Diagnostic> diagnostics = ((AbstractFSMEditor) getDiagramTypeProvider()
.getDiagramBehavior().getDiagramContainer())
.getDiagnosingModelObserver().getElementDiagonsticMap()
.get(bo);
if (diagnostics != null)
result.add(new QuickFixFeature(fp));
ICustomFeature features[] = new ICustomFeature[result.size()];
return result.toArray(features);
}
@Override
public IUpdateFeature getUpdateFeature(IUpdateContext context) {
return new UpdateFeature(fp);
}
@Override
public IRemoveFeature getRemoveFeature(IRemoveContext context) {
return new RemoveFeature(fp);
}
@Override
public IDeleteFeature getDeleteFeature(IDeleteContext context) {
return new DeleteFeature(fp);
}
protected static void createFigure(TrPoint tp, boolean subtp,
ContainerShape containerShape,
GraphicsAlgorithm invisibleRectangle, Color darkColor, Color brightColor) {
int margin = subtp?MARGIN_SMALL:MARGIN;
int size = subtp?ITEM_SIZE_SMALL:ITEM_SIZE;
int line = subtp?LINE_WIDTH/2:LINE_WIDTH;
IGaService gaService = Graphiti.getGaService();
Ellipse circle = gaService.createEllipse(invisibleRectangle);
circle.setForeground(darkColor);
circle.setBackground(brightColor);
circle.setLineWidth(line);
int s2 = size/2;
int offset = margin-s2;
gaService.setLocationAndSize(circle, offset, offset, size, size);
if (tp instanceof TransitionPoint) {
if (!((TransitionPoint) tp).isHandler())
circle.setBackground(darkColor);
}
else if (tp instanceof ExitPoint) {
int xy[] = new int[] { s2, 0, size, s2, s2, size, 0, s2};
Polygon diamond = gaService.createPolygon(invisibleRectangle, xy);
diamond.setForeground(darkColor);
diamond.setBackground(brightColor);
diamond.setLineWidth(line);
gaService.setLocation(diamond, offset, offset);
}
else if (tp instanceof EntryPoint) {
int sq = (int) (0.707106*s2);
int l1[] = new int[] { margin-sq, margin+sq, margin+sq, margin-sq };
Polyline line1 = gaService.createPolyline(invisibleRectangle, l1);
line1.setLineWidth(line);
line1.setForeground(darkColor);
int l2[] = new int[] { margin-sq, margin-sq, margin+sq, margin+sq };
Polyline line2 = gaService.createPolyline(invisibleRectangle, l2);
line2.setLineWidth(line);
line2.setForeground(darkColor);
}
if (containerShape.getAnchors().isEmpty()) {
// here we place our anchor
IPeCreateService peCreateService = Graphiti.getPeCreateService();
// TODOHRR: EllipseAnchor would be nice
ChopboxAnchor anchor = peCreateService.createChopboxAnchor(containerShape);
anchor.setReferencedGraphicsAlgorithm(circle);
}
else {
// we just set the referenced GA
//containerShape.getAnchors().get(0).setReferencedGraphicsAlgorithm(rect);
}
}
private static void updateTrPointFigure(TrPoint tp, PictogramElement pe, Color dark, Color bright) {
ContainerShape container = (ContainerShape)pe;
// we clear the figure and rebuild it
GraphicsAlgorithm invisibleRect = pe.getGraphicsAlgorithm();
while (!invisibleRect.getGraphicsAlgorithmChildren().isEmpty()) {
EcoreUtil.delete(invisibleRect.getGraphicsAlgorithmChildren().get(0), true);
}
EObject parentObj = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(container.getContainer());
boolean subtp = parentObj instanceof State;
createFigure(tp, subtp, container, invisibleRect, dark, bright);
GraphicsAlgorithm ga = container.getChildren().get(0).getGraphicsAlgorithm();
if (ga instanceof Text) {
((Text)ga).setValue(tp.getName());
}
}
protected static boolean isSubTP(PictogramElement pe) {
if (!(pe instanceof ContainerShape))
return false;
ContainerShape parentShape = ((ContainerShape)pe).getContainer();
EObject parent = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(parentShape);
return (parent instanceof State);
}
protected static boolean isValidPosition(ILocationContext loc, ITargetContext tgt, int margin) {
//System.out.println("isValidPosition "+tgt.getTargetContainer());
if (tgt.getTargetContainer().getGraphicsAlgorithm()==null)
return false;
if (tgt.getTargetContainer().getGraphicsAlgorithm().getGraphicsAlgorithmChildren().isEmpty())
return false;
int x = loc.getX();
int y = loc.getY();
if (loc instanceof ICreateContext) {
// adjust position as relative to border rectangle
x -= margin;
y -= margin;
}
int width = tgt.getTargetContainer().getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getWidth();
int height = tgt.getTargetContainer().getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0).getHeight();
boolean inStripe = false;
// may move in a stripe along the actor class border
int stripe = margin/2;
if (x<=stripe)
inStripe = true;
else if (y<=stripe)
inStripe = true;
else if ((width-stripe)<=x)
inStripe = true;
else if ((height-stripe)<=y)
inStripe = true;
//System.out.println("w:"+width+" h:"+height+" x:"+x+" y:"+y+" in stripe "+inStripe);
return inStripe;
}
protected static String getItemKind(TrPoint item) {
if (item instanceof TransitionPoint) {
return ((TransitionPoint) item).isHandler()? "htp":"tp";
}
else if (item instanceof EntryPoint) {
return "entp";
}
else if (item instanceof ExitPoint) {
return "extp";
}
return "";
}
protected static void adjustLabel(Text label, int x, int y, int width, int margin, int size) {
Orientation halign = Orientation.ALIGNMENT_CENTER;
Orientation valign = Orientation.ALIGNMENT_CENTER;
int pos = 0;
if (x<=margin)
halign = Orientation.ALIGNMENT_LEFT;
else if ((width-margin)<=x)
halign = Orientation.ALIGNMENT_RIGHT;
if (y<=margin) {
pos = 0;
valign = Orientation.ALIGNMENT_BOTTOM;
}
else {
pos = 5*margin/4;
valign = Orientation.ALIGNMENT_TOP;
}
label.setHorizontalAlignment(halign);
label.setVerticalAlignment(valign);
if (pos!=label.getY()) {
IGaService gaService = Graphiti.getGaService();
gaService.setLocationAndSize(label, 0, pos, 2*margin, 3*margin/4);
}
}
}
private class BehaviorProvider extends DefaultToolBehaviorProvider {
public BehaviorProvider(IDiagramTypeProvider dtp) {
super(dtp);
}
@Override
public GraphicsAlgorithm[] getClickArea(PictogramElement pe) {
GraphicsAlgorithm invisible = pe.getGraphicsAlgorithm();
GraphicsAlgorithm rectangle =
invisible.getGraphicsAlgorithmChildren().get(0);
return new GraphicsAlgorithm[] { rectangle };
}
@Override
public GraphicsAlgorithm getSelectionBorder(PictogramElement pe) {
GraphicsAlgorithm invisible = pe.getGraphicsAlgorithm();
GraphicsAlgorithm rectangle =
invisible.getGraphicsAlgorithmChildren().get(0);
return rectangle;
}
@Override
public ICustomFeature getDoubleClickFeature(IDoubleClickContext context) {
return new FeatureProvider.PropertyFeature(getDiagramTypeProvider().getFeatureProvider());
}
@Override
public IContextButtonPadData getContextButtonPad(
IPictogramElementContext context) {
IContextButtonPadData data = super.getContextButtonPad(context);
PictogramElement pe = context.getPictogramElement();
CreateConnectionContext ccc = new CreateConnectionContext();
ccc.setSourcePictogramElement(pe);
Anchor anchor = null;
if (pe instanceof AnchorContainer) {
// our transition point has four fixed point anchor - we choose the first one
anchor = ((ContainerShape)pe).getAnchors().get(0);
}
ccc.setSourceAnchor(anchor);
ContextButtonEntry button = new ContextButtonEntry(null, context);
button.setText("Create Transition");
button.setIconId(ImageProvider.IMG_TRANSITION);
ICreateConnectionFeature[] features = getFeatureProvider().getCreateConnectionFeatures();
for (ICreateConnectionFeature feature : features) {
if (feature.isAvailable(ccc) && feature.canStartConnection(ccc))
button.addDragAndDropFeature(feature);
}
if (button.getDragAndDropFeatures().size() > 0) {
data.getDomainSpecificContextButtons().add(button);
}
return data;
}
/**
* @author jayant
*/
@Override
public IDecorator[] getDecorators(PictogramElement pe) {
// Constants for positioning decorators
GraphicsAlgorithm ga = pe.getGraphicsAlgorithm();
GraphicsAlgorithm port = ga.getGraphicsAlgorithmChildren().get(0);
int xOrigin = port.getX() + 6;
int yOrigin = port.getY() - 6;
int xGap = 0, yGap = 7;
// Get the linked Business Object
EObject bo = Graphiti.getLinkService()
.getBusinessObjectForLinkedPictogramElement(pe);
// Get Diagnostics associated with the business object
ArrayList<Diagnostic> diagnostics = ((AbstractFSMEditor) getDiagramTypeProvider()
.getDiagramBehavior().getDiagramContainer())
.getDiagnosingModelObserver().getElementDiagonsticMap()
.get(bo);
// Form Decorators based on Diagnostics
ArrayList<IDecorator> decorators = DecoratorUtil
.getMarkersFromDiagnostics(diagnostics);
if (decorators.isEmpty())
return super.getDecorators(pe);
else {
int i = 0;
for (IDecorator decorator : decorators) {
((ImageDecorator) decorator).setX(xOrigin + xGap * i);
((ImageDecorator) decorator).setY(yOrigin + yGap * i);
i++;
}
return (IDecorator[]) decorators
.toArray(new IDecorator[decorators.size()]);
}
}
}
private FeatureProvider pfp;
private BehaviorProvider tbp;
public TrPointSupport(IDiagramTypeProvider dtp, IFeatureProvider fp) {
pfp = new FeatureProvider(dtp, fp);
tbp = new BehaviorProvider(dtp);
}
public IFeatureProvider getFeatureProvider() {
return pfp;
}
public IToolBehaviorProvider getToolBehaviorProvider() {
return tbp;
}
private static void addItem(EObject ownObject, int x, int y,
ContainerShape stateShape, IFeatureProvider fp) {
AddContext addContext = new AddContext();
addContext.setNewObject(ownObject);
addContext.setTargetContainer(stateShape);
addContext.setX(x);
addContext.setY(y);
ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext);
assert(pe!=null): "transition point should have been created";
assert(!pe.getAnchors().isEmpty()): "transition point must have an anchor";
}
// private static EObject getOwnObject(EObject obj, ResourceSet rs) {
// URI uri = EcoreUtil.getURI(obj);
// EObject own = rs.getEObject(uri, true);
// assert(own!=null): "own object must exist";
// return own;
// }
}