| /******************************************************************************* |
| * 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 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.CPBranchTransition; |
| import org.eclipse.etrice.core.fsm.fSM.ChoicepointTerminal; |
| import org.eclipse.etrice.core.fsm.fSM.ContinuationTransition; |
| import org.eclipse.etrice.core.fsm.fSM.DetailCode; |
| import org.eclipse.etrice.core.fsm.fSM.EntryPoint; |
| import org.eclipse.etrice.core.fsm.fSM.FSMFactory; |
| import org.eclipse.etrice.core.fsm.fSM.GuardedTransition; |
| import org.eclipse.etrice.core.fsm.fSM.InitialTransition; |
| import org.eclipse.etrice.core.fsm.fSM.ModelComponent; |
| import org.eclipse.etrice.core.fsm.fSM.NonInitialTransition; |
| import org.eclipse.etrice.core.fsm.fSM.RefinedTransition; |
| import org.eclipse.etrice.core.fsm.fSM.StateGraph; |
| import org.eclipse.etrice.core.fsm.fSM.SubStateTrPointTerminal; |
| import org.eclipse.etrice.core.fsm.fSM.TrPointTerminal; |
| import org.eclipse.etrice.core.fsm.fSM.Transition; |
| import org.eclipse.etrice.core.fsm.fSM.TransitionChainStartTransition; |
| import org.eclipse.etrice.core.fsm.fSM.TransitionTerminal; |
| import org.eclipse.etrice.core.fsm.fSM.TriggeredTransition; |
| import org.eclipse.etrice.ui.behavior.fsm.dialogs.IFSMDialogFactory; |
| import org.eclipse.etrice.ui.behavior.fsm.dialogs.ITransitionPropertyDialog; |
| 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.UIBaseActivator; |
| import org.eclipse.etrice.ui.common.base.preferences.UIBasePreferenceConstants; |
| import org.eclipse.etrice.ui.common.base.support.CantRemoveFeature; |
| import org.eclipse.etrice.ui.common.base.support.ChangeAwareCreateConnectionFeature; |
| import org.eclipse.etrice.ui.common.base.support.ChangeAwareCustomFeature; |
| import org.eclipse.etrice.ui.common.base.support.DeleteWithoutConfirmFeature; |
| import org.eclipse.graphiti.datatypes.ILocation; |
| import org.eclipse.graphiti.dt.IDiagramTypeProvider; |
| import org.eclipse.graphiti.features.IAddFeature; |
| import org.eclipse.graphiti.features.ICreateConnectionFeature; |
| import org.eclipse.graphiti.features.IDeleteFeature; |
| import org.eclipse.graphiti.features.IFeatureProvider; |
| import org.eclipse.graphiti.features.IReason; |
| import org.eclipse.graphiti.features.IReconnectionFeature; |
| import org.eclipse.graphiti.features.IRemoveFeature; |
| import org.eclipse.graphiti.features.IUpdateFeature; |
| import org.eclipse.graphiti.features.context.IAddConnectionContext; |
| import org.eclipse.graphiti.features.context.IAddContext; |
| import org.eclipse.graphiti.features.context.ICreateConnectionContext; |
| 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.IReconnectionContext; |
| import org.eclipse.graphiti.features.context.IRemoveContext; |
| import org.eclipse.graphiti.features.context.IUpdateContext; |
| import org.eclipse.graphiti.features.context.impl.AddConnectionContext; |
| import org.eclipse.graphiti.features.context.impl.ReconnectionContext; |
| import org.eclipse.graphiti.features.context.impl.RemoveContext; |
| import org.eclipse.graphiti.features.custom.AbstractCustomFeature; |
| 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.DefaultReconnectionFeature; |
| import org.eclipse.graphiti.features.impl.Reason; |
| import org.eclipse.graphiti.mm.GraphicsAlgorithmContainer; |
| 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.Text; |
| import org.eclipse.graphiti.mm.algorithms.styles.Color; |
| import org.eclipse.graphiti.mm.algorithms.styles.Point; |
| import org.eclipse.graphiti.mm.pictograms.Anchor; |
| import org.eclipse.graphiti.mm.pictograms.Connection; |
| import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator; |
| import org.eclipse.graphiti.mm.pictograms.ContainerShape; |
| import org.eclipse.graphiti.mm.pictograms.FreeFormConnection; |
| import org.eclipse.graphiti.mm.pictograms.PictogramElement; |
| import org.eclipse.graphiti.services.Graphiti; |
| import org.eclipse.graphiti.services.IGaService; |
| import org.eclipse.graphiti.services.IPeCreateService; |
| import org.eclipse.graphiti.tb.DefaultToolBehaviorProvider; |
| 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.dialogs.MessageDialog; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.xtext.util.Strings; |
| import org.eclipse.xtext.xbase.lib.Pair; |
| |
| import com.google.inject.Injector; |
| |
| public class TransitionSupport { |
| |
| private static final IColorConstant LINE_COLOR = new ColorConstant(0, 0, 0); |
| private static final IColorConstant INHERITED_COLOR = new ColorConstant(100, 100, 100); |
| private static final IColorConstant FILL_COLOR = new ColorConstant(255, 255, 255); |
| private static final int LINE_WIDTH = 1; |
| private static final String newLine = Strings.newLine(); |
| private static final int newLineLength = Strings.newLine().length(); |
| |
| static class FeatureProvider extends DefaultFeatureProvider { |
| |
| private class CreateFeature extends ChangeAwareCreateConnectionFeature { |
| |
| public CreateFeature(IFeatureProvider fp) { |
| super(fp, "Transition", "create Transition"); |
| } |
| |
| @Override |
| public String getCreateImageId() { |
| return ImageProvider.IMG_TRANSITION; |
| } |
| |
| @Override |
| public boolean canCreate(ICreateConnectionContext context) { |
| return FSMSupportUtil.getInstance().canConnect( |
| context.getSourceAnchor(), |
| context.getTargetAnchor(), |
| (ContainerShape)context.getSourcePictogramElement().eContainer(), fp); |
| } |
| |
| public boolean canStartConnection(ICreateConnectionContext context) { |
| TransitionTerminal src = FSMSupportUtil.getInstance().getTransitionTerminal(context.getSourceAnchor(), fp); |
| if (src==null && !FSMSupportUtil.getInstance().isInitialPoint(context.getSourceAnchor(), fp)) |
| return false; |
| |
| StateGraph sg = FSMSupportUtil.getInstance().getStateGraph((ContainerShape) context.getSourcePictogramElement().eContainer(), fp); |
| if (sg==null) |
| return false; |
| |
| return FSMSupportUtil.getInstance().getFSMValidationUtil().isConnectable(src, sg).isOk(); |
| } |
| |
| @Override |
| public Connection doCreate(ICreateConnectionContext context) { |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); |
| |
| TransitionTerminal src = FSMSupportUtil.getInstance().getTransitionTerminal(context.getSourceAnchor(), fp); |
| TransitionTerminal dst = FSMSupportUtil.getInstance().getTransitionTerminal(context.getTargetAnchor(), fp); |
| StateGraph sg = FSMSupportUtil.getInstance().getStateGraph((ContainerShape) context.getSourcePictogramElement().eContainer(), fp); |
| if (dst!=null && sg!=null) { |
| |
| // TODOHRR-B transition dialog |
| // allow switch between default and non-default CP branch? This would change the transition type |
| |
| Transition trans = null; |
| if (src==null) { |
| InitialTransition t = FSMFactory.eINSTANCE.createInitialTransition(); |
| t.setTo(dst); |
| trans = t; |
| } |
| else if (src instanceof SubStateTrPointTerminal |
| || (src instanceof TrPointTerminal && ((TrPointTerminal)src).getTrPoint() instanceof EntryPoint)) { |
| ContinuationTransition t = FSMFactory.eINSTANCE.createContinuationTransition(); |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| else if (src instanceof ChoicepointTerminal) { |
| boolean dfltBranch = true; |
| for (Transition tr : FSMSupportUtil.getInstance().getFSMHelpers().getAllTransitions(sg)) { |
| if (tr instanceof ContinuationTransition) { |
| TransitionTerminal from = ((ContinuationTransition) tr).getFrom(); |
| if (from instanceof ChoicepointTerminal) { |
| if (((ChoicepointTerminal) from).getCp()==((ChoicepointTerminal)src).getCp()) |
| dfltBranch = false; |
| } |
| } |
| } |
| NonInitialTransition t = dfltBranch? FSMFactory.eINSTANCE.createContinuationTransition() |
| : FSMFactory.eINSTANCE.createCPBranchTransition(); |
| |
| if (t instanceof CPBranchTransition) { |
| DetailCode dc = FSMFactory.eINSTANCE.createDetailCode(); |
| dc.setUsed(false); |
| ((CPBranchTransition) t).setCondition(dc); |
| } |
| |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| else { |
| NonInitialTransition t = null; |
| switch (mc.getCommType()) { |
| case DATA_DRIVEN: |
| t = FSMFactory.eINSTANCE.createGuardedTransition(); |
| break; |
| case ASYNCHRONOUS: |
| // let user choose between triggered and guarded transition |
| Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| MessageDialog dlg = new MessageDialog( |
| shell, |
| "Create new transition", |
| null, // accept the default window icon |
| "Select the kind of transition", |
| MessageDialog.QUESTION, |
| new String[] { |
| "triggered", |
| "guarded" |
| }, |
| 0 // default button index |
| ); |
| |
| switch (dlg.open()) { // open returns index of pressed button |
| case 0: |
| t = FSMFactory.eINSTANCE.createTriggeredTransition(); |
| break; |
| case 1: |
| t = FSMFactory.eINSTANCE.createGuardedTransition(); |
| break; |
| } |
| break; |
| case EVENT_DRIVEN: |
| t = FSMFactory.eINSTANCE.createTriggeredTransition(); |
| break; |
| case SYNCHRONOUS: |
| break; |
| default: |
| break; |
| } |
| if (t==null) |
| return null; |
| |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| |
| if (trans instanceof InitialTransition) { |
| trans.setName(FSMSupportUtil.getInstance().getFSMUtil().getUniqueInitialTransitionName(sg)); |
| } |
| else { |
| trans.setName(FSMSupportUtil.getInstance().getFSMUtil().getUniqueTransitionName(sg)); |
| } |
| |
| ContainerShape targetContainer = FSMSupportUtil.getInstance().getStateGraphContainer((ContainerShape) context.getSourcePictogramElement().eContainer()); |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); |
| if (inherited) { |
| sg = FSMSupportUtil.getInstance().insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); |
| } |
| |
| sg.getTransitions().add(trans); |
| |
| Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); |
| IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class); |
| ITransitionPropertyDialog dlg = factory.createTransitionPropertyDialog(shell, FSMSupportUtil.getInstance().getModelComponent(getDiagram()), trans); |
| if (dlg.open()==Window.OK) { |
| AddConnectionContext addContext = new AddConnectionContext(context.getSourceAnchor(), context.getTargetAnchor()); |
| addContext.setNewObject(trans); |
| return (Connection) getFeatureProvider().addIfPossible(addContext); |
| } |
| } |
| |
| return null; |
| } |
| } |
| |
| private class AddFeature extends AbstractAddFeature { |
| |
| public AddFeature(IFeatureProvider fp) { |
| super(fp); |
| } |
| |
| @Override |
| public boolean canAdd(IAddContext context) { |
| if (context instanceof IAddConnectionContext && context.getNewObject() instanceof Transition) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public PictogramElement add(IAddContext context) { |
| IAddConnectionContext addConContext = (IAddConnectionContext) context; |
| Transition trans = (Transition) context.getNewObject(); |
| |
| // a transition target can not be the initial point (which has a StateGraph associated) |
| // so we use the target anchor to determine the StateGraph container |
| ContainerShape container = ((ContainerShape) addConContext.getTargetAnchor().getParent()).getContainer(); |
| Object bo = getBusinessObjectForPictogramElement(container); |
| if (!(bo instanceof StateGraph)) |
| container = container.getContainer(); |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(trans, container); |
| |
| IPeCreateService peCreateService = Graphiti.getPeCreateService(); |
| FreeFormConnection connection = peCreateService.createFreeFormConnection(getDiagram()); |
| connection.setStart(addConContext.getSourceAnchor()); |
| connection.setEnd(addConContext.getTargetAnchor()); |
| |
| if (addConContext.getSourceAnchor()==addConContext.getTargetAnchor()) { |
| Point pt = createSelfTransitionBendPoint(connection); |
| connection.getBendpoints().add(pt); |
| } |
| |
| Graphiti.getPeService().setPropertyValue(connection, Constants.TYPE_KEY, Constants.TRANS_TYPE); |
| |
| IGaService gaService = Graphiti.getGaService(); |
| Polyline polyline = gaService.createPolyline(connection); |
| Color lineColor = manageColor(inherited?INHERITED_COLOR:LINE_COLOR); |
| polyline.setForeground(lineColor); |
| polyline.setLineWidth(LINE_WIDTH); |
| |
| ConnectionDecorator cd = peCreateService |
| .createConnectionDecorator(connection, false, 1.0, true); |
| Color fillColor = FSMSupportUtil.getInstance().getFSMHelpers().hasDetailCode(trans.getAction())? |
| lineColor:manageColor(FILL_COLOR); |
| createArrow(cd, lineColor, fillColor); |
| |
| ConnectionDecorator textDecorator = |
| peCreateService.createConnectionDecorator(connection, true, |
| 0.5, true); |
| Text text = gaService.createDefaultText(getDiagram(), textDecorator, getLabel(trans)); |
| text.setForeground(lineColor); |
| gaService.setLocation(text, 10, 0); |
| |
| |
| // create link and wire it |
| link(connection, trans); |
| |
| return connection; |
| } |
| |
| private Point createSelfTransitionBendPoint(FreeFormConnection connection) { |
| ILocation begin = Graphiti.getPeService().getLocationRelativeToDiagram(connection.getStart()); |
| |
| // TODOHRR: algorithm to determine self transition bend point position |
| int deltaX = 0; |
| int deltaY = StateGraphSupport.MARGIN*3; |
| |
| return Graphiti.getGaService().createPoint(begin.getX()+deltaX, begin.getY()+deltaY); |
| } |
| |
| private Polyline createArrow(GraphicsAlgorithmContainer gaContainer, Color lineColor, Color fillColor) { |
| |
| IGaService gaService = Graphiti.getGaService(); |
| Polygon polygon = |
| gaService.createPolygon(gaContainer, new int[] { -15, 5, 0, 0, -15, -5 }); |
| |
| polygon.setForeground(lineColor); |
| polygon.setBackground(fillColor); |
| polygon.setLineWidth(LINE_WIDTH); |
| |
| return polygon; |
| } |
| |
| } |
| |
| private class ReconnectionFeature extends DefaultReconnectionFeature { |
| |
| private boolean doneChanges = false; |
| |
| public ReconnectionFeature(IFeatureProvider fp) { |
| super(fp); |
| } |
| |
| @Override |
| public boolean canReconnect(IReconnectionContext context) { |
| if (!super.canReconnect(context)) |
| return false; |
| |
| Transition trans = (Transition) getBusinessObjectForPictogramElement(context.getConnection()); |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), trans); |
| if (inherited) |
| return false; |
| |
| Anchor src = context.getConnection().getStart(); |
| Anchor tgt = context.getConnection().getEnd(); |
| if (context.getReconnectType().equals(ReconnectionContext.RECONNECT_SOURCE)) |
| src = context.getNewAnchor(); |
| else |
| tgt = context.getNewAnchor(); |
| |
| return FSMSupportUtil.getInstance().canConnect(src, tgt, trans, (ContainerShape) context.getTargetPictogramElement().eContainer(), fp); |
| } |
| |
| @Override |
| public void postReconnect(IReconnectionContext context) { |
| super.postReconnect(context); |
| |
| TransitionTerminal src = FSMSupportUtil.getInstance().getTransitionTerminal(context.getConnection().getStart(), fp); |
| TransitionTerminal dst = FSMSupportUtil.getInstance().getTransitionTerminal(context.getConnection().getEnd(), fp); |
| StateGraph sg = FSMSupportUtil.getInstance().getStateGraph((ContainerShape) context.getTargetPictogramElement().eContainer(), fp); |
| |
| // in the following we set source and target of the connection regardless of whether they have changed |
| // if the type of the transition changed we create a new one and open the property dialog |
| |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); |
| Transition orig = (Transition) getBusinessObjectForPictogramElement(context.getConnection()); |
| Transition trans = null; |
| if (src==null) { |
| InitialTransition t = (orig instanceof InitialTransition)? |
| (InitialTransition)orig : FSMFactory.eINSTANCE.createInitialTransition(); |
| t.setTo(dst); |
| trans = t; |
| } |
| else if (src instanceof SubStateTrPointTerminal |
| || (src instanceof TrPointTerminal && ((TrPointTerminal)src).getTrPoint() instanceof EntryPoint)) { |
| ContinuationTransition t = (orig instanceof ContinuationTransition)? |
| (ContinuationTransition)orig : FSMFactory.eINSTANCE.createContinuationTransition(); |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| else if (src instanceof ChoicepointTerminal) { |
| NonInitialTransition t = null; |
| if (context.getReconnectType().equals(ReconnectionContext.RECONNECT_SOURCE)) { |
| boolean dfltBranch = true; |
| for (Transition tr : FSMSupportUtil.getInstance().getFSMHelpers().getAllTransitions(sg)) { |
| if (tr instanceof ContinuationTransition) { |
| TransitionTerminal from = ((ContinuationTransition) tr).getFrom(); |
| if (from instanceof ChoicepointTerminal) { |
| if (((ChoicepointTerminal) from).getCp()==((ChoicepointTerminal)src).getCp()) |
| dfltBranch = false; |
| } |
| } |
| } |
| t = dfltBranch? FSMFactory.eINSTANCE.createContinuationTransition() |
| : FSMFactory.eINSTANCE.createCPBranchTransition(); |
| } |
| else |
| t = (NonInitialTransition) orig; |
| |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| else { |
| TransitionChainStartTransition t = null; |
| switch(mc.getCommType()){ |
| case EVENT_DRIVEN: |
| if(orig instanceof TriggeredTransition) |
| t = (TransitionChainStartTransition) orig; |
| else |
| t = FSMFactory.eINSTANCE.createTriggeredTransition(); |
| break; |
| case DATA_DRIVEN: |
| if(orig instanceof GuardedTransition) |
| t = (TransitionChainStartTransition) orig; |
| else |
| t = FSMFactory.eINSTANCE.createGuardedTransition(); |
| break; |
| case ASYNCHRONOUS: |
| if(orig instanceof TriggeredTransition || orig instanceof GuardedTransition ) |
| t = (TransitionChainStartTransition) orig; |
| else { |
| // let user choose between triggered and guarded transition |
| Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| MessageDialog dlg = new MessageDialog( |
| shell, |
| "Create new transition", |
| null, // accept the default window icon |
| "Select the kind of transition", |
| MessageDialog.QUESTION, |
| new String[] { |
| "triggered", |
| "guarded" |
| }, |
| 0 // default button index |
| ); |
| |
| switch (dlg.open()) { // open returns index of pressed button |
| case 0: |
| t = FSMFactory.eINSTANCE.createTriggeredTransition(); |
| break; |
| case 1: |
| t = FSMFactory.eINSTANCE.createGuardedTransition(); |
| break; |
| } |
| } |
| break; |
| case SYNCHRONOUS: |
| break; |
| default: |
| break; |
| } |
| |
| t.setFrom(src); |
| t.setTo(dst); |
| trans = t; |
| } |
| |
| if (orig!=trans) { |
| if (trans instanceof InitialTransition) { |
| trans.setName("init"); |
| } |
| else { |
| trans.setName(orig.getName()); |
| } |
| |
| trans.setAction(orig.getAction()); |
| trans.setName(orig.getName()); |
| |
| sg.getTransitions().remove(orig); |
| sg.getTransitions().add(trans); |
| |
| Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); |
| IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class); |
| ITransitionPropertyDialog dlg = factory.createTransitionPropertyDialog(shell, mc, trans); |
| if (dlg.open()!=Window.OK) { |
| sg.getTransitions().add(orig); |
| sg.getTransitions().remove(trans); |
| if (context.getNewAnchor()==context.getConnection().getStart()) |
| context.getConnection().setStart(context.getOldAnchor()); |
| else |
| context.getConnection().setEnd(context.getOldAnchor()); |
| return; |
| } |
| |
| link(context.getConnection(), trans); |
| } |
| |
| doneChanges = true; |
| Color fillColor = FSMSupportUtil.getInstance().getFSMHelpers().hasDetailCode(trans.getAction())? |
| manageColor(LINE_COLOR):manageColor(FILL_COLOR); |
| updateLabel(trans, context.getConnection(), fillColor); |
| } |
| |
| @Override |
| public boolean hasDoneChanges() { |
| return doneChanges; |
| } |
| } |
| |
| 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; |
| |
| if (bo instanceof Transition) |
| return true; |
| |
| return false; |
| } |
| |
| @Override |
| public IReason updateNeeded(IUpdateContext context) { |
| Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); |
| if (bo instanceof EObject && ((EObject)bo).eIsProxy()) { |
| return Reason.createTrueReason("Transition deleted from model"); |
| } |
| |
| if (bo instanceof Transition) { |
| Transition t = (Transition) bo; |
| Connection conn = (Connection)context.getPictogramElement(); |
| if (conn.getConnectionDecorators().size()>=2) { |
| ConnectionDecorator cd = conn.getConnectionDecorators().get(0); |
| if (cd.getGraphicsAlgorithm() instanceof Polygon) { |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), t); |
| Color lineColor = inherited? manageColor(INHERITED_COLOR):manageColor(LINE_COLOR); |
| boolean hasActionCode = FSMSupportUtil.getInstance().getFSMHelpers().hasActionCode(t, mc); |
| Color fillColor = hasActionCode? lineColor : manageColor(FILL_COLOR); |
| if (!equal(cd.getGraphicsAlgorithm().getBackground(), fillColor)) |
| return Reason.createTrueReason("Arrow head needs update"); |
| } |
| cd = conn.getConnectionDecorators().get(1); |
| if (cd.getGraphicsAlgorithm() instanceof Text) { |
| Text label = (Text) cd.getGraphicsAlgorithm(); |
| if (!label.getValue().equals(getLabel(t))) |
| return Reason.createTrueReason("Label needs update"); |
| } |
| } |
| } |
| |
| return Reason.createFalseReason(); |
| } |
| |
| private boolean equal(Color c1, Color c2) { |
| return c1.getRed()==c2.getRed() && c1.getGreen()==c2.getGreen() && c1.getBlue()==c2.getBlue(); |
| } |
| |
| @Override |
| public boolean update(IUpdateContext context) { |
| Connection containerShape = (Connection)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; |
| } |
| |
| boolean updated = false; |
| |
| if (bo instanceof Transition) { |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); |
| Transition trans = (Transition) bo; |
| Connection conn = (Connection)context.getPictogramElement(); |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), trans); |
| Color lineColor = inherited? manageColor(INHERITED_COLOR):manageColor(LINE_COLOR); |
| boolean hasActionCode = FSMSupportUtil.getInstance().getFSMHelpers().hasActionCode(trans, mc); |
| Color fillColor = hasActionCode? lineColor : manageColor(FILL_COLOR); |
| updateLabel(trans, conn, fillColor); |
| updated = true; |
| if (updateNeeded(context).toBoolean()) |
| updated = false; |
| } |
| |
| return updated; |
| } |
| } |
| |
| private static class PropertyFeature extends ChangeAwareCustomFeature { |
| |
| private boolean editable; |
| |
| public PropertyFeature(IFeatureProvider fp, boolean editable) { |
| super(fp); |
| this.editable = editable; |
| } |
| |
| @Override |
| public String getName() { |
| return editable? "Edit Transition..." : "View Transition"; |
| } |
| |
| @Override |
| public String getDescription() { |
| return editable? "Edit Transition Properties" : "View Transition Properties"; |
| } |
| |
| private Pair<Connection, Transition> getTransition(ICustomContext context) { |
| PictogramElement[] pes = context.getPictogramElements(); |
| if (pes != null && pes.length == 1) { |
| PictogramElement pe = pes[0]; |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| if (!(pe instanceof Connection)) |
| return null; |
| |
| Object bo = getBusinessObjectForPictogramElement(pe); |
| if (bo instanceof Transition) { |
| return new Pair<Connection, Transition>((Connection) pe, (Transition) bo); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean canExecute(ICustomContext context) { |
| return getTransition(context)!=null; |
| } |
| |
| @Override |
| public boolean doExecute(ICustomContext context) { |
| Pair<Connection, Transition> pair = getTransition(context); |
| Transition trans = pair.getValue(); |
| Connection conn = pair.getKey(); |
| |
| Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); |
| Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); |
| IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class); |
| ITransitionPropertyDialog dlg = factory.createTransitionPropertyDialog(shell, FSMSupportUtil.getInstance().getModelComponent(getDiagram()), trans); |
| if (dlg.open()==Window.OK){ |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), trans); |
| Color lineColor = inherited? manageColor(INHERITED_COLOR):manageColor(LINE_COLOR); |
| Color fillColor = FSMSupportUtil.getInstance().getFSMHelpers().hasDetailCode(trans.getAction())? |
| lineColor:manageColor(FILL_COLOR); |
| updateLabel(trans, conn, fillColor); |
| |
| return true; |
| } |
| |
| return false; |
| } |
| } |
| |
| private static class RefineTransitionFeature extends AbstractCustomFeature { |
| |
| /** |
| * @param fp |
| */ |
| public RefineTransitionFeature(IFeatureProvider fp) { |
| super(fp); |
| } |
| |
| @Override |
| public String getName() { |
| return "Refine Transition"; |
| } |
| |
| @Override |
| public String getDescription() { |
| return "Refine transition to add action code"; |
| } |
| |
| @Override |
| public boolean canExecute(ICustomContext context) { |
| PictogramElement[] pes = context.getPictogramElements(); |
| if (pes != null && pes.length == 1) { |
| PictogramElement pe = pes[0]; |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| if (!(pe instanceof Connection)) |
| return false; |
| |
| Object bo = getBusinessObjectForPictogramElement(pe); |
| if (bo instanceof Transition) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public void execute(ICustomContext context) { |
| PictogramElement pe = context.getPictogramElements()[0]; |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| Transition trans = (Transition) getBusinessObjectForPictogramElement(pe); |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); |
| if (mc.getStateMachine()==null) |
| mc.setStateMachine(FSMFactory.eINSTANCE.createStateGraph()); |
| |
| RefinedTransition rt = FSMFactory.eINSTANCE.createRefinedTransition(); |
| rt.setTarget(trans); |
| mc.getStateMachine().getRefinedTransitions().add(rt); |
| // the connection pe is still linked to the former transition that was refined! |
| |
| ICustomFeature[] features = getFeatureProvider().getCustomFeatures(context); |
| for (ICustomFeature cf : features) { |
| if (cf instanceof PropertyFeature) { |
| cf.execute(context); |
| break; |
| } |
| } |
| } |
| |
| } |
| |
| protected static class DeleteFeature extends DeleteWithoutConfirmFeature { |
| |
| public DeleteFeature(IFeatureProvider fp) { |
| super(fp); |
| } |
| |
| @Override |
| public boolean canDelete(IDeleteContext context) { |
| PictogramElement pe = context.getPictogramElement(); |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| if (!(pe instanceof Connection)) |
| return false; |
| |
| Object bo = getBusinessObjectForPictogramElement(pe); |
| if (bo instanceof Transition) { |
| boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), (Transition) bo); |
| if (inherited) |
| return false; |
| |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| private IFeatureProvider fp; |
| |
| public FeatureProvider(IDiagramTypeProvider dtp, IFeatureProvider fp) { |
| super(dtp); |
| this.fp = fp; |
| } |
| |
| @Override |
| public ICreateConnectionFeature[] getCreateConnectionFeatures() { |
| return new ICreateConnectionFeature[] { new CreateFeature(fp) }; |
| } |
| |
| @Override |
| public IAddFeature getAddFeature(IAddContext context) { |
| return new AddFeature(fp); |
| } |
| |
| @Override |
| public IUpdateFeature getUpdateFeature(IUpdateContext context) { |
| return new UpdateFeature(fp); |
| } |
| |
| @Override |
| public IReconnectionFeature getReconnectionFeature(IReconnectionContext context) { |
| return new ReconnectionFeature(fp); |
| } |
| |
| @Override |
| public IRemoveFeature getRemoveFeature(IRemoveContext context) { |
| return new CantRemoveFeature(fp); |
| } |
| |
| @Override |
| public IDeleteFeature getDeleteFeature(IDeleteContext context) { |
| return new DeleteFeature(fp); |
| } |
| |
| @Override |
| public ICustomFeature[] getCustomFeatures(ICustomContext context) { |
| PictogramElement pe = context.getPictogramElements()[0]; |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe .eContainer(); |
| Object bo = getBusinessObjectForPictogramElement(pe); |
| |
| ArrayList<ICustomFeature> result = new ArrayList<ICustomFeature>(); |
| |
| if (bo instanceof Transition) { |
| Transition trans = (Transition) bo; |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagramTypeProvider().getDiagram()); |
| boolean editable = FSMSupportUtil.getInstance().getFSMHelpers().getModelComponent(trans)==mc; |
| |
| // let's check whether we already refined this transition |
| if (!editable) |
| if (mc.getStateMachine()!=null) |
| for (RefinedTransition rt : mc.getStateMachine().getRefinedTransitions()) { |
| if (rt.getTarget()==trans) { |
| editable = true; |
| break; |
| } |
| } |
| |
| result.add(new PropertyFeature(fp, editable)); |
| |
| if (!editable) |
| result.add(new RefineTransitionFeature(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); |
| } |
| |
| protected static void updateLabel(Transition trans, Connection conn, Color fillColor) { |
| if (conn.getConnectionDecorators().size()<2) |
| return; |
| |
| ConnectionDecorator cd = conn.getConnectionDecorators().get(0); |
| if (cd.getGraphicsAlgorithm() instanceof Polygon) { |
| Polygon p = (Polygon) cd.getGraphicsAlgorithm(); |
| p.setBackground(fillColor); |
| } |
| |
| cd = conn.getConnectionDecorators().get(1); |
| if (cd.getGraphicsAlgorithm() instanceof Text) { |
| Text label = (Text) cd.getGraphicsAlgorithm(); |
| label.setValue(getLabel(trans)); |
| } |
| } |
| |
| protected static String getLabel(Transition trans) { |
| IPreferenceStore store = UIBaseActivator.getDefault().getPreferenceStore(); |
| int MAX_LINE_LENGTH = store.getInt(UIBasePreferenceConstants.MAX_LABEL_LINE_LENGTH); |
| int MAX_LINES = store.getInt(UIBasePreferenceConstants.MAX_LABEL_LINES); |
| String label = FSMSupportUtil.getInstance().getFSMNameProvider().getTransitionLabelName(trans); |
| StringBuilder result = new StringBuilder(); |
| int i = 0; |
| for (; i+MAX_LINE_LENGTH<label.length(); i+=MAX_LINE_LENGTH) { |
| result.append(label.substring(i, i+MAX_LINE_LENGTH)+newLine); |
| } |
| result.append(label.subSequence(i, label.length())); |
| int maxLen = (MAX_LINE_LENGTH+newLineLength)*MAX_LINES-newLineLength; |
| if (result.length()>maxLen) |
| return result.substring(0, maxLen)+"..."; |
| else |
| return result.toString(); |
| } |
| } |
| |
| class BehaviorProvider extends DefaultToolBehaviorProvider { |
| |
| public BehaviorProvider(IDiagramTypeProvider dtp) { |
| super(dtp); |
| } |
| |
| @Override |
| public ICustomFeature getDoubleClickFeature(IDoubleClickContext context) { |
| PictogramElement pe = context.getPictogramElements()[0]; |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| Object bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(pe); |
| if (bo instanceof Transition) { |
| Transition trans = (Transition) bo; |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagramTypeProvider().getDiagram()); |
| boolean editable = FSMSupportUtil.getInstance().getFSMHelpers().getModelComponent(trans)==mc; |
| return new FeatureProvider.PropertyFeature(getDiagramTypeProvider().getFeatureProvider(), editable); |
| } |
| |
| return null; |
| } |
| |
| @Override |
| public Object getToolTip(GraphicsAlgorithm ga) { |
| // if this is called we know there is a business object!=null |
| PictogramElement pe = ga.getPictogramElement(); |
| if (pe instanceof ConnectionDecorator) |
| pe = (PictogramElement) pe.eContainer(); |
| |
| EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(pe); |
| if (bo instanceof Transition) { |
| Transition tr = (Transition) bo; |
| String label = FSMSupportUtil.getInstance().getFSMNameProvider().getTransitionLabelName(tr); |
| ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagramTypeProvider().getDiagram()); |
| String code = FSMSupportUtil.getInstance().getFSMHelpers().getAllActionCode(tr, mc); |
| if (code!=null && !code.isEmpty()) { |
| if (label.length()>0) |
| label += "\n"; |
| label += "action:\n"+code; |
| } |
| return label; |
| } |
| |
| return super.getToolTip(ga); |
| } |
| |
| /** |
| * @author jayant |
| */ |
| @Override |
| public IDecorator[] getDecorators(PictogramElement pe) { |
| if (pe.isVisible()) { |
| // Constants for positioning decorators |
| int xOrigin = -20, yOrigin = 0; // Position to the left of label |
| int xGap = 0, yGap = -10; |
| |
| // Get the linked Business Object |
| EObject bo = Graphiti.getLinkService() |
| .getBusinessObjectForLinkedPictogramElement( |
| (PictogramElement) pe.eContainer()); |
| |
| // 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()) { |
| int i = 0; |
| for (IDecorator decorator : decorators) { |
| ((ImageDecorator) decorator).setX(xOrigin + i * xGap); |
| ((ImageDecorator) decorator).setY(yOrigin + i * yGap); |
| i++; |
| } |
| |
| return (IDecorator[]) decorators |
| .toArray(new IDecorator[decorators.size()]); |
| } |
| } |
| |
| return super.getDecorators(pe); |
| } |
| } |
| |
| private FeatureProvider pfp; |
| private BehaviorProvider tbp; |
| |
| public TransitionSupport(IDiagramTypeProvider dtp, IFeatureProvider fp) { |
| pfp = new FeatureProvider(dtp,fp); |
| tbp = new BehaviorProvider(dtp); |
| } |
| |
| public IFeatureProvider getFeatureProvider() { |
| return pfp; |
| } |
| |
| public IToolBehaviorProvider getToolBehaviorProvider() { |
| return tbp; |
| } |
| } |