| /******************************************************************************* |
| * 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; |
| // } |
| } |