diff options
author | Henrik Rentz-Reichert | 2018-07-06 17:19:51 +0000 |
---|---|---|
committer | Henrik Rentz-Reichert | 2018-07-06 17:22:00 +0000 |
commit | 0509ac03bea494b08a92251e68e9efc92e415a20 (patch) | |
tree | d070ca8800c829827df8aff75c1b773fe1115908 /plugins/org.eclipse.etrice.ui.behavior.fsm | |
parent | c2dfdeabf15d7e367bcd92731e6ac8651ffb9cac (diff) | |
parent | bed42b94fbf934db15e792b247ee747f0c37ebf4 (diff) | |
download | org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.tar.gz org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.tar.xz org.eclipse.etrice-0509ac03bea494b08a92251e68e9efc92e415a20.zip |
Merge remote-tracking branch 'newfsmgen_finalize'
Conflicts:
plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF
plugins/org.eclipse.etrice.ui.behavior/META-INF/MANIFEST.MF
Change-Id: Icc81a851cdcdb35081b8eaa3d5b025c1f850de54
Diffstat (limited to 'plugins/org.eclipse.etrice.ui.behavior.fsm')
35 files changed, 1842 insertions, 1719 deletions
diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/.classpath b/plugins/org.eclipse.etrice.ui.behavior.fsm/.classpath index 1fa3e6803..87e8cd659 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/.classpath +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/.classpath @@ -1,7 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="src" path="xtend-gen"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> </classpath> diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.etrice.ui.behavior.fsm/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF b/plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF index 8e73b0042..af6a4bf54 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-Vendor: eTrice Require-Bundle: org.eclipse.etrice.core.common.ui;bundle-version="1.1.3", org.eclipse.etrice.ui.common.base;bundle-version="1.1.3", org.eclipse.etrice.core.fsm;bundle-version="1.1.3", + org.eclipse.etrice.core.genmodel.fsm;bundle-version="1.1.3", org.eclipse.etrice.core.fsm.ui;bundle-version="1.1.3", org.eclipse.graphiti;bundle-version="0.8.0", org.eclipse.graphiti.ui;bundle-version="0.8.0", @@ -18,13 +19,16 @@ Require-Bundle: org.eclipse.etrice.core.common.ui;bundle-version="1.1.3", org.eclipse.xtext.ui;bundle-version="2.7.0", org.eclipse.xtend.lib;bundle-version="2.7.0", org.eclipse.xtext.ui.shared;bundle-version="2.7.0", - org.eclipse.etrice.expressions.ui;bundle-version="1.1.3" + org.eclipse.etrice.expressions.ui;bundle-version="1.1.3", + org.eclipse.xtext.ui.shared;bundle-version="2.7.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.etrice.ui.behavior.fsm.actioneditor, +Export-Package: org.eclipse.etrice.ui.behavior.fsm, + org.eclipse.etrice.ui.behavior.fsm.actioneditor, org.eclipse.etrice.ui.behavior.fsm.actioneditor.preferences, org.eclipse.etrice.ui.behavior.fsm.commands, org.eclipse.etrice.ui.behavior.fsm.dialogs, org.eclipse.etrice.ui.behavior.fsm.editor, org.eclipse.etrice.ui.behavior.fsm.provider, - org.eclipse.etrice.ui.behavior.fsm.support + org.eclipse.etrice.ui.behavior.fsm.support, + org.eclipse.etrice.ui.behavior.fsm.support.util diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/PopulateDiagramCommand.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/PopulateDiagramCommand.java index 28d00f9cc..6bc96f050 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/PopulateDiagramCommand.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/PopulateDiagramCommand.java @@ -16,42 +16,33 @@ import org.eclipse.emf.transaction.RecordingCommand; import org.eclipse.emf.transaction.TransactionalEditingDomain; import org.eclipse.etrice.core.fsm.fSM.ModelComponent; import org.eclipse.etrice.ui.behavior.fsm.support.ContextSwitcher; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; import org.eclipse.graphiti.dt.IDiagramTypeProvider; -import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.context.impl.UpdateContext; import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.graphiti.ui.services.GraphitiUi; -import com.google.inject.Injector; - public class PopulateDiagramCommand extends RecordingCommand { + private String providerId; private ModelComponent mc; private Diagram diagram; - private IFeatureProvider fp; - private Injector injector; - public PopulateDiagramCommand(String providerId, Diagram diag, ModelComponent mc, Injector injector, TransactionalEditingDomain domain) { + public PopulateDiagramCommand(String providerId, Diagram diag, ModelComponent mc, TransactionalEditingDomain domain) { super(domain); + this.providerId = providerId; this.diagram = diag; this.mc = mc; - this.injector = injector; - - IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, providerId); //$NON-NLS-1$ - fp = dtp.getFeatureProvider(); } @Override protected void doExecute() { + IDiagramTypeProvider dtp = GraphitiUi.getExtensionManager().createDiagramTypeProvider(diagram, providerId); //$NON-NLS-1$ - fp.link(diagram, mc); - - // we use a temporary structure to create the whole tree - StateGraphContext tree = StateGraphContext.createContextTree(mc, injector); - //System.out.println(tree); - - FSMSupportUtil.getInstance().addStateGraph(tree, diagram, fp); + dtp.getFeatureProvider().link(diagram, mc); + + UpdateContext ctx = new UpdateContext(diagram); + dtp.getFeatureProvider().getUpdateFeature(ctx).update(ctx); ContextSwitcher.switchTop(diagram); } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/StateGraphContext.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/StateGraphContext.java deleted file mode 100644 index 867ab3953..000000000 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/commands/StateGraphContext.java +++ /dev/null @@ -1,274 +0,0 @@ -package org.eclipse.etrice.ui.behavior.fsm.commands; - -import java.util.ArrayList; -import java.util.HashMap; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; -import org.eclipse.etrice.core.fsm.fSM.FSMFactory; -import org.eclipse.etrice.core.fsm.fSM.InitialTransition; -import org.eclipse.etrice.core.fsm.fSM.ModelComponent; -import org.eclipse.etrice.core.fsm.fSM.RefinedState; -import org.eclipse.etrice.core.fsm.fSM.SimpleState; -import org.eclipse.etrice.core.fsm.fSM.State; -import org.eclipse.etrice.core.fsm.fSM.StateGraph; -import org.eclipse.etrice.core.fsm.fSM.StateGraphItem; -import org.eclipse.etrice.core.fsm.fSM.TrPoint; -import org.eclipse.etrice.core.fsm.fSM.Transition; -import org.eclipse.etrice.ui.behavior.fsm.support.DefaultPositionProvider; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; -import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider; - -import com.google.inject.Injector; - -public class StateGraphContext { - private ArrayList<StateGraphContext> children = new ArrayList<StateGraphContext>(); - - private StateGraph stateGraph; - private ArrayList<State> states = new ArrayList<State>(); - private ArrayList<ChoicePoint> chPoints = new ArrayList<ChoicePoint>(); - private ArrayList<TrPoint> trPoints = new ArrayList<TrPoint>(); - private ArrayList<Transition> transitions = new ArrayList<Transition>(); - private IPositionProvider positionProvider; - private HashMap<StateGraphItem, StateGraphContext> obj2ctx; - - public static StateGraphContext createContextTree(ModelComponent mc, Injector injector) { - - // the top level state graph is always the one of our actor class - if (mc.getStateMachine()==null || mc.getStateMachine().eIsProxy()) { - mc.setStateMachine(FSMFactory.eINSTANCE.createStateGraph()); - } - - // base classes in reverse order - ArrayList<ModelComponent> classes = new ArrayList<ModelComponent>(); - { - ModelComponent a = mc; - while (a!=null) { - classes.add(0, a); - a = a.getBase(); - } - } - - // build and merge contexts from base classes to derived classes - StateGraphContext tree = null; - for (ModelComponent cls : classes) { - if (cls.getStateMachine()!=null) { - if (tree==null) - tree = new StateGraphContext(cls.getStateMachine(), new HashMap<StateGraphItem, StateGraphContext>()); - else - tree.merge(cls.getStateMachine()); - } - } - - tree.positionProvider = new DefaultPositionProvider(mc, injector); - makePositionsAvailableToChildrenContexts(tree); - - return tree; - } - - private StateGraphContext(StateGraph sg, HashMap<StateGraphItem, StateGraphContext> obj2ctx) { - this.stateGraph = sg; - this.obj2ctx = obj2ctx; - - init(sg); - } - - private void init(StateGraph sg) { - for (State s : sg.getStates()) { - states.add(s); - obj2ctx.put(s, this); - } - for (ChoicePoint cp : sg.getChPoints()) { - chPoints.add(cp); - obj2ctx.put(cp, this); - } - for (TrPoint tp : sg.getTrPoints()) { - trPoints.add(tp); - obj2ctx.put(tp, this); - } - for (Transition t : sg.getTransitions()) { - transitions.add(t); - obj2ctx.put(t, this); - } - - // recurse - for (State s : sg.getStates()) { - if (s.getSubgraph()!=null) - children.add(new StateGraphContext(s.getSubgraph(), obj2ctx)); - } - } - - private void merge(StateGraph derived) { - stateGraph = derived; - - // add derived contents up to refined states - for (State s : derived.getStates()) { - if (s instanceof SimpleState) { - states.add(s); - obj2ctx.put(s, this); - } - } - for (ChoicePoint cp : derived.getChPoints()) { - chPoints.add(cp); - obj2ctx.put(cp, this); - } - for (TrPoint tp : derived.getTrPoints()) { - trPoints.add(tp); - obj2ctx.put(tp, this); - } - for (Transition t : derived.getTransitions()) { - transitions.add(t); - obj2ctx.put(t, this); - } - - // recurse for non-refined states - for (State s : derived.getStates()) { - if (s instanceof SimpleState) - if (s.getSubgraph()!=null) - children.add(new StateGraphContext(s.getSubgraph(), obj2ctx)); - } - - // refined states - for (State refined : derived.getStates()) { - if (refined instanceof RefinedState) { - State base = ((RefinedState) refined).getTarget(); - StateGraphContext ctx = obj2ctx.get(base); - assert(ctx!=null): "should have visited base state already"; - - // remove base and put refined in place - ctx.getStates().remove(base); - ctx.getStates().add(refined); - obj2ctx.put(refined, this); - - // merge sub contexts - if (FSMSupportUtil.getInstance().getFSMHelpers().hasDirectSubStructure(base)) { - StateGraphContext basesub = null; - for (StateGraphContext bs : ctx.getChildren()) { - if (bs.getParentState()==base) { - basesub = bs; - break; - } - } - if (basesub!=null) { - if (FSMSupportUtil.getInstance().getFSMHelpers().hasDirectSubStructure(refined)) { - basesub.merge(refined.getSubgraph()); - } - } - else { - assert(false): "context not found"; - } - } - else if (FSMSupportUtil.getInstance().getFSMHelpers().hasDirectSubStructure(refined)) { - StateGraphContext sub = new StateGraphContext(refined.getSubgraph(), obj2ctx); - ctx.getChildren().add(sub); - } - } - } - } - - /** - * Propagate the position map to all children recursively - * - * @param tree - */ - private static void makePositionsAvailableToChildrenContexts(StateGraphContext tree) { - for (StateGraphContext child : tree.getChildren()) { - child.positionProvider = tree.positionProvider; - makePositionsAvailableToChildrenContexts(child); - } - } - - public State getParentState() { - if (stateGraph.eContainer() instanceof State) - return (State) stateGraph.eContainer(); - - return null; - } - - public ArrayList<StateGraphContext> getChildren() { - return children; - } - - public ArrayList<State> getStates() { - return states; - } - - public ArrayList<ChoicePoint> getChPoints() { - return chPoints; - } - - public StateGraph getStateGraph() { - return stateGraph; - } - - public ArrayList<TrPoint> getTrPoints() { - return trPoints; - } - - public ArrayList<Transition> getTransitions() { - return transitions; - } - - public IPositionProvider getPositionProvider() { - return positionProvider; - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return dump(""); - } - - /** - * @param indent - * @return context tree in human readable form - */ - private String dump(String indent) { - StringBuilder result = new StringBuilder(); - result.append(indent+">>> "+getText(stateGraph)+"\n"); - indent += " "; - for (State s : states) { - result.append(indent+getText(s)+"\n"); - } - - for (StateGraphContext child : children) { - result.append(child.dump(indent)); - } - return result.toString(); - } - - private String getText(StateGraph sg) { - ModelComponent mc = getModelComponent(sg); - EObject parent = sg.eContainer(); - String item = parent instanceof ModelComponent? "diagram" : (parent.eClass().getName()+" "+((State)parent).getName()); - return "state graph of "+item+" of "+(mc==null? "?":mc.getComponentName()); - } - - private String getText(StateGraphItem item) { - ModelComponent mc = getModelComponent(item); - return item.eClass().getName()+" "+item.getName()+" of "+(mc==null? "?":mc.getComponentName()); - } - - private ModelComponent getModelComponent(EObject obj) { - EObject parent = obj.eContainer(); - while (parent!=null) { - if (parent instanceof ModelComponent) - return (ModelComponent) parent; - parent = parent.eContainer(); - } - return null; - } - - public StateGraphContext getContext(StateGraphItem item) { - return obj2ctx.get(item); - } - - public StateGraph getInitialPoint(){ - for(Transition t : transitions) - if(t instanceof InitialTransition) - return (StateGraph) t.eContainer(); - return null; - } -} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/AbstractMemberAwarePropertyDialog.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/AbstractMemberAwarePropertyDialog.java index 90ebde21c..72419ec9d 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/AbstractMemberAwarePropertyDialog.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/AbstractMemberAwarePropertyDialog.java @@ -29,7 +29,7 @@ import org.eclipse.etrice.ui.behavior.fsm.actioneditor.ActionCodeEditorRegistry; import org.eclipse.etrice.ui.behavior.fsm.actioneditor.ActionCodeEditorRegistry.ActionCodeEditorRegistryEntry; import org.eclipse.etrice.ui.behavior.fsm.actioneditor.IActionCodeEditor; import org.eclipse.etrice.ui.behavior.fsm.actioneditor.preferences.PreferenceConstants; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.dialogs.AbstractPropertyDialog; import org.eclipse.etrice.ui.common.base.dialogs.MultiValidator2; import org.eclipse.jface.preference.IPreferenceStore; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/ChoicePointPropertyDialog.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/ChoicePointPropertyDialog.java index 6eb48c402..ccdc035e0 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/ChoicePointPropertyDialog.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/ChoicePointPropertyDialog.java @@ -9,7 +9,7 @@ import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; import org.eclipse.etrice.core.fsm.fSM.FSMPackage; import org.eclipse.etrice.core.fsm.validation.FSMValidationUtilXtend.Result; import org.eclipse.etrice.ui.behavior.fsm.Activator; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.dialogs.AbstractPropertyDialog; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TrPointPropertyDialog.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TrPointPropertyDialog.java index d9a369885..7c0fd40d5 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TrPointPropertyDialog.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TrPointPropertyDialog.java @@ -10,7 +10,7 @@ import org.eclipse.etrice.core.fsm.fSM.TrPoint; import org.eclipse.etrice.core.fsm.fSM.TransitionPoint; import org.eclipse.etrice.core.fsm.validation.FSMValidationUtilXtend.Result; import org.eclipse.etrice.ui.behavior.fsm.Activator; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.dialogs.AbstractPropertyDialog; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TransitionTriggerCompartment.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TransitionTriggerCompartment.java index 1fcef7532..d86bc6790 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TransitionTriggerCompartment.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/dialogs/TransitionTriggerCompartment.java @@ -25,7 +25,7 @@ import org.eclipse.etrice.core.fsm.fSM.Transition; import org.eclipse.etrice.core.fsm.fSM.Trigger; import org.eclipse.etrice.core.fsm.fSM.TriggeredTransition; import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.dialogs.AbstractPropertyDialog; import org.eclipse.jface.viewers.IBaseLabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMDiagramTypeProvider.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMDiagramTypeProvider.java index fa38f2706..80044564b 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMDiagramTypeProvider.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMDiagramTypeProvider.java @@ -12,6 +12,8 @@ package org.eclipse.etrice.ui.behavior.fsm.editor; +import org.eclipse.etrice.ui.behavior.fsm.provider.GenModelProvider; +import org.eclipse.etrice.ui.behavior.fsm.provider.IInjectorProvider; import org.eclipse.etrice.ui.common.base.editor.AbstractBaseDiagramTypeProvider; import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.graphiti.platform.IDiagramContainer; @@ -21,7 +23,15 @@ import org.eclipse.graphiti.platform.IDiagramContainer; * functionality provided by {@link AbstractFSMEditor}. Diagram editor plugins * that extend {@link AbstractFSMEditor} should also extend and use this class. */ -public abstract class AbstractFSMDiagramTypeProvider extends AbstractBaseDiagramTypeProvider { +public abstract class AbstractFSMDiagramTypeProvider extends AbstractBaseDiagramTypeProvider implements IInjectorProvider { + + public GenModelProvider getGenModelProvider() { + // create always new one for now +// Stopwatch timer = Stopwatch.createStarted(); +// GenModelProvider genModelProvider = new GenModelProvider(this); +// System.out.println(timer.stop().elapsed(TimeUnit.MILLISECONDS)); + return new GenModelProvider(this); + } /* (non-Javadoc) * @see org.eclipse.graphiti.dt.AbstractDiagramTypeProvider#resourceReloaded(org.eclipse.graphiti.mm.pictograms.Diagram) diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMEditor.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMEditor.java index 389a9ff45..bc2609c17 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMEditor.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/AbstractFSMEditor.java @@ -13,6 +13,7 @@ package org.eclipse.etrice.ui.behavior.fsm.editor; import java.util.ArrayList; +import java.util.EventObject; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; @@ -27,8 +28,9 @@ import org.eclipse.etrice.core.fsm.fSM.RefinedState; import org.eclipse.etrice.core.fsm.fSM.State; import org.eclipse.etrice.core.fsm.fSM.StateGraph; import org.eclipse.etrice.core.fsm.util.FSMHelpers; +import org.eclipse.etrice.core.fsm.validation.FSMValidationUtil; import org.eclipse.etrice.ui.behavior.fsm.support.ContextSwitcher; -import org.eclipse.etrice.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.editor.DiagramEditorBase; import org.eclipse.graphiti.dt.IDiagramTypeProvider; import org.eclipse.graphiti.features.IFeatureProvider; @@ -38,6 +40,8 @@ import org.eclipse.graphiti.mm.pictograms.Diagram; import org.eclipse.graphiti.mm.pictograms.Shape; import org.eclipse.graphiti.services.Graphiti; import org.eclipse.graphiti.ui.editor.DiagramBehavior; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; import com.google.common.base.Function; @@ -139,6 +143,23 @@ public abstract class AbstractFSMEditor extends DiagramEditorBase { @Override public void doSave(IProgressMonitor monitor) { + + FSMValidationUtil fsmValidationUtil = FSMSupportUtil.getInstance().getFSMValidationUtil(); + Diagram diagram = getDiagramTypeProvider().getDiagram(); + ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(diagram); + if (mc.getStateMachine()!=null) { + for (State s : mc.getStateMachine().getStates()) { + if (s instanceof RefinedState) { + if (fsmValidationUtil.isRefinedStateEmpty((RefinedState) s)) { + MessageDialog.openError(Display.getCurrent().getActiveShell(), + "Check of Refined State", + "A Refined State with empty action codes must have a non-empty sub state graph."); + return; + } + } + } + } + getEditingDomain().getCommandStack().execute(new RecordingCommand(getEditingDomain()) { protected void doExecute() { cleanupBeforeSave(); @@ -270,4 +291,10 @@ public abstract class AbstractFSMEditor extends DiagramEditorBase { featureProvider.updateIfPossible(updateCtx); diagramTypeProvider.getDiagramBehavior().refresh(); } + + @Override + public void commandStackChanged(EventObject event) { + // TODO Auto-generated method stub + super.commandStackChanged(event); + } } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/BehaviorExporter.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/BehaviorExporter.java index 782b7a916..95d2b3499 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/BehaviorExporter.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/BehaviorExporter.java @@ -18,7 +18,7 @@ import org.eclipse.emf.ecore.EObject; 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.ui.behavior.fsm.support.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.export.DiagramExporter; import org.eclipse.etrice.ui.common.base.export.IBulkDiagramExporter; import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/DiagnosingModelObserver.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/DiagnosingModelObserver.java index ba29924be..8a7eea9a3 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/DiagnosingModelObserver.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/editor/DiagnosingModelObserver.java @@ -23,6 +23,7 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.Diagnostician; import org.eclipse.emf.ecore.util.EContentAdapter; +import org.eclipse.etrice.core.fsm.fSM.DetailCode; import org.eclipse.etrice.core.fsm.fSM.StateGraph; import org.eclipse.etrice.core.fsm.fSM.Trigger; import org.eclipse.xtext.validation.FeatureBasedDiagnostic; @@ -116,10 +117,13 @@ public class DiagnosingModelObserver extends EContentAdapter { super.notifyChanged(notification); // Re-Validate on each notification except Adapter Removal. - // This prevents the editor to hang on dispose (since all adapters are - // then removed). + // This prevents the editor to hang on dispose (since all adapters are then removed). if (notification.getEventType() < Notification.REMOVING_ADAPTER) { - updateElementDiagnosticMap(); + if(!(notification.getNewValue() instanceof EObject) || notification.getNewValue() instanceof DetailCode) { + // Bug 531689: skip validation when user is typing in DetailCode or text field to prevent delay + } else { + updateElementDiagnosticMap(); + } } } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/BaseDiagramProvider.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/BaseDiagramProvider.xtend new file mode 100644 index 000000000..d6ad81747 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/BaseDiagramProvider.xtend @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.provider + +import com.google.common.collect.ArrayListMultimap +import com.google.common.collect.Multimap +import java.util.Collection +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.etrice.core.fsm.fSM.ModelComponent +import org.eclipse.etrice.core.fsm.fSM.StateGraph +import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMDiagramTypeProvider +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil +import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase +import org.eclipse.graphiti.mm.pictograms.PictogramElement +import org.eclipse.graphiti.mm.pictograms.PictogramLink +import org.eclipse.graphiti.services.Graphiti + +/** + * Provides the {@linkplain PictogramElement} objects of the base class diagram. + * This is a reverse mapping from room business objects to linked base diagram pictograms. + * + * TODO: use fsmgenmodel instead + */ +class BaseDiagramProvider { + + val Multimap<EObject, PictogramElement> baseDiagramBusinessObjs = ArrayListMultimap.create + val fsmHelpers = FSMSupportUtil.instance.FSMHelpers + + new(AbstractFSMDiagramTypeProvider diagramTypeProvider) { + val diagramAccess = diagramTypeProvider.injector.getInstance(DiagramAccessBase) + val mc = Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(diagramTypeProvider.diagram) as ModelComponent + val rs = diagramTypeProvider.diagram.eResource.resourceSet + + // open base diagrams => causes full recursive update or creation of all base diagrams + // all base diagrams have to be considered because inherited subgraph could not exist yet + val baseClasses = newArrayList => [ + var base = mc.base + while(base !== null && it.add(base)) { + base = base.base + } + ] + baseClasses.reverseView.forEach[ base | + val baseDiagram = diagramAccess.getDiagram(base, rs) + if(baseDiagram !== null) { + // create mapping from business object to pictogram elements + EcoreUtil.ExternalCrossReferencer.find(baseDiagram).forEach [ targetEObj, eFeatureSetting | + eFeatureSetting.map[getEObject].filter(PictogramLink).map[pictogramElement].forEach [ pe | + put(mc, targetEObj, pe) + ] + ] + + // base diagram resource not needed anymore + rs.resources.remove(baseDiagram.eResource) + } + ] + } + + private def put(ModelComponent mc, EObject obj, PictogramElement value) { + if (obj instanceof StateGraph) { + if (fsmHelpers.isTopLevel(obj)) { + // to find the initial point of the TOP level we need the ModelComponent's stateMachine as a key + baseDiagramBusinessObjs.put(mc.stateMachine, value) + } + } + baseDiagramBusinessObjs.put(obj, value) + } + + def Collection<PictogramElement> getPictograms(EObject roomObj) { + if(roomObj === null) emptyList else baseDiagramBusinessObjs.get(roomObj) + } + +} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/GenModelProvider.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/GenModelProvider.xtend new file mode 100644 index 000000000..7b9c50473 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/provider/GenModelProvider.xtend @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.provider + +import java.util.Map +import org.eclipse.emf.ecore.EObject +import org.eclipse.etrice.core.fsm.fSM.ModelComponent +import org.eclipse.etrice.core.genmodel.fsm.BasicFsmGenBuilder +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Graph +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.GraphContainer +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Link +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Node +import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMDiagramTypeProvider +import org.eclipse.graphiti.dt.IDiagramTypeProvider +import org.eclipse.graphiti.services.Graphiti +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.FSMGenElement + +class GenModelProvider { + + val BasicFsmGenBuilder builder + val IDiagramTypeProvider fsmDiagramProvider + var Map<EObject, FSMGenElement> graphMap = newHashMap + + var GraphContainer modelInstance = null + + new(AbstractFSMDiagramTypeProvider fsmDiagramProvider) { + this.fsmDiagramProvider = fsmDiagramProvider + builder = new BasicFsmGenBuilder(fsmDiagramProvider.injector) + } + + def updateModel() { + Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(fsmDiagramProvider.diagram) => [ + modelInstance = if(it instanceof ModelComponent) builder.createTransformedModel(it) else null + ] + if (modelInstance !== null) { + graphMap.clear + modelInstance.eAllContents.forEach [ + switch (it) { + Graph: graphMap.put(stateGraph, it) + Node: graphMap.put(stateGraphNode, it) + Link: graphMap.put(transition, it) + } + ] + } + } + + def getModel() { + if (modelInstance === null) { + updateModel() + } + + return modelInstance; + } + + def <T extends FSMGenElement> getCasted(EObject roomObj) { + return graphMap.get(roomObj) as T + } +} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/AbstractFSMProviderDispatcher.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/AbstractFSMProviderDispatcher.java index 1b231a161..9fad672db 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/AbstractFSMProviderDispatcher.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/AbstractFSMProviderDispatcher.java @@ -24,6 +24,7 @@ import org.eclipse.etrice.core.fsm.fSM.TrPoint; import org.eclipse.etrice.core.fsm.fSM.Transition; import org.eclipse.etrice.core.fsm.fSM.util.FSMSwitch; import org.eclipse.etrice.core.fsm.naming.FSMFragmentProvider; +import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMDiagramTypeProvider; import org.eclipse.etrice.ui.behavior.fsm.provider.IInjectorProvider; import org.eclipse.etrice.ui.common.base.support.CantDeleteFeature; import org.eclipse.etrice.ui.common.base.support.CantRemoveFeature; @@ -78,7 +79,7 @@ import org.eclipse.graphiti.util.IColorConstant; import com.google.inject.Injector; -public abstract class AbstractFSMProviderDispatcher implements IInjectorProvider { +public class AbstractFSMProviderDispatcher { private class FeatureProviderSwitch extends FSMSwitch<IFeatureProvider> { private ContainerShape parent = null; @@ -235,9 +236,9 @@ public abstract class AbstractFSMProviderDispatcher implements IInjectorProvider private IInjectorProvider injectorProvider; - public DispatchingFeatureProvider(IDiagramTypeProvider dtp, IInjectorProvider injectorProvider) { + public DispatchingFeatureProvider(AbstractFSMDiagramTypeProvider dtp) { super(dtp); - this.injectorProvider = injectorProvider; + this.injectorProvider = dtp; } @Override @@ -550,9 +551,9 @@ public abstract class AbstractFSMProviderDispatcher implements IInjectorProvider private DispatchingToolBehaviorProvider dispatchingBP; - public AbstractFSMProviderDispatcher(IDiagramTypeProvider dtp) { + public AbstractFSMProviderDispatcher(AbstractFSMDiagramTypeProvider dtp) { // create those first before using them - dispatchingFP = new DispatchingFeatureProvider(dtp, this); + dispatchingFP = new DispatchingFeatureProvider(dtp); dispatchingBP = new DispatchingToolBehaviorProvider(dtp); stateGraphSupport = new StateGraphSupport(dtp, dispatchingFP); @@ -582,6 +583,7 @@ public abstract class AbstractFSMProviderDispatcher implements IInjectorProvider return featureSwitch.getCreateConnectionFeatures(); } + @SafeVarargs private static <T> T[] concatAll(T[] first, T[]... rest) { int totalLength = first.length; for (T[] array : rest) { diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/BaseDiagramPositionProvider.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/BaseDiagramPositionProvider.xtend new file mode 100644 index 000000000..083c0e12e --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/BaseDiagramPositionProvider.xtend @@ -0,0 +1,165 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support + +import java.util.List +import org.eclipse.etrice.core.fsm.fSM.InitialTransition +import org.eclipse.etrice.core.fsm.fSM.ModelComponent +import org.eclipse.etrice.core.fsm.fSM.RefinedState +import org.eclipse.etrice.core.fsm.fSM.RefinedTransition +import org.eclipse.etrice.core.fsm.fSM.State +import org.eclipse.etrice.core.fsm.fSM.StateGraph +import org.eclipse.etrice.core.fsm.fSM.StateGraphNode +import org.eclipse.etrice.core.fsm.fSM.TrPoint +import org.eclipse.etrice.core.fsm.fSM.Transition +import org.eclipse.etrice.ui.behavior.fsm.provider.BaseDiagramProvider +import org.eclipse.graphiti.mm.algorithms.Text +import org.eclipse.graphiti.mm.pictograms.Connection +import org.eclipse.graphiti.mm.pictograms.FreeFormConnection +import org.eclipse.graphiti.mm.pictograms.PictogramElement +import org.eclipse.graphiti.services.Graphiti +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor + +/** + * IPositionProvider based on {@linkplain BaseDiagramProvider} + * Logic copied from DefaultPositionProvider + */ +@FinalFieldsConstructor +class BaseDiagramPositionProvider implements IPositionProvider { + + val BaseDiagramProvider baseDiagram + + // TODO: positions should not rely on graphics internals + def getMargin(StateGraphNode node) { + switch node { + State: StateSupport.MARGIN + TrPoint: TrPointSupport.MARGIN + default: 0 + } + } + + // TODO: positions should not rely on graphics internals + def getMargin(StateGraph graph){ + return 0 + } + + def private toPosAndSize(PictogramElement pe, int margin){ + val borderGa = (pe.eContainer as PictogramElement).graphicsAlgorithm.graphicsAlgorithmChildren.head + val ga = pe.graphicsAlgorithm + + val x = (ga.getX() / borderGa.width as double) * sx + margin + val y = (ga.getY() / borderGa.height as double) * sy + margin + val width = ((ga.getWidth() - 2 * margin) / borderGa.width as double) * sx + val height = ((ga.getHeight() - 2 * margin) / borderGa.height as double) * sy + + new PosAndSize(x as int, y as int, width as int, height as int) + } + + override getGraphPosAndSize(StateGraph sg) { + // graph is child of border shape, see initial point + val pe = baseDiagram.getPictograms(sg).findFirst[parentBo instanceof ModelComponent] + if (pe !== null){ + val visibleGa = pe.graphicsAlgorithm.graphicsAlgorithmChildren.head + new PosAndSize(pe.graphicsAlgorithm.x, pe.graphicsAlgorithm.y, visibleGa.width, visibleGa.height) + } + } + + override getPoints(Transition trans) { + val pe = { + if (trans instanceof RefinedTransition) + baseDiagram.getPictograms(trans.target).head + else + baseDiagram.getPictograms(trans).head + } + newArrayList => [ pointList | + if (pe instanceof Connection){ + val graphPosAndSize = getGraphPosAndSize(trans.eContainer as StateGraph) + val text = pe.connectionDecorators.map[graphicsAlgorithm].filter(Text).head + if (text !== null){ + pointList += new Pos( + (((text.x / graphPosAndSize.width as double) * sx) as int), + (((text.y / graphPosAndSize.height as double) * sy) as int) + ) + if (pe instanceof FreeFormConnection){ + pointList += pe.bendpoints.map[pt | new Pos( + (((pt.x / graphPosAndSize.width as double) * sx + x) as int) - StateGraphSupport.MARGIN, + (((pt.y / graphPosAndSize.height as double) * sy + y) as int) - StateGraphSupport.MARGIN + )] + } + } + } + ] + } + + override getPosition(StateGraphNode node) { + val getBasePos = [baseDiagram.getPictograms(it).findFirst[parentBo instanceof StateGraph]?.toPosAndSize(node.margin)] + + return if(node instanceof RefinedState){ + // 1. RefinedState is base diagram + // 2. RefinedState target is in base diagram + getBasePos.apply(node)?:getBasePos.apply(node.target) + } else { + getBasePos.apply(node) + } + } + + override getInitialPoint(StateGraph stateGraph) { + val initTransPe = baseDiagram.getPictograms(stateGraph.transitions.filter(InitialTransition).head).head + if(initTransPe instanceof Connection){ + val sourceAnchorBo = Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(initTransPe.start) + if(sourceAnchorBo instanceof StateGraph) + return sourceAnchorBo + } + } + + // TODO: better naming, this is the initial point + override getPosition(StateGraph graph) { + // initial point bo is graph and it is child of border shape + baseDiagram.getPictograms(graph).findFirst[parentBo instanceof StateGraph]?.toPosAndSize(graph.margin) + } + + override <T extends StateGraphNode> getPositions(List<T> items) { + items.map[baseDiagram.getPictograms(it).head?.toPosAndSize(it.margin)] + } + + override getSubPosition(StateGraphNode subNode) { + val pe = baseDiagram.getPictograms(subNode).findFirst[parentBo instanceof State] + if (pe !== null){ + val parentPe = pe.eContainer as PictogramElement + val relX = pe.graphicsAlgorithm.getX() as double / (parentPe.graphicsAlgorithm.getWidth() - 2 * StateSupport.MARGIN) + val relY = pe.graphicsAlgorithm.getY() as double / (parentPe.graphicsAlgorithm.getHeight() - 2 * StateSupport.MARGIN) + return #[relX, relY] + } + } + + var int x + var int y + + override setPosition(int x, int y) { + this.x = x + this.y = y + } + + var double sx + var double sy + + override setScale(double sx, double sy) { + this.sx = sx + this.sy = sy + } + + def private getParentBo(PictogramElement pe) { + Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(pe.eContainer as PictogramElement) + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ChoicePointSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ChoicePointSupport.java index 8cb7bced3..d7891a575 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ChoicePointSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ChoicePointSupport.java @@ -27,6 +27,8 @@ 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.behavior.fsm.support.util.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.ModelEditingUtil; 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; @@ -92,7 +94,7 @@ import org.eclipse.ui.PlatformUI; import com.google.inject.Injector; public class ChoicePointSupport { - + public static final int ITEM_SIZE = (int) (StateGraphSupport.MARGIN*0.625); protected static final int LINE_WIDTH = 2; @@ -121,9 +123,8 @@ public class ChoicePointSupport { StateGraph sg = (StateGraph) targetContainer.getLink().getBusinessObjects().get(0); ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); - boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); - if (inherited) { - sg = FSMSupportUtil.getInstance().insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); + if (!FSMSupportUtil.getInstance().isOwnedBy(mc, sg)) { + sg = ModelEditingUtil.insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); } // create choice point and add it @@ -193,7 +194,7 @@ public class ChoicePointSupport { ContainerShape containerShape = peCreateService.createContainerShape(sgShape, true); - Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.TRP_TYPE); + Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.CP_TYPE); int x = context.getX()-ITEM_SIZE; int y = context.getY()-ITEM_SIZE; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/Constants.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/Constants.java index a7d17712c..9af3edb57 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/Constants.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/Constants.java @@ -20,5 +20,6 @@ public interface Constants { static final String STATE_TYPE = "state"; static final String CP_TYPE = "cp"; static final String TRP_TYPE = "trp"; + static final String INI_TYPE = "ini"; static final String TRANS_TYPE = "trans"; } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ContextSwitcher.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ContextSwitcher.java index cdde42d97..4256eaf38 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ContextSwitcher.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/ContextSwitcher.java @@ -9,6 +9,7 @@ import org.eclipse.etrice.core.fsm.fSM.ModelComponent; import org.eclipse.etrice.core.fsm.fSM.RefinedState; import org.eclipse.etrice.core.fsm.fSM.State; import org.eclipse.etrice.core.fsm.fSM.StateGraph; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; import org.eclipse.graphiti.mm.pictograms.Connection; import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator; diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DefaultPositionProvider.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DefaultPositionProvider.java deleted file mode 100644 index 3be1be189..000000000 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DefaultPositionProvider.java +++ /dev/null @@ -1,349 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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: - * Henrik Rentz-Reichert (initial contribution) - * - *******************************************************************************/ - -package org.eclipse.etrice.ui.behavior.fsm.support; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; -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.StateGraphItem; -import org.eclipse.etrice.core.fsm.fSM.StateGraphNode; -import org.eclipse.etrice.core.fsm.fSM.TrPoint; -import org.eclipse.etrice.core.fsm.fSM.Transition; -import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; -import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; -import org.eclipse.etrice.ui.common.base.support.DiagramAccessBase; -import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; -import org.eclipse.graphiti.mm.algorithms.Text; -import org.eclipse.graphiti.mm.algorithms.styles.Point; -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.Diagram; -import org.eclipse.graphiti.mm.pictograms.FreeFormConnection; -import org.eclipse.graphiti.mm.pictograms.Shape; -import org.eclipse.graphiti.services.Graphiti; -import org.eclipse.graphiti.services.ILinkService; - -import com.google.inject.Injector; - -/** - * @author Henrik Rentz-Reichert (initial contribution) - * - */ -public class DefaultPositionProvider implements IPositionProvider { - private static class Position { - double x; - double y; - double sx; - double sy; - } - - private HashMap<String, Position> obj2pos = new HashMap<String, Position>(); - private HashMap<String, Position> subObj2pos = new HashMap<String, Position>(); - private HashMap<String, ArrayList<Position>> trans2points = new HashMap<String, ArrayList<Position>>(); - private HashMap<String, StateGraph> initialPointObj = new HashMap<String, StateGraph>(); - private HashMap<String, PosAndSize> sg2sz = new HashMap<String, PosAndSize>(); - private double scaleX; - private double scaleY; - private int posX, posY; - - public DefaultPositionProvider(ModelComponent mc, Injector injector) { - mapPositions(mc.getBase(), injector); - } - - /* (non-Javadoc) - * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#setScale(double, double) - */ - @Override - public void setScale(double sx, double sy) { - this.scaleX = sx; - this.scaleY = sy; - } - - @Override - public void setPosition(int x, int y){ - this.posX = x; - this.posY = y; - } - - public PosAndSize getPosition(StateGraphNode node) { - Position pos = obj2pos.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(node)); - if (pos==null) - return null; - - int margin = getMargin(node); - PosAndSize pt = new PosAndSize( - (int) (pos.x * scaleX) + margin, - (int) (pos.y * scaleY) + margin, - (int) (pos.sx * scaleX), - (int) (pos.sy * scaleY) - ); - return pt; - } - - @Override - public PosAndSize getPosition(StateGraph graph) { - EObject container = graph.eContainer(); - String path = "#init"; - if(container instanceof StateGraphNode) - path = FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath((StateGraphNode)container) + path; - Position pos = obj2pos.get(path); - - if (pos==null) - return null; - - int margin = getMargin(graph); - PosAndSize pt = new PosAndSize( - (int) (pos.x * scaleX) + margin, - (int) (pos.y * scaleY) + margin, - (int) (pos.sx * scaleX), - (int) (pos.sy * scaleY) - ); - return pt; - } - - public List<Pos> getPoints(Transition trans) { - ArrayList<Pos> result = new ArrayList<Pos>(); - - ArrayList<Position> list = trans2points.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(trans)); - if (list!=null) { - int i = 0; - for (Position p : list) { - Pos pos = - new Pos( - (int) (p.x * scaleX) + ((i==0)?0:posX), - (int) (p.y * scaleY) + ((i==0)?0:posY) - ); - result.add(pos); - i++; - } - } - - return result; - } - - /* (non-Javadoc) - * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#getPositions(java.util.List) - */ - @Override - public <T extends StateGraphNode> List<PosAndSize> getPositions(List<T> nodes) { - ArrayList<PosAndSize> result = new ArrayList<PosAndSize>(nodes.size()); - - if (nodes.isEmpty()) - return result; - - int n = 0; - for (T node : nodes) { - PosAndSize pt = getPosition(node); - result.add(pt); - if (pt==null) - n++; - } - - int delta = (int) (scaleX/(n+1)); - int pos = delta; - - int h = StateGraphSupport.MARGIN; - if (nodes.get(0) instanceof State) - h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/4; - else if (nodes.get(0) instanceof ChoicePoint) - h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/2; - else if (nodes.get(0) instanceof TrPoint) - h = StateGraphSupport.MARGIN; - else { - assert(false): "unexpected sub type"; - } - - for (int i=0; i<nodes.size(); ++i) { - if (result.get(i)==null) { - PosAndSize pt = new PosAndSize( - pos, - h, - 0, - 0 - ); - result.set(i, pt); - - pos += delta; - } - } - - return result; - } - - /** - * Load base class diagrams recursively and put midpoint positions relative to boundary rectangle into map. - * - * Positions are relative to the invisible rectangle. They are transformed to the border rectangle and normalized. - * - * @param mc - * @param obj2pos - */ - private void mapPositions(ModelComponent mc, Injector injector) { - if (mc==null) - return; - - DiagramAccessBase diagramAccess = injector.getInstance(DiagramAccessBase.class); - Diagram diagram = diagramAccess.getDiagram(mc); - if (diagram==null) - return; - - StateGraphContext tree = StateGraphContext.createContextTree(FSMSupportUtil.getInstance().getModelComponent(diagram), injector); - FSMNameProvider fsmNameProvider = FSMSupportUtil.getInstance().getFSMNameProvider(); - - ILinkService linkService = Graphiti.getLinkService(); - for (Shape sgShape : diagram.getChildren()) { - // this is the level of StateGraphs - if (sgShape instanceof ContainerShape) { - EObject obj = linkService.getBusinessObjectForLinkedPictogramElement(sgShape); - GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); - double width = borderRect.getWidth(); - double height = borderRect.getHeight(); - PosAndSize sz = new PosAndSize( - sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY(), - borderRect.getWidth(), borderRect.getHeight()); - sg2sz.put(fsmNameProvider.getFullPath((StateGraph) obj), sz); - for (Shape sgItemShape : ((ContainerShape)sgShape).getChildren()) { - // this is the level of States, TrPoints and ChoicePoints - obj = linkService.getBusinessObjectForLinkedPictogramElement(sgItemShape); - GraphicsAlgorithm ga = sgItemShape.getGraphicsAlgorithm(); - if(ga==null) - continue; - int margin = 0; - String path = null; - if (obj instanceof StateGraphNode) { - StateGraphNode node = (StateGraphNode)obj; - margin = getMargin(node); - path = fsmNameProvider.getFullPath((StateGraphItem) obj); - - if(sgItemShape instanceof ContainerShape){ - // sub items - for(Shape childShape : ((ContainerShape)sgItemShape).getChildren()){ - EObject childObj = linkService.getBusinessObjectForLinkedPictogramElement(childShape); - if(childObj instanceof StateGraphItem){ - GraphicsAlgorithm childGa = childShape.getGraphicsAlgorithm(); - String childPath = fsmNameProvider.getFullPath((StateGraphItem) childObj); - if (childPath != null) { - Position pos = new Position(); - pos.x = childGa.getX() / (double) (ga.getWidth() - 2 * margin); - pos.y = childGa.getY() / (double) (ga.getHeight() - 2 * margin); - pos.sx = -1; - pos.sy = -1; - subObj2pos.put(childPath, pos); - } - } - } - } - } else if(obj instanceof StateGraph){ - StateGraph graph = (StateGraph)obj; - margin = getMargin(graph); - EObject container = graph.eContainer(); - path = "#init"; - if(container instanceof StateGraphNode) - path = fsmNameProvider.getFullPath((StateGraphNode)container) + path; - initialPointObj.put(path, graph); - } - if(path != null){ - Position pos = new Position(); - pos.x = ga.getX() / width; - pos.y = ga.getY() / height; - pos.sx = (ga.getWidth() - 2*margin) / width; - pos.sy = (ga.getHeight()- 2*margin) / height; - obj2pos.put(path, pos); - } - - // Entry and Exit Points on State borders are treated by the insertion of the State - } - } - } - - for (Connection conn : diagram.getConnections()) { - EObject obj = linkService.getBusinessObjectForLinkedPictogramElement(conn); - if (obj instanceof Transition) { - ConnectionDecorator cd = conn.getConnectionDecorators().get(1); - if (cd.getGraphicsAlgorithm() instanceof Text) { - Transition trans = (Transition) obj; - StateGraph sg = tree.getContext(trans).getStateGraph(); - - // graph size - PosAndSize sz = sg2sz.get(fsmNameProvider.getFullPath(sg)); - ArrayList<Position> points = new ArrayList<Position>(); - trans2points.put(fsmNameProvider.getFullPath((Transition) obj), points); - - // label position - Position pos = new Position(); - pos.x = cd.getGraphicsAlgorithm().getX() / ((double)sz.getWidth()); - pos.y = cd.getGraphicsAlgorithm().getY() / ((double)sz.getHeight()); - points.add(pos); - - if (conn instanceof FreeFormConnection) { - for (Point bp : ((FreeFormConnection) conn).getBendpoints()) { - pos = new Position(); - pos.x = (bp.getX() - sz.getX()) / ((double)sz.getWidth()); - pos.y = (bp.getY() - sz.getY()) / ((double)sz.getHeight()); - points.add(pos); - } - } - } - - } - } - - // recursion - mapPositions(mc.getBase(), injector); - } - - private int getMargin(StateGraphNode node) { - if (node instanceof State) - return StateSupport.MARGIN; - else if (node instanceof TrPoint) - return TrPointSupport.MARGIN; - - return 0; - } - - private int getMargin(StateGraph graph) { - return 0; - } - - public StateGraph getInitialPoint(StateGraph graph){ - EObject container = graph.eContainer(); - String path = "#init"; - if(container instanceof StateGraphNode) - path = FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath((StateGraphNode)container) + path; - return initialPointObj.get(path); - } - - /* (non-Javadoc) - * @see org.eclipse.etrice.ui.behavior.support.IPositionProvider#getGraphSize(org.eclipse.etrice.core.room.StateGraph) - */ - @Override - public PosAndSize getGraphPosAndSize(StateGraph sg) { - return sg2sz.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(sg)); - } - - @Override - public double[] getSubPosition(StateGraphNode subNode) { - Position pos = subObj2pos.get(FSMSupportUtil.getInstance().getFSMNameProvider().getFullPath(subNode)); - if (pos==null) - return null; - - return new double[]{pos.x, pos.y}; - } -} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DiagramUpdateFeature.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DiagramUpdateFeature.java index 860e53b2f..bf9b7ceab 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DiagramUpdateFeature.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/DiagramUpdateFeature.java @@ -14,10 +14,12 @@ package org.eclipse.etrice.ui.behavior.fsm.support; import java.util.ArrayList; +import org.eclipse.etrice.core.fsm.fSM.FSMFactory; import org.eclipse.etrice.core.fsm.fSM.ModelComponent; import org.eclipse.etrice.core.fsm.fSM.StateGraph; -import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; -import org.eclipse.etrice.ui.behavior.fsm.provider.IInjectorProvider; +import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMDiagramTypeProvider; +import org.eclipse.etrice.ui.behavior.fsm.support.util.DiagramEditingUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.graphiti.features.IFeatureProvider; import org.eclipse.graphiti.features.IReason; import org.eclipse.graphiti.features.IRemoveFeature; @@ -33,8 +35,6 @@ import org.eclipse.graphiti.mm.pictograms.ContainerShape; import org.eclipse.graphiti.mm.pictograms.Shape; import org.eclipse.graphiti.platform.IDiagramBehavior; -import com.google.inject.Injector; - /** * @author Henrik Rentz-Reichert (initial contribution) * @@ -63,9 +63,7 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { */ @Override public IReason updateNeeded(IUpdateContext context) { - ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); - Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); - StateGraphContext tree = StateGraphContext.createContextTree(mc, injector); + IStateGraphContext tree = createStateGraphContext(); usedShapes.clear(); @@ -108,9 +106,7 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { */ @Override public boolean update(IUpdateContext context) { - ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); - Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); - StateGraphContext tree = StateGraphContext.createContextTree(mc, injector); + IStateGraphContext tree = createStateGraphContext(); StateGraph currentStateGraph = ContextSwitcher.getCurrentStateGraph(getDiagram()); @@ -169,7 +165,7 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { * @param ctx * @return */ - private IReason updateNeeded(StateGraphContext ctx) { + private IReason updateNeeded(IStateGraphContext ctx) { StateGraph sg = ctx.getStateGraph(); ContainerShape cont = findStateGraphContainer(sg); if (cont==null) @@ -196,7 +192,7 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { } // recursion - for (StateGraphContext child : ctx.getChildren()) { + for (IStateGraphContext child : ctx.getChildren()) { IReason needUpdate = updateNeeded(child); if (needUpdate.toBoolean()) return needUpdate; @@ -209,14 +205,14 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { * @param ctx * @return */ - private boolean update(StateGraphContext ctx) { + private boolean update(IStateGraphContext ctx) { boolean changed = false; StateGraph sg = ctx.getStateGraph(); ContainerShape cont = findStateGraphContainer(sg); if (cont==null) { // create - cont = FSMSupportUtil.getInstance().addStateGraph(ctx, getDiagram(), getFeatureProvider()); + cont = DiagramEditingUtil.getInstance().addStateGraph(ctx, getDiagram(), getFeatureProvider()); changed = true; usedShapes.add(cont); } @@ -242,7 +238,7 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { } // recursion - for (StateGraphContext child : ctx.getChildren()) { + for (IStateGraphContext child : ctx.getChildren()) { if (update(child)) changed = true; } @@ -262,5 +258,20 @@ public class DiagramUpdateFeature extends AbstractUpdateFeature { } return null; } + + private IStateGraphContext createStateGraphContext(){ + ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); +// Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); +// StateGraphContext tree = StateGraphContext.createContextTree(mc, injector); + + // side effect on model, but diagram needs that for initial graph shape + if(mc.getStateMachine() == null || mc.getStateMachine().eIsProxy()){ + mc.setStateMachine(FSMFactory.eINSTANCE.createStateGraph()); + } + + IStateGraphContext tree = new GenModelStateGraphContext((AbstractFSMDiagramTypeProvider)getFeatureProvider().getDiagramTypeProvider()); + + return tree; + } } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/FSMSupportUtil.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/FSMSupportUtil.java deleted file mode 100644 index 999b607e6..000000000 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/FSMSupportUtil.java +++ /dev/null @@ -1,997 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 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: - * Henrik Rentz-Reichert (initial contribution) - * - *******************************************************************************/ - -package org.eclipse.etrice.ui.behavior.fsm.support; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; -import org.eclipse.etrice.core.fsm.fSM.ChoicepointTerminal; -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.InitialTransition; -import org.eclipse.etrice.core.fsm.fSM.ModelComponent; -import org.eclipse.etrice.core.fsm.fSM.NonInitialTransition; -import org.eclipse.etrice.core.fsm.fSM.RefinedState; -import org.eclipse.etrice.core.fsm.fSM.RefinedTransition; -import org.eclipse.etrice.core.fsm.fSM.State; -import org.eclipse.etrice.core.fsm.fSM.StateGraph; -import org.eclipse.etrice.core.fsm.fSM.StateGraphItem; -import org.eclipse.etrice.core.fsm.fSM.StateGraphNode; -import org.eclipse.etrice.core.fsm.fSM.StateTerminal; -import org.eclipse.etrice.core.fsm.fSM.SubStateTrPointTerminal; -import org.eclipse.etrice.core.fsm.fSM.TrPoint; -import org.eclipse.etrice.core.fsm.fSM.TrPointTerminal; -import org.eclipse.etrice.core.fsm.fSM.Transition; -import org.eclipse.etrice.core.fsm.fSM.TransitionTerminal; -import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; -import org.eclipse.etrice.core.fsm.ui.FSMUiModule; -import org.eclipse.etrice.core.fsm.util.FSMHelpers; -import org.eclipse.etrice.core.fsm.util.FSMNewNamingUtil; -import org.eclipse.etrice.core.fsm.validation.FSMValidationUtil; -import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; -import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider.Pos; -import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider.PosAndSize; -import org.eclipse.etrice.ui.common.base.support.CommonSupportUtil; -import org.eclipse.graphiti.datatypes.ILocation; -import org.eclipse.graphiti.features.IFeatureProvider; -import org.eclipse.graphiti.features.IRemoveFeature; -import org.eclipse.graphiti.features.context.IRemoveContext; -import org.eclipse.graphiti.features.context.impl.AddConnectionContext; -import org.eclipse.graphiti.features.context.impl.AddContext; -import org.eclipse.graphiti.features.context.impl.LayoutContext; -import org.eclipse.graphiti.features.context.impl.RemoveContext; -import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; -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.Diagram; -import org.eclipse.graphiti.mm.pictograms.FreeFormConnection; -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.ILinkService; - -import com.google.inject.Inject; -import com.google.inject.Injector; - -/** - * @author Henrik Rentz-Reichert - * - */ -public class FSMSupportUtil { - - private static final String INITIAL = "init"; - private static final String STATE = "state:"; - private static final String TP = "tp:"; - private static final String CP = "cp:"; - private static final String SEP = "."; - private static FSMSupportUtil instance = null; - - /** - * @return the instance - */ - public static FSMSupportUtil getInstance() { - if (instance==null) { - // this class has members that have to be filled by the FSMUi injector - Injector injector = FSMUiModule.getInjector(); - instance = injector.getInstance(FSMSupportUtil.class); - } - return instance; - } - - @Inject - private FSMHelpers fsmHelpers; - @Inject - private FSMValidationUtil fsmValidationUtil; - @Inject - private FSMNameProvider fsmNameProvider; - @Inject - private FSMNewNamingUtil fsmNewNamingUtil; - - /** - * @return the roomHelpers - */ - public FSMHelpers getFSMHelpers() { - return fsmHelpers; - } - - /** - * @return the validationUtil - */ - public FSMValidationUtil getFSMValidationUtil() { - return fsmValidationUtil; - } - - /** - * @return the roomUtil - */ - public FSMNewNamingUtil getFSMNewNamingUtil() { - return fsmNewNamingUtil; - } - - /** - * @return the roomNameProvider - */ - public FSMNameProvider getFSMNameProvider() { - return fsmNameProvider; - } - - public 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; - } - - public boolean isInherited(Diagram diag, EObject obj) { - if(obj instanceof StateGraph) - obj = obj.eContainer(); - else if (obj instanceof ModelComponent) - return ((ModelComponent) obj).getBase() != null; - - return obj instanceof RefinedState || obj instanceof RefinedTransition || !EcoreUtil.isAncestor(getModelComponent(diag), obj); - } - - public boolean showAsInherited(Diagram diag, State obj) { - - if (obj instanceof RefinedState) - return true; - - return fsmHelpers.getModelComponent(obj)!=getModelComponent(diag); - } - - public Diagram getDiagram(GraphicsAlgorithm ga) { - if (ga.eContainer() instanceof GraphicsAlgorithm) - return getDiagram((GraphicsAlgorithm)ga.eContainer()); - return getDiagram(ga.getPictogramElement()); - } - - /** - * @param pictogramElement - * @return - */ - public Diagram getDiagram(PictogramElement pe) { - while (pe.eContainer()!=null) { - if (pe.eContainer() instanceof Diagram) - return (Diagram) pe.eContainer(); - pe = (PictogramElement) pe.eContainer(); - } - return null; - } - - public ModelComponent getModelComponent(Diagram diag) { - EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(diag); - if (bo instanceof ModelComponent) - return (ModelComponent) bo; - return null; - } - - /** - * @param sg - * @param mc - * @param targetContainer - * @param fp - * @return - */ - public StateGraph insertRefinedState(StateGraph sg, ModelComponent mc, ContainerShape targetContainer, - IFeatureProvider fp) { - sg = getSubGraphOfRefinedStateFor((State) sg.eContainer(), mc); - fp.link(targetContainer, sg); - return sg; - } - - /** - * @param sg - * @param mc - * @param targetContainer - */ - public void undoInsertRefinedState(StateGraph sg, ModelComponent mc, - ContainerShape targetContainer, IFeatureProvider fp) { - RefinedState rs = (RefinedState) sg.eContainer(); - fp.link(targetContainer, rs.getTarget().getSubgraph()); - - if (!(fsmHelpers.hasDetailCode(rs.getEntryCode()) || fsmHelpers.hasDetailCode(rs.getExitCode()))) { - mc.getStateMachine().getStates().remove(rs); - } - } - - /** - * @param s - * @param mc - * @return - */ - public StateGraph getSubGraphOfRefinedStateFor(State s, ModelComponent mc) { - RefinedState rs = getRefinedStateFor(s, mc); - - if (rs.getSubgraph()==null) - rs.setSubgraph(FSMFactory.eINSTANCE.createStateGraph()); - - return rs.getSubgraph(); - } - - public RefinedState getRefinedStateFor(State s, ModelComponent mc) { - HashMap<State, RefinedState> target2rs = new HashMap<State, RefinedState>(); - for (State st : mc.getStateMachine().getStates()) { - if (st instanceof RefinedState) - target2rs.put(((RefinedState) st).getTarget(), (RefinedState) st); - } - - RefinedState rs = null; - - // do we already have a RefinedState pointing to s? - if (target2rs.containsKey(s)) { - rs = target2rs.get(s); - } - else { - // we have to create one and place it in the best fitting context - StateGraph sg = null; - State parent = s; - while (parent.eContainer().eContainer() instanceof State) { - parent = (State) s.eContainer().eContainer(); - if (target2rs.containsKey(parent)) { - RefinedState bestFitting = target2rs.get(parent); - if (bestFitting.getSubgraph()==null) - bestFitting.setSubgraph(FSMFactory.eINSTANCE.createStateGraph()); - sg = bestFitting.getSubgraph(); - break; - } - } - - if (sg==null) - sg = mc.getStateMachine(); - - rs = FSMFactory.eINSTANCE.createRefinedState(); - rs.setTarget(s); - sg.getStates().add(rs); - } - return rs; - } - - /** - * @param state - * @param diagram - * @return - */ - public State getTargettingState(State state, Diagram diagram) { - ModelComponent mc = getModelComponent(diagram); - return fsmHelpers.getTargettingState(state, mc); - } - - /** - * This method exploits the fact that the immediate children of the diagram are - * associated with the state graphs. - * - * @param shape - * @return the container shape that is associated with the state graph of the diagram - */ - public ContainerShape getStateGraphContainer(ContainerShape shape) { - while (shape!=null) { - ContainerShape parent = shape.getContainer(); - if (parent instanceof Diagram) - return shape; - shape = parent; - } - return null; - } - - public StateGraph getStateGraph(ContainerShape cs, IFeatureProvider fp) { - ContainerShape shape = getStateGraphContainer(cs); - Object bo = fp.getBusinessObjectForPictogramElement(shape); - if (bo instanceof StateGraph) - return (StateGraph) bo; - else - assert(false): "state graph expected"; - - return null; - } - - public TransitionTerminal getTransitionTerminal(Anchor anchor, IFeatureProvider fp) { - if (anchor != null) { - Object obj = fp.getBusinessObjectForPictogramElement(anchor.getParent()); - if (obj instanceof TrPoint) { - Object parent = fp.getBusinessObjectForPictogramElement((ContainerShape) anchor.getParent().eContainer()); - if (parent instanceof State) { - State state = (parent instanceof RefinedState)? ((RefinedState)parent).getTarget() : (State)parent; - SubStateTrPointTerminal sstpt = FSMFactory.eINSTANCE.createSubStateTrPointTerminal(); - sstpt.setState(state); - sstpt.setTrPoint((TrPoint) obj); - return sstpt; - } - else { - TrPointTerminal tpt = FSMFactory.eINSTANCE.createTrPointTerminal(); - tpt.setTrPoint((TrPoint) obj); - return tpt; - } - } - else if (obj instanceof State) { - State state = (obj instanceof RefinedState)? ((RefinedState)obj).getTarget() : (State)obj; - StateTerminal st = FSMFactory.eINSTANCE.createStateTerminal(); - st.setState(state); - return st; - } - else if (obj instanceof ChoicePoint) { - ChoicepointTerminal ct = FSMFactory.eINSTANCE.createChoicepointTerminal(); - ct.setCp((ChoicePoint) obj); - return ct; - } - } - return null; - } - - public boolean isInitialPoint(Anchor anchor, IFeatureProvider fp) { - if (anchor!=null) { - Object obj = fp.getBusinessObjectForPictogramElement(anchor.getParent()); - if (obj instanceof StateGraph) { - Object parent = fp.getBusinessObjectForPictogramElement((ContainerShape) anchor.getParent().eContainer()); - if (parent instanceof StateGraph) - return true; - } - } - return false; - } - - public boolean canConnect(Anchor asrc, Anchor atgt, ContainerShape cs, IFeatureProvider fp) { - return canConnect(asrc, atgt, null, cs, fp); - } - - public boolean canConnect(Anchor asrc, Anchor atgt, Transition trans, - ContainerShape cs, IFeatureProvider fp) { - TransitionTerminal src = getTransitionTerminal(asrc, fp); - TransitionTerminal tgt = getTransitionTerminal(atgt, fp); - - if (src==null && !isInitialPoint(asrc, fp)) - return false; - if (tgt==null) - return false; - - StateGraph sg = getStateGraph(cs, fp); - if (sg==null) - return false; - - return fsmValidationUtil.isConnectable(src, tgt, trans, sg).isOk(); - } - - /** - * @param s the state whose sub structure should be deleted - * @param mc the ModelComponent - * @param diagram the current diagram - * @param fp the feature provider - */ - public void deleteSubStructureRecursive(State s, ModelComponent mc, - Diagram diagram, IFeatureProvider fp) { - if (fsmHelpers.hasSubStructure(s, mc)) { - StateGraph subgraph = s.getSubgraph(); - - // depth first - for (State st : subgraph.getStates()) { - deleteSubStructureRecursive(st, mc, diagram, fp); - } - - ContainerShape subShape = ContextSwitcher.getContext(diagram, subgraph); - CommonSupportUtil.deleteConnectionsRecursive(subShape, fp); - EcoreUtil.delete(subShape, true); - } - } - - public List<State> getStates(ContainerShape shape, IFeatureProvider fp) { - return getStates(shape, fp, null, null); - } - - private List<State> getStates(ContainerShape shape, IFeatureProvider fp, Map<String, Anchor> item2anchor, List<Shape> stateShapes) { - List<State> items = new ArrayList<State>(); - for (Shape ch : shape.getChildren()) { - Object bo = fp.getBusinessObjectForPictogramElement(ch); - if (bo instanceof State) { - items.add((State)bo); - if (item2anchor!=null) - item2anchor.put(getKey((State)bo), ch.getAnchors().get(0)); - if (stateShapes!=null) - stateShapes.add(ch); - } - } - return items; - } - - public List<ChoicePoint> getChoicePoints(ContainerShape shape, IFeatureProvider fp) { - return getChoicePoints(shape, fp, null, null); - } - - private List<ChoicePoint> getChoicePoints(ContainerShape shape, IFeatureProvider fp, Map<String, Anchor> item2anchor, - List<Shape> cpShapes) { - List<ChoicePoint> items = new ArrayList<ChoicePoint>(); - for (Shape ch : shape.getChildren()) { - Object bo = fp.getBusinessObjectForPictogramElement(ch); - if (bo instanceof ChoicePoint) { - items.add((ChoicePoint)bo); - if (item2anchor!=null) - item2anchor.put(getKey((ChoicePoint)bo), ch.getAnchors().get(0)); - if (cpShapes!=null) - cpShapes.add(ch); - } - } - return items; - } - - public List<TrPoint> getTrPoints(StateGraph sg, ContainerShape shape, IFeatureProvider fp) { - return getTrPoints(sg, shape, fp, null, null); - } - - private List<TrPoint> getTrPoints(StateGraph sg, ContainerShape shape, IFeatureProvider fp, - Map<String, Anchor> item2anchor, List<Shape> tpShapes) { - List<TrPoint> items = new ArrayList<TrPoint>(); - for (Shape ch : shape.getChildren()) { - Object bo = fp.getBusinessObjectForPictogramElement(ch); - if (bo instanceof TrPoint) { - items.add((TrPoint)bo); - if (item2anchor!=null) - item2anchor.put(getKey((TrPoint)bo), ch.getAnchors().get(0)); - if (tpShapes!=null) - tpShapes.add(ch); - } - } - return items; - } - - /** - * @param diagram - * @param fp - * @return - */ - public List<Transition> getTransitions(Diagram diagram, IFeatureProvider fp) { - List<Transition> transitions = new ArrayList<Transition>(); - for (Connection conn : diagram.getConnections()) { - Object bo = fp.getBusinessObjectForPictogramElement(conn); - if (bo instanceof Transition) - transitions.add((Transition) bo); - } - return transitions; - } - - private Map<Transition, Connection> getTransitionsMap(ContainerShape sgShape, IFeatureProvider fp) { - Diagram diagram = (Diagram) sgShape.eContainer(); - Map<Transition, Connection> transitions = new HashMap<Transition, Connection>(); - for (Connection conn : diagram.getConnections()) { - Object bo = fp.getBusinessObjectForPictogramElement(conn); - - // we only collect connections that have a starting point contained in our sgShape - if (bo instanceof Transition && EcoreUtil.isAncestor(sgShape, conn.getStart())) - transitions.put((Transition) bo, conn); - } - return transitions; - } - - /** - * @param sgShape - * @param node2anchor - */ - private void getSubTpAnchors(ContainerShape sgShape, HashMap<String, Anchor> node2anchor) { - for (Shape childShape : sgShape.getChildren()) { - EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(childShape); - if (bo instanceof State) - getAnchors((State) bo, childShape, node2anchor); - } - } - - public ContainerShape addStateGraph(StateGraphContext ctx, Diagram diagram, IFeatureProvider fp) { - AddContext addContext = new AddContext(); - addContext.setNewObject(ctx.getStateGraph()); - addContext.setTargetContainer(diagram); - PosAndSize graphPosAndSize = ctx.getPositionProvider().getGraphPosAndSize(ctx.getStateGraph()); - if (graphPosAndSize!=null) { - addContext.setX(graphPosAndSize.getX()); - addContext.setY(graphPosAndSize.getY()); - addContext.setWidth(graphPosAndSize.getWidth()); - addContext.setHeight(graphPosAndSize.getHeight()); - } - else { - addContext.setX(StateGraphSupport.MARGIN); - addContext.setY(StateGraphSupport.MARGIN); - } - - ContainerShape sgShape = (ContainerShape) fp.addIfPossible(addContext); - if (sgShape==null) - return null; - - final HashMap<String, Anchor> node2anchor = new HashMap<String, Anchor>(); - - GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); - ctx.getPositionProvider().setScale(borderRect.getWidth(), borderRect.getHeight()); - ctx.getPositionProvider().setPosition(sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY()); - - addInitialPointIff(ctx, ctx.getPositionProvider(), sgShape, fp, node2anchor); - addStateGraphNodes(ctx.getTrPoints(), ctx.getPositionProvider(), sgShape, fp, node2anchor); - addStateGraphNodes(ctx.getStates(), ctx.getPositionProvider(), sgShape, fp, node2anchor); - addStateGraphNodes(ctx.getChPoints(), ctx.getPositionProvider(), sgShape, fp, node2anchor); - - for (StateGraphContext sub : ctx.getChildren()) { - addStateGraph(sub, diagram, fp); - } - - getSubTpAnchors(sgShape, node2anchor); - - addTransitions(ctx.getTransitions(), ctx.getPositionProvider(), sgShape, fp, node2anchor); - - return sgShape; - } - - private void addInitialPointIff(StateGraphContext ctx, IPositionProvider positionProvider, ContainerShape sgShape, - IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { - - // model - StateGraph sg = ctx.getInitialPoint(); - if(sg==null) - // (super class) diagram - sg = positionProvider.getInitialPoint(ctx.getStateGraph()); - if(sg==null) - return; - - PosAndSize pos = positionProvider.getPosition(sg); - AddContext addContext = new AddContext(); - addContext.setNewObject(sg); - addContext.setTargetContainer(sgShape); - if(pos != null){ - addContext.setX(pos.getX()); - addContext.setY(pos.getY()); - if (pos.getWidth()>0 && pos.getHeight()>0) { - addContext.setWidth(pos.getWidth()); - addContext.setHeight(pos.getHeight()); - } - } else { - addContext.setX(3*StateGraphSupport.MARGIN); - addContext.setY(3*StateGraphSupport.MARGIN); - } - - ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext); - assert(pe!=null): "initial point should have been created"; - assert(!pe.getAnchors().isEmpty()): "initial point should have an anchor"; - node2anchor.put(INITIAL, pe.getAnchors().get(0)); - } - - public void updateStateGraph(StateGraph sg, StateGraphContext ctx, ContainerShape sgShape, - IFeatureProvider fp) { - - HashMap<String, Anchor> node2anchor = new HashMap<String, Anchor>(); - - GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); - ctx.getPositionProvider().setScale(borderRect.getWidth(), borderRect.getHeight()); - ctx.getPositionProvider().setPosition(sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY()); - - // states - { - ArrayList<Shape> shapes = new ArrayList<Shape>(); - List<State> present = getStates(sgShape, fp, node2anchor, shapes); - checkDuplicates(present); - List<State> expected = ctx.getStates(); - List<State> toAdd = new ArrayList<State>(); - List<State> toUpdate = new ArrayList<State>(); - List<State> toRemove = new ArrayList<State>(); - for (State item : expected) { - if (present.contains(item)) - toUpdate.add(item); - else - toAdd.add(item); - } - for(State item : present){ - if(!expected.contains(item)) - toRemove.add(item); - } - addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); - updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); - removeGraphicalRepresentation(toRemove, shapes, fp); - } - - // transition points - { - ArrayList<Shape> shapes = new ArrayList<Shape>(); - List<TrPoint> present = getTrPoints(sg, sgShape, fp, node2anchor, shapes); - checkDuplicates(present); - List<TrPoint> expected = ctx.getTrPoints(); - List<TrPoint> toAdd = new ArrayList<TrPoint>(); - List<TrPoint> toUpdate = new ArrayList<TrPoint>(); - List<TrPoint> toRemove = new ArrayList<TrPoint>(); - for (TrPoint item : expected) { - if (present.contains(item)) - toUpdate.add(item); - else - toAdd.add(item); - } - for(TrPoint item : present){ - if(!expected.contains(item)) - toRemove.add(item); - } - addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); - updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); - removeGraphicalRepresentation(toRemove, shapes, fp); - } - - // choice points - { - ArrayList<Shape> shapes = new ArrayList<Shape>(); - List<ChoicePoint> present = getChoicePoints(sgShape, fp, node2anchor, shapes); - checkDuplicates(present); - List<ChoicePoint> expected = ctx.getChPoints(); - List<ChoicePoint> toAdd = new ArrayList<ChoicePoint>(); - List<ChoicePoint> toUpdate = new ArrayList<ChoicePoint>(); - List<ChoicePoint> toRemove = new ArrayList<ChoicePoint>(); - for (ChoicePoint item : expected) { - if (present.contains(item)) - toUpdate.add(item); - else - toAdd.add(item); - } - for(ChoicePoint item : present){ - if(!expected.contains(item)) - toRemove.add(item); - } - addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); - updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); - removeGraphicalRepresentation(toRemove, shapes, fp); - } - - getSubTpAnchors(sgShape, node2anchor); - - // initial point - { - // exists in this diagram ? - Shape present = null; - for (Shape ch : sgShape.getChildren()) { - Object bo = fp.getBusinessObjectForPictogramElement(ch); - if (bo instanceof StateGraph) - present = ch; - } - if(present != null) - node2anchor.put(INITIAL, present.getAnchors().get(0)); - // exists in model ? - StateGraph expected = ctx.getInitialPoint(); - if(expected == null) - // exists in (super class) diagram ? - expected = ctx.getPositionProvider().getInitialPoint(ctx.getStateGraph()); - if(expected != null && present == null) - addInitialPointIff(ctx, ctx.getPositionProvider(), sgShape, fp, node2anchor); - else - updateInitialPoint(present, ctx.getPositionProvider(), fp); - } - - // transitions - { - // get transitions that belong to our state graph - // (for other connections we might not have the node anchors yet) - Map<Transition, Connection> present = getTransitionsMap(sgShape, fp); - List<Transition> expected = ctx.getTransitions(); - List<Transition> toAdd = new ArrayList<Transition>(); - List<Transition> toRemove = new ArrayList<Transition>(); - for (Transition trans : expected) - if (!present.containsKey(trans)) - toAdd.add(trans); - for(Transition item : present.keySet()){ - if(!expected.contains(item)) - toRemove.add(item); - } - addTransitions(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); - updateTransitions(present, ctx.getPositionProvider(), sgShape, fp, node2anchor); - removeGraphicalRepresentation(toRemove, present.values(), fp); - } - } - - /** - * @param items - */ - private void checkDuplicates(List<? extends StateGraphItem> items) { - for (StateGraphItem item : items) { - if (items.indexOf(item)!=items.lastIndexOf(item)) { - Assert.isTrue( - items.indexOf(item)==items.lastIndexOf(item), - "multiple occurrences of "+fsmNameProvider.getFullPath(item)); - } - } - } - - private void addTransitions(List<Transition> transitions, IPositionProvider positionProvider, ContainerShape sgShape, - IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { - - for (Transition trans : transitions) { - String from = (trans instanceof InitialTransition)? INITIAL:getKey(((NonInitialTransition)trans).getFrom()); - String to = getKey(trans.getTo()); - Anchor src = node2anchor.get(from); - Anchor dst = node2anchor.get(to); - - assert(src!=null && dst!=null): "transition endpoints must be present"; - - AddConnectionContext context = new AddConnectionContext(src, dst); - context.setNewObject(trans); - PictogramElement pe = fp.addIfPossible(context); - if (pe instanceof FreeFormConnection) { - FreeFormConnection conn = (FreeFormConnection) pe; - - // JH: workaround for correct bend points of inherited self transition - conn.getBendpoints().clear(); - - List<Pos> points = positionProvider.getPoints(trans); - if (points!=null && !points.isEmpty()) { - Iterator<Pos> it = points.iterator(); - - // first is label position - Pos pos = it.next(); - ConnectionDecorator cd = conn.getConnectionDecorators().get(1); - Graphiti.getGaService().setLocation(cd.getGraphicsAlgorithm(), pos.getX(), pos.getY()); - - // remaining are bend points - while (it.hasNext()) { - pos = it.next(); - Point pt = Graphiti.getGaService().createPoint(pos.getX(), pos.getY()); - conn.getBendpoints().add(pt); - } - } - else if (src==dst) { - ILocation begin = Graphiti.getPeService().getLocationRelativeToDiagram(conn.getStart()); - Point pt = Graphiti.getGaService().createPoint(begin.getX(), begin.getY()+StateGraphSupport.MARGIN*3); - conn.getBendpoints().add(pt); - } - } - } - } - - private void addStateGraphNodes(List<? extends StateGraphNode> nodes, IPositionProvider positionProvider, ContainerShape sgShape, - IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { - - List<PosAndSize> positions = positionProvider.getPositions(nodes); - - int idx = 0; - for (StateGraphNode node : nodes) { - addStateGraphNode(node, sgShape, positions.get(idx), fp, node2anchor); - ++idx; - } - } - - private void addStateGraphNode(StateGraphNode tp, ContainerShape sgShape, PosAndSize pos, - IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { - AddContext addContext = new AddContext(); - addContext.setNewObject(tp); - addContext.setTargetContainer(sgShape); - addContext.setX(pos.getX()); - addContext.setY(pos.getY()); - if (pos.getWidth()>0 && pos.getHeight()>0) { - addContext.setWidth(pos.getWidth()); - addContext.setHeight(pos.getHeight()); - } - - ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext); - assert(pe!=null): tp.eClass().getName()+" should have been created"; - assert(!pe.getAnchors().isEmpty()): tp.eClass().getName()+" should have an anchor"; - node2anchor.put(getKey(tp), pe.getAnchors().get(0)); - } - - private void updateInitialPoint(Shape shape, IPositionProvider positionProvider, IFeatureProvider fp) { - if (shape==null) - return; - - StateGraph sg = (StateGraph) fp.getBusinessObjectForPictogramElement(shape); - PosAndSize ps = positionProvider.getPosition(sg); - if (ps==null) - return; - - // relocate and resize the invisible rectangle - GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); - - Graphiti.getLayoutService().setLocationAndSize( - ga, - ps.getX(), - ps.getY(), - ps.getWidth(), - ps.getHeight() - ); - - // have to call the layout to adjust the visible border - LayoutContext lc = new LayoutContext(shape); - fp.layoutIfPossible(lc); - } - - private void updateStateGraphNodes(List<? extends StateGraphNode> nodes, List<Shape> shapes, - IPositionProvider positionProvider, IFeatureProvider fp) { - - ILinkService linkService = Graphiti.getLinkService(); - IGaService gaService = Graphiti.getGaService(); - - for (StateGraphNode node : nodes) { - PosAndSize ps = positionProvider.getPosition(node); - if (ps==null) - continue; - - // TODO: sub-optimal since quadratic effort - use combined list for nodes and shapes or similar solution - for (Shape shape : shapes) { - EObject bo = linkService.getBusinessObjectForLinkedPictogramElement(shape); - if (bo==node) { - // relocate and resize the invisible rectangle - GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); -// System.out.println(node + ": "+ga.getX()+" "+ga.getY()+" "+ga.getWidth()+" "+ga.getHeight()); -// System.out.println(" -> "+ps.getX()+" "+ps.getY()+" "+ps.getWidth()+" "+ps.getHeight()); - - int margin = 0; - if (node instanceof State) - margin = StateSupport.MARGIN; - else if (node instanceof TrPoint) - margin = TrPointSupport.MARGIN; - - gaService.setLocationAndSize( - ga, - ps.getX()-margin, - ps.getY()-margin, - ps.getWidth()+2*margin, - ps.getHeight()+2*margin - ); - - // have to call the layout to adjust the visible border - LayoutContext lc = new LayoutContext(shape); - fp.layoutIfPossible(lc); - - // update position of sub items - if(shape instanceof ContainerShape){ - ContainerShape container = (ContainerShape) shape; - for(Shape child : container.getChildren()){ - EObject childBo = linkService.getBusinessObjectForLinkedPictogramElement(child); - if(!(childBo instanceof StateGraphNode)) - continue; - - double[] relPos = positionProvider.getSubPosition((StateGraphNode) childBo); - if(relPos != null) - gaService.setLocation(child.getGraphicsAlgorithm(), (int)(relPos[0] * ps.getWidth()), (int)(relPos[1]*ps.getHeight())); - } - } - - break; - } - } - } - } - - public void removeGraphicalRepresentation(Collection<? extends EObject> toRemove, Collection<? extends PictogramElement> pictograms, IFeatureProvider fp) { - for(EObject bo : toRemove) - for(PictogramElement pe : pictograms) - if(fp.getBusinessObjectForPictogramElement(pe) == bo){ - IRemoveContext rc = new RemoveContext(pe); - IRemoveFeature removeFeature = fp.getRemoveFeature(rc); - if (removeFeature != null) - removeFeature.remove(rc); - break; - } - } - - private void updateTransitions(Map<Transition, Connection> transitions, IPositionProvider positionProvider, ContainerShape sgShape, - IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { - - for(Entry<Transition, Connection> e: transitions.entrySet()){ - Transition trans = e.getKey(); - Connection conn = e.getValue(); - - String from = (trans instanceof InitialTransition)? INITIAL:getKey(((NonInitialTransition)trans).getFrom()); - String to = getKey(trans.getTo()); - Anchor newSrc = node2anchor.get(from); - Anchor newDst = node2anchor.get(to); - - assert(newSrc!=null && newDst!=null): "transition endpoints must be present"; - - if(conn.getStart()!=newSrc) - conn.setStart(newSrc); - if(conn.getEnd()!=newDst) - conn.setEnd(newDst); - - List<Pos> points = positionProvider.getPoints(trans); - Iterator<Pos> it = points.iterator(); - if (points==null || points.isEmpty()) - continue; - - // first is label position - Pos pos = it.next(); - ConnectionDecorator cd = conn.getConnectionDecorators().get(1); - Graphiti.getGaService().setLocation(cd.getGraphicsAlgorithm(), pos.getX(), pos.getY()); - - if (conn instanceof FreeFormConnection) { - FreeFormConnection fconn = (FreeFormConnection) conn; - - // remaining are bend points - fconn.getBendpoints().clear(); - List<Point> bendpoints = new ArrayList<Point>(); - while (it.hasNext()) { - pos = it.next(); - Point pt = Graphiti.getGaService().createPoint(pos.getX(), pos.getY()); - bendpoints.add(pt); - } - fconn.getBendpoints().addAll(bendpoints); - } - } - } - - private void getAnchors(State state, PictogramElement stateShape, final HashMap<String, Anchor> node2anchor) { - - if (stateShape instanceof ContainerShape) { - node2anchor.put(getKey(state), ((ContainerShape)stateShape).getAnchors().get(0)); - for (Shape child : ((ContainerShape) stateShape).getChildren()) { - if (child instanceof ContainerShape) { - ContainerShape childShape = (ContainerShape) child; - if (!childShape.getAnchors().isEmpty()) { - if (!childShape.getLink().getBusinessObjects().isEmpty()) { - EObject obj = childShape.getLink().getBusinessObjects().get(0); - if (obj instanceof EntryPoint || obj instanceof ExitPoint) { - node2anchor.put(getKey(obj, true), childShape.getAnchors().get(0)); - } - } - } - } - } - } - } - - private String getKey(EObject obj) { - return getKey(obj, false); - } - - private String getKey(EObject obj, boolean subTp) { - if (obj instanceof TrPoint) { - TrPoint tp = (TrPoint) obj; - if (!subTp) - return TP+tp.getName(); - else { - if (tp.eContainer().eContainer() instanceof State) { - State s = (State) tp.eContainer().eContainer(); - return TP+tp.getName()+SEP+s.getName(); - } - else { - assert(false): "State expected"; - } - } - } - else if (obj instanceof State) { - return STATE+((State)obj).getName(); - } - else if (obj instanceof ChoicePoint) { - return CP+((ChoicePoint)obj).getName(); - } - else if (obj instanceof TransitionTerminal) { - TransitionTerminal tt = (TransitionTerminal) obj; - if (tt instanceof ChoicepointTerminal) { - return CP+((ChoicepointTerminal)tt).getCp().getName(); - } - else if (tt instanceof StateTerminal) { - return STATE+((StateTerminal)tt).getState().getName(); - } - else if (tt instanceof SubStateTrPointTerminal) { - SubStateTrPointTerminal sstt = (SubStateTrPointTerminal) tt; - return TP+sstt.getTrPoint().getName()+SEP+sstt.getState().getName(); - } - else if (tt instanceof TrPointTerminal) { - return TP+((TrPointTerminal)tt).getTrPoint().getName(); - } - else { - assert(false): "unexpected sub type"; - } - } - assert(false): "unexpected type"; - return null; - } - -} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/GenModelStateGraphContext.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/GenModelStateGraphContext.xtend new file mode 100644 index 000000000..97ee76065 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/GenModelStateGraphContext.xtend @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support + +import org.eclipse.etrice.core.fsm.fSM.ChoicePoint +import org.eclipse.etrice.core.fsm.fSM.InitialTransition +import org.eclipse.etrice.core.fsm.fSM.State +import org.eclipse.etrice.core.fsm.fSM.TrPoint +import org.eclipse.etrice.core.fsm.fSM.Transition +import org.eclipse.etrice.core.genmodel.fsm.fsmgen.Graph +import org.eclipse.etrice.ui.behavior.fsm.editor.AbstractFSMDiagramTypeProvider +import org.eclipse.etrice.ui.behavior.fsm.provider.BaseDiagramProvider +import org.eclipse.etrice.ui.behavior.fsm.provider.GenModelProvider +import org.eclipse.etrice.core.fsm.fSM.RefinedTransition + +/** + * StateGraphContext based on newfsmgen. + */ +class GenModelStateGraphContext implements IStateGraphContext { + + val GenModelProvider genModel + val BaseDiagramPositionProvider baseDiagram + val Graph graph + + new(AbstractFSMDiagramTypeProvider diagramTypeProvider){ + this.genModel = diagramTypeProvider.genModelProvider + this.baseDiagram = new BaseDiagramPositionProvider(new BaseDiagramProvider(diagramTypeProvider)) + this.graph = genModel.model.graph + } + + new(Graph graph, GenModelStateGraphContext other){ + this.genModel = other.genModel + this.baseDiagram = other.baseDiagram + this.graph = graph + } + + // + // IStateGraphContext + // + + override getChPoints() { + graph.nodes.map[it.stateGraphNode].filter(ChoicePoint).toList + } + + override getChildren() { + graph.nodes.filter[it.subgraph !== null].map[new GenModelStateGraphContext(it.subgraph, this) as IStateGraphContext].toList + } + + override getInitialPoint() { + // return a Graph as initial point ?!? + if(!graph.links.map[transition].filter(InitialTransition).empty) graph.stateGraph + } + + override getParentState() { + graph.node.stateGraphNode as State + } + + override getPositionProvider() { + return baseDiagram + } + + override getStateGraph() { + graph.stateGraph + } + + override getStates() { + graph.nodes.map[it.stateGraphNode].filter(State).toList + } + + override getTrPoints() { + graph.nodes.map[it.stateGraphNode].filter(TrPoint).toList + } + + override getTransitions() { + val baseTransitions = graph.links.map[it.transition] + + // we take the union of Transitions and targets of RefinedTransitions + (baseTransitions.filter(Transition) + baseTransitions.filter(RefinedTransition).map[target]).toList + } + +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/IStateGraphContext.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/IStateGraphContext.java new file mode 100644 index 000000000..5764c136d --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/IStateGraphContext.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support; + +import java.util.List; + +import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; +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.Transition; + +/** + * Interface to change implementation of StateGraphContext (newfsmgen) + */ +public interface IStateGraphContext { + + public State getParentState(); + + public List<IStateGraphContext> getChildren(); + + public List<State> getStates(); + + public List<ChoicePoint> getChPoints(); + + public StateGraph getStateGraph(); + + public List<TrPoint> getTrPoints(); + + public List<Transition> getTransitions(); + + public IPositionProvider getPositionProvider(); + + public StateGraph getInitialPoint(); +} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/InitialPointSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/InitialPointSupport.java index aa55c2c6b..c38007be6 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/InitialPointSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/InitialPointSupport.java @@ -13,11 +13,14 @@ package org.eclipse.etrice.ui.behavior.fsm.support; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.etrice.core.fsm.fSM.InitialTransition; import org.eclipse.etrice.core.fsm.fSM.ModelComponent; import org.eclipse.etrice.core.fsm.fSM.StateGraph; import org.eclipse.etrice.core.fsm.fSM.Transition; import org.eclipse.etrice.ui.behavior.fsm.provider.ImageProvider; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.ModelEditingUtil; 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; @@ -28,8 +31,10 @@ 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.IDeleteContext; @@ -37,11 +42,15 @@ 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.IUpdateContext; import org.eclipse.graphiti.features.context.impl.CreateConnectionContext; +import org.eclipse.graphiti.features.context.impl.RemoveContext; import org.eclipse.graphiti.features.impl.AbstractAddFeature; import org.eclipse.graphiti.features.impl.AbstractCreateFeature; +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.Rectangle; @@ -93,10 +102,9 @@ public class InitialPointSupport { ContainerShape targetContainer = context.getTargetContainer(); StateGraph sg = (StateGraph) targetContainer.getLink().getBusinessObjects().get(0); - boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); - if (inherited) { - ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); - sg = FSMSupportUtil.getInstance().insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); + ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); + if (!FSMSupportUtil.getInstance().isOwnedBy(mc, sg)) { + sg = ModelEditingUtil.insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); } // We don't create anything here since in the model the initial point is @@ -155,14 +163,15 @@ public class InitialPointSupport { ContainerShape sgShape = context.getTargetContainer(); StateGraph sg = (StateGraph) context.getNewObject(); - boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); + Transition initTransition = FSMSupportUtil.getInstance().getFSMHelpers().getInitTransition(sg); + boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), initTransition); // CONTAINER SHAPE WITH RECTANGLE IPeCreateService peCreateService = Graphiti.getPeCreateService(); ContainerShape containerShape = peCreateService.createContainerShape(sgShape, true); - Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.TRP_TYPE); + Graphiti.getPeService().setPropertyValue(containerShape, Constants.TYPE_KEY, Constants.INI_TYPE); int x = context.getX()-ITEM_SIZE; int y = context.getY()-ITEM_SIZE; @@ -215,7 +224,8 @@ public class InitialPointSupport { if (canMove) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof StateGraph) { - return !FSMSupportUtil.getInstance().isInherited(getDiagram(), (StateGraph)bo); + Transition initTransition = FSMSupportUtil.getInstance().getFSMHelpers().getInitTransition((StateGraph) bo); + return !FSMSupportUtil.getInstance().isInherited(getDiagram(), initTransition); } return false; } @@ -224,6 +234,58 @@ public class InitialPointSupport { } } + 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 StateGraph; + } + + @Override + public IReason updateNeeded(IUpdateContext context) { + Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); + if (bo instanceof EObject && ((EObject)bo).eIsProxy()) { + return Reason.createTrueReason("InitialPoint deleted from model"); + } + + 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; + } + + if (bo instanceof StateGraph) { + Transition initTransition = FSMSupportUtil.getInstance().getFSMHelpers().getInitTransition((StateGraph) bo); + boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), initTransition); + + Color dark = manageColor(inherited? INHERITED_COLOR:DARK_COLOR); + updateFigure(containerShape, dark, manageColor(BRIGHT_COLOR)); + } + return true; + } + + } + protected static class RemoveFeature extends DefaultRemoveFeature { public RemoveFeature(IFeatureProvider fp) { @@ -233,7 +295,8 @@ public class InitialPointSupport { public boolean canRemove(IRemoveContext context) { Object bo = getBusinessObjectForPictogramElement(context.getPictogramElement()); if (bo instanceof StateGraph) { - return !FSMSupportUtil.getInstance().isInherited(getDiagram(), (StateGraph) bo); + Transition initTransition = FSMSupportUtil.getInstance().getFSMHelpers().getInitTransition((StateGraph) bo); + return !FSMSupportUtil.getInstance().isInherited(getDiagram(), initTransition); } return false; } @@ -300,6 +363,11 @@ public class InitialPointSupport { return new DeleteFeature(fp); } + @Override + public IUpdateFeature getUpdateFeature(IUpdateContext context) { + return new UpdateFeature(fp); + } + protected static void createFigure( ContainerShape containerShape, GraphicsAlgorithm invisibleRectangle, Color darkColor, Color brightColor) { @@ -325,7 +393,18 @@ public class InitialPointSupport { //containerShape.getAnchors().get(0).setReferencedGraphicsAlgorithm(rect); } } - + + private static void updateFigure(PictogramElement pe, Color dark, Color bright) { + ContainerShape container = (ContainerShape)pe; + + // we clear the figure and rebuild it + GraphicsAlgorithm borderRect = pe.getGraphicsAlgorithm(); + while (!borderRect.getGraphicsAlgorithmChildren().isEmpty()) { + EcoreUtil.delete(borderRect.getGraphicsAlgorithmChildren().get(0), true); + } + + createFigure(container, borderRect, dark, bright); + } } private class BehaviorProvider extends DefaultToolBehaviorProvider { diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphSupport.java index e690751e6..16a1795b2 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphSupport.java @@ -19,13 +19,16 @@ import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; +import org.eclipse.etrice.core.fsm.fSM.RefinedState; 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.Transition; -import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; +import org.eclipse.etrice.core.fsm.util.FSMHelpers; 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.support.util.DiagramEditingUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; import org.eclipse.etrice.ui.common.base.support.DeleteWithoutConfirmFeature; import org.eclipse.graphiti.dt.IDiagramTypeProvider; import org.eclipse.graphiti.features.IAddFeature; @@ -72,6 +75,8 @@ 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.swt.widgets.Display; import com.google.common.collect.Sets; @@ -273,6 +278,22 @@ public class StateGraphSupport { Object bo = getBusinessObjectForPictogramElement(container); if (bo instanceof StateGraph) { StateGraph sg = (StateGraph) bo; + if (sg.eContainer() instanceof RefinedState) { + RefinedState rs = (RefinedState) sg.eContainer(); + FSMHelpers fsmHelpers = FSMSupportUtil.getInstance().getFSMHelpers(); + if (fsmHelpers.isEmpty(sg)) { + // check action codes + boolean entryEmpty = fsmHelpers.getDetailCode(rs.getEntryCode()).trim().isEmpty(); + boolean exitEmpty = fsmHelpers.getDetailCode(rs.getExitCode()).trim().isEmpty(); + boolean doEmpty = fsmHelpers.getDetailCode(rs.getDoCode()).trim().isEmpty(); + if (entryEmpty && exitEmpty && doEmpty) { + MessageDialog.openInformation(Display.getCurrent().getActiveShell(), + "Check of Refined State", + "A Refined State with empty action codes must have a non-empty sub state graph."); + return; + } + } + } getDiagramBehavior().getDiagramContainer().selectPictogramElements(new PictogramElement[] {}); ContextSwitcher.goUp(getDiagram(), sg); } @@ -314,12 +335,12 @@ public class StateGraphSupport { int obsolete = 0; if (context instanceof StateGraphUpdateContext) { - StateGraphContext ctx = ((StateGraphUpdateContext)context).getContext(); + IStateGraphContext ctx = ((StateGraphUpdateContext)context).getContext(); // check for states added in model not present in diagram (including inherited) { Set<State> expected = Sets.newHashSet(ctx.getStates()); - Set<State> present = Sets.newHashSet(FSMSupportUtil.getInstance().getStates(shape, fp)); + Set<State> present = Sets.newHashSet(DiagramEditingUtil.getInstance().getStates(shape, fp)); if((missing = Sets.difference(expected, present).size()) > 0) reason += missing+" missing states\n"; @@ -331,7 +352,7 @@ public class StateGraphSupport { { missing = obsolete = 0; Set<TrPoint> expected = Sets.newHashSet(ctx.getTrPoints()); - Set<TrPoint> present = Sets.newHashSet(FSMSupportUtil.getInstance().getTrPoints(sg, shape, fp)); + Set<TrPoint> present = Sets.newHashSet(DiagramEditingUtil.getInstance().getTrPoints(sg, shape, fp)); if((missing = Sets.difference(expected, present).size()) > 0) reason += missing+" missing transition points\n"; @@ -343,7 +364,7 @@ public class StateGraphSupport { { missing = obsolete = 0; Set<ChoicePoint> expected = Sets.newHashSet(ctx.getChPoints()); - Set<ChoicePoint> present = Sets.newHashSet(FSMSupportUtil.getInstance().getChoicePoints(shape, fp)); + Set<ChoicePoint> present = Sets.newHashSet(DiagramEditingUtil.getInstance().getChoicePoints(shape, fp)); if((missing = Sets.difference(expected, present).size()) > 0) reason += missing+" missing choice points\n"; @@ -401,9 +422,9 @@ public class StateGraphSupport { StateGraph sg = (StateGraph) bo; if (context instanceof StateGraphUpdateContext) { - StateGraphContext ctx = ((StateGraphUpdateContext)context).getContext(); + IStateGraphContext ctx = ((StateGraphUpdateContext)context).getContext(); - FSMSupportUtil.getInstance().updateStateGraph(sg, ctx, sgShape, fp); + DiagramEditingUtil.getInstance().updateStateGraph(sg, ctx, sgShape, fp); } if (!sgShape.getChildren().isEmpty()) { diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphUpdateContext.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphUpdateContext.java index 82c766c07..a1afa2204 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphUpdateContext.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateGraphUpdateContext.java @@ -12,7 +12,6 @@ package org.eclipse.etrice.ui.behavior.fsm.support; -import org.eclipse.etrice.ui.behavior.fsm.commands.StateGraphContext; import org.eclipse.graphiti.features.context.impl.UpdateContext; import org.eclipse.graphiti.mm.pictograms.PictogramElement; @@ -22,12 +21,12 @@ import org.eclipse.graphiti.mm.pictograms.PictogramElement; */ public class StateGraphUpdateContext extends UpdateContext { - private StateGraphContext context; + private IStateGraphContext context; /** * @param pictogramElement */ - public StateGraphUpdateContext(PictogramElement pe, StateGraphContext ctx) { + public StateGraphUpdateContext(PictogramElement pe, IStateGraphContext ctx) { super(pe); this.context = ctx; @@ -36,7 +35,7 @@ public class StateGraphUpdateContext extends UpdateContext { /** * @return the context */ - public StateGraphContext getContext() { + public IStateGraphContext getContext() { return context; } diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateSupport.java index 2ca43aadf..43d846452 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/StateSupport.java @@ -30,6 +30,9 @@ 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.behavior.fsm.support.util.DiagramEditingUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.ModelEditingUtil; 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; @@ -153,16 +156,12 @@ public class StateSupport { public Object[] doCreate(ICreateContext context) { ContainerShape targetContainer = context.getTargetContainer(); - ModelComponent ac = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); - StateGraph sg = (StateGraph) targetContainer.getLink().getBusinessObjects().get(0); - - // hrr: was boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); - // but if we are inside our own refined state it is treated as inherited which is wrong - boolean inherited = !EcoreUtil.isAncestor(FSMSupportUtil.getInstance().getModelComponent(getDiagram()), sg); - if (inherited) { - sg = FSMSupportUtil.getInstance().insertRefinedState(sg, ac, targetContainer, getFeatureProvider()); - } - + ModelComponent mc = FSMSupportUtil.getInstance().getModelComponent(getDiagram()); + StateGraph sg = (StateGraph) targetContainer.getLink().getBusinessObjects().get(0); + if (!FSMSupportUtil.getInstance().isOwnedBy(mc, sg)) { + sg = ModelEditingUtil.insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); + + } // create new State and add it SimpleState s = FSMFactory.eINSTANCE.createSimpleState(); s.setName(FSMSupportUtil.getInstance().getFSMNewNamingUtil().getUniqueName("state", sg)); @@ -171,7 +170,7 @@ public class StateSupport { Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); Injector injector = ((IInjectorProvider) getFeatureProvider()).getInjector(); IFSMDialogFactory factory = injector.getInstance(IFSMDialogFactory.class); - IStatePropertyDialog dlg = factory.createStatePropertyDialog(shell, ac, s, true); + IStatePropertyDialog dlg = factory.createStatePropertyDialog(shell, mc, s, true); if (dlg.open()==Window.OK) { addGraphicalRepresentation(context, s); @@ -527,7 +526,7 @@ public class StateSupport { boolean isBaseClassState = FSMSupportUtil.getInstance().getFSMHelpers().getModelComponent(s)!=FSMSupportUtil.getInstance().getModelComponent(getDiagram()); if (isBaseClassState) { - newSG = FSMSupportUtil.getInstance().getSubGraphOfRefinedStateFor(s, FSMSupportUtil.getInstance().getModelComponent(getDiagram())); + newSG = ModelEditingUtil.getOrCreateSubGraphOfRefinedStateFor(s, FSMSupportUtil.getInstance().getModelComponent(getDiagram())); s = (State) newSG.eContainer(); // replace old business object with new refined state @@ -590,7 +589,7 @@ public class StateSupport { ContainerShape container = (ContainerShape)context.getPictogramElements()[0]; Object bo = getBusinessObjectForPictogramElement(container); State s = (State) bo; - RefinedState rs = FSMSupportUtil.getInstance().getRefinedStateFor(s, FSMSupportUtil.getInstance().getModelComponent(getDiagram())); + RefinedState rs = ModelEditingUtil.getOrCreateRefinedStateFor(s, FSMSupportUtil.getInstance().getModelComponent(getDiagram())); // replace old business object with new refined state link(container, rs); @@ -599,6 +598,11 @@ public class StateSupport { for (ICustomFeature cf : features) { if (cf instanceof PropertyFeature) { cf.execute(context); + if (!cf.hasDoneChanges()) { + // roll back + link(container, s); + EcoreUtil.remove(rs); + } break; } } @@ -830,7 +834,7 @@ public class StateSupport { IFeatureProvider fp = getFeatureProvider(); Diagram diagram = getDiagram(); ModelComponent mc = FSMSupportUtil.getInstance().getFSMHelpers().getModelComponent(s); - FSMSupportUtil.getInstance().deleteSubStructureRecursive(s, mc, diagram, fp); + DiagramEditingUtil.getInstance().deleteSubStructureRecursive(s, mc, diagram, fp); ContainerShape container = (ContainerShape) context.getPictogramElement(); CommonSupportUtil.deleteConnectionsRecursive(container, fp); diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TrPointSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TrPointSupport.java index cd2e86afb..bd07b6f83 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TrPointSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TrPointSupport.java @@ -32,6 +32,8 @@ 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.behavior.fsm.support.util.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.ModelEditingUtil; 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; @@ -145,9 +147,9 @@ public class TrPointSupport { 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()); + + if (!FSMSupportUtil.getInstance().isOwnedBy(mc, sg)) { + sg = ModelEditingUtil.insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); } // create transition point diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TransitionSupport.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TransitionSupport.java index 6a7f9112d..f912cdfd7 100644 --- a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TransitionSupport.java +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/TransitionSupport.java @@ -41,6 +41,8 @@ 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.behavior.fsm.support.util.FSMSupportUtil; +import org.eclipse.etrice.ui.behavior.fsm.support.util.ModelEditingUtil; 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; @@ -267,11 +269,8 @@ public class TransitionSupport { } ContainerShape targetContainer = FSMSupportUtil.getInstance().getStateGraphContainer((ContainerShape) context.getSourcePictogramElement().eContainer()); - // hrr: was boolean inherited = FSMSupportUtil.getInstance().isInherited(getDiagram(), sg); - // but if we are inside our own refined state it is treated as inherited which is wrong - boolean inherited = !EcoreUtil.isAncestor(FSMSupportUtil.getInstance().getModelComponent(getDiagram()), sg); - if (inherited) { - sg = FSMSupportUtil.getInstance().insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); + if (!FSMSupportUtil.getInstance().isOwnedBy(mc, sg)) { + sg = ModelEditingUtil.insertRefinedState(sg, mc, targetContainer, getFeatureProvider()); } sg.getTransitions().add(trans); diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramEditingUtil.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramEditingUtil.java new file mode 100644 index 000000000..c90cd2e26 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramEditingUtil.java @@ -0,0 +1,743 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; +import org.eclipse.etrice.core.fsm.fSM.ChoicepointTerminal; +import org.eclipse.etrice.core.fsm.fSM.EntryPoint; +import org.eclipse.etrice.core.fsm.fSM.ExitPoint; +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.State; +import org.eclipse.etrice.core.fsm.fSM.StateGraph; +import org.eclipse.etrice.core.fsm.fSM.StateGraphItem; +import org.eclipse.etrice.core.fsm.fSM.StateGraphNode; +import org.eclipse.etrice.core.fsm.fSM.StateTerminal; +import org.eclipse.etrice.core.fsm.fSM.SubStateTrPointTerminal; +import org.eclipse.etrice.core.fsm.fSM.TrPoint; +import org.eclipse.etrice.core.fsm.fSM.TrPointTerminal; +import org.eclipse.etrice.core.fsm.fSM.Transition; +import org.eclipse.etrice.core.fsm.fSM.TransitionTerminal; +import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; +import org.eclipse.etrice.ui.behavior.fsm.support.ContextSwitcher; +import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider; +import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider.Pos; +import org.eclipse.etrice.ui.behavior.fsm.support.IPositionProvider.PosAndSize; +import org.eclipse.etrice.ui.behavior.fsm.support.IStateGraphContext; +import org.eclipse.etrice.ui.behavior.fsm.support.StateGraphSupport; +import org.eclipse.etrice.ui.behavior.fsm.support.StateSupport; +import org.eclipse.etrice.ui.behavior.fsm.support.TrPointSupport; +import org.eclipse.etrice.ui.common.base.support.CommonSupportUtil; +import org.eclipse.graphiti.datatypes.ILocation; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.features.IRemoveFeature; +import org.eclipse.graphiti.features.context.IRemoveContext; +import org.eclipse.graphiti.features.context.impl.AddConnectionContext; +import org.eclipse.graphiti.features.context.impl.AddContext; +import org.eclipse.graphiti.features.context.impl.LayoutContext; +import org.eclipse.graphiti.features.context.impl.RemoveContext; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +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.Diagram; +import org.eclipse.graphiti.mm.pictograms.FreeFormConnection; +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.ILinkService; + +/** + * Shared logic to modify graphical diagram + */ +public class DiagramEditingUtil { + + private static final String INITIAL = "init"; + private static final String STATE = "state:"; + private static final String TP = "tp:"; + private static final String CP = "cp:"; + private static final String SEP = "."; + + private static DiagramEditingUtil instance = null; + + public static DiagramEditingUtil getInstance() { + if(instance == null) + instance = new DiagramEditingUtil(); + + return instance; + } + + public void updateStateGraph(StateGraph sg, IStateGraphContext ctx, ContainerShape sgShape, + IFeatureProvider fp) { + + HashMap<String, Anchor> node2anchor = new HashMap<String, Anchor>(); + + GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); + ctx.getPositionProvider().setScale(borderRect.getWidth(), borderRect.getHeight()); + ctx.getPositionProvider().setPosition(sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY()); + + // states + { + ArrayList<Shape> shapes = new ArrayList<Shape>(); + List<State> present = getStates(sgShape, fp, node2anchor, shapes); + checkDuplicates(present); + List<State> expected = ctx.getStates(); + List<State> toAdd = new ArrayList<State>(); + List<State> toUpdate = new ArrayList<State>(); + List<State> toRemove = new ArrayList<State>(); + for (State item : expected) { + if (present.contains(item)) + toUpdate.add(item); + else + toAdd.add(item); + } + for(State item : present){ + if(!expected.contains(item)) + toRemove.add(item); + } + addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); + updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); + removeGraphicalRepresentation(toRemove, shapes, fp); + } + + // transition points + { + ArrayList<Shape> shapes = new ArrayList<Shape>(); + List<TrPoint> present = getTrPoints(sg, sgShape, fp, node2anchor, shapes); + checkDuplicates(present); + List<TrPoint> expected = ctx.getTrPoints(); + List<TrPoint> toAdd = new ArrayList<TrPoint>(); + List<TrPoint> toUpdate = new ArrayList<TrPoint>(); + List<TrPoint> toRemove = new ArrayList<TrPoint>(); + for (TrPoint item : expected) { + if (present.contains(item)) + toUpdate.add(item); + else + toAdd.add(item); + } + for(TrPoint item : present){ + if(!expected.contains(item)) + toRemove.add(item); + } + addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); + updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); + removeGraphicalRepresentation(toRemove, shapes, fp); + } + + // choice points + { + ArrayList<Shape> shapes = new ArrayList<Shape>(); + List<ChoicePoint> present = getChoicePoints(sgShape, fp, node2anchor, shapes); + checkDuplicates(present); + List<ChoicePoint> expected = ctx.getChPoints(); + List<ChoicePoint> toAdd = new ArrayList<ChoicePoint>(); + List<ChoicePoint> toUpdate = new ArrayList<ChoicePoint>(); + List<ChoicePoint> toRemove = new ArrayList<ChoicePoint>(); + for (ChoicePoint item : expected) { + if (present.contains(item)) + toUpdate.add(item); + else + toAdd.add(item); + } + for(ChoicePoint item : present){ + if(!expected.contains(item)) + toRemove.add(item); + } + addStateGraphNodes(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); + updateStateGraphNodes(toUpdate, shapes, ctx.getPositionProvider(), fp); + removeGraphicalRepresentation(toRemove, shapes, fp); + } + + getSubTpAnchors(sgShape, node2anchor); + + // initial point + { + // exists in this diagram ? + Shape present = null; + for (Shape ch : sgShape.getChildren()) { + Object bo = fp.getBusinessObjectForPictogramElement(ch); + if (bo instanceof StateGraph) + present = ch; + } + if(present != null) { + node2anchor.put(INITIAL, present.getAnchors().get(0)); + } + // exists in model ? + StateGraph expected = ctx.getInitialPoint(); + if(expected == null) { + // exists in (super class) diagram ? + expected = ctx.getPositionProvider().getInitialPoint(ctx.getStateGraph()); + } + if(expected != null && present == null) { + addInitialPointIff(ctx, ctx.getPositionProvider(), sgShape, fp, node2anchor); + } + else { + updateInitialPoint(present, ctx.getPositionProvider(), fp); + } + } + + // transitions + { + // get transitions that belong to our state graph + // (for other connections we might not have the node anchors yet) + Map<Transition, Connection> present = getTransitionsMap(sgShape, fp); + List<Transition> expected = ctx.getTransitions(); + List<Transition> toAdd = new ArrayList<Transition>(); + List<Transition> toRemove = new ArrayList<Transition>(); + for (Transition trans : expected) + if (!present.containsKey(trans)) + toAdd.add(trans); + for(Transition item : present.keySet()){ + if(!expected.contains(item)) + toRemove.add(item); + } + addTransitions(toAdd, ctx.getPositionProvider(), sgShape, fp, node2anchor); + updateTransitions(present, ctx.getPositionProvider(), sgShape, fp, node2anchor); + removeGraphicalRepresentation(toRemove, present.values(), fp); + } + } + + + public void removeGraphicalRepresentation(Collection<? extends EObject> toRemove, Collection<? extends PictogramElement> pictograms, IFeatureProvider fp) { + for(EObject bo : toRemove) + for(PictogramElement pe : pictograms) + if(fp.getBusinessObjectForPictogramElement(pe) == bo){ + IRemoveContext rc = new RemoveContext(pe); + IRemoveFeature removeFeature = fp.getRemoveFeature(rc); + if (removeFeature != null) + removeFeature.remove(rc); + break; + } + } + + + /** + * @param s the state whose sub structure should be deleted + * @param mc the ModelComponent + * @param diagram the current diagram + * @param fp the feature provider + */ + public void deleteSubStructureRecursive(State s, ModelComponent mc, Diagram diagram, IFeatureProvider fp) { + if (FSMSupportUtil.getInstance().getFSMHelpers().hasSubStructure(s, mc)) { + StateGraph subgraph = s.getSubgraph(); + + // depth first + for (State st : subgraph.getStates()) { + deleteSubStructureRecursive(st, mc, diagram, fp); + } + + ContainerShape subShape = ContextSwitcher.getContext(diagram, subgraph); + CommonSupportUtil.deleteConnectionsRecursive(subShape, fp); + EcoreUtil.delete(subShape, true); + } + } + + public ContainerShape addStateGraph(IStateGraphContext ctx, Diagram diagram, IFeatureProvider fp) { + AddContext addContext = new AddContext(); + addContext.setNewObject(ctx.getStateGraph()); + addContext.setTargetContainer(diagram); + PosAndSize graphPosAndSize = ctx.getPositionProvider().getGraphPosAndSize(ctx.getStateGraph()); + if (graphPosAndSize!=null) { + addContext.setX(graphPosAndSize.getX()); + addContext.setY(graphPosAndSize.getY()); + addContext.setWidth(graphPosAndSize.getWidth()); + addContext.setHeight(graphPosAndSize.getHeight()); + } + else { + addContext.setX(StateGraphSupport.MARGIN); + addContext.setY(StateGraphSupport.MARGIN); + } + + ContainerShape sgShape = (ContainerShape) fp.addIfPossible(addContext); + if (sgShape==null) + return null; + + final HashMap<String, Anchor> node2anchor = new HashMap<String, Anchor>(); + + GraphicsAlgorithm borderRect = sgShape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren().get(0); + ctx.getPositionProvider().setScale(borderRect.getWidth(), borderRect.getHeight()); + ctx.getPositionProvider().setPosition(sgShape.getGraphicsAlgorithm().getX(), sgShape.getGraphicsAlgorithm().getY()); + + addInitialPointIff(ctx, ctx.getPositionProvider(), sgShape, fp, node2anchor); + addStateGraphNodes(ctx.getTrPoints(), ctx.getPositionProvider(), sgShape, fp, node2anchor); + addStateGraphNodes(ctx.getStates(), ctx.getPositionProvider(), sgShape, fp, node2anchor); + addStateGraphNodes(ctx.getChPoints(), ctx.getPositionProvider(), sgShape, fp, node2anchor); + + for (IStateGraphContext sub : ctx.getChildren()) { + addStateGraph(sub, diagram, fp); + } + + getSubTpAnchors(sgShape, node2anchor); + + addTransitions(ctx.getTransitions(), ctx.getPositionProvider(), sgShape, fp, node2anchor); + + return sgShape; + } + + + public List<State> getStates(ContainerShape shape, IFeatureProvider fp) { + return getStates(shape, fp, null, null); + } + + public List<ChoicePoint> getChoicePoints(ContainerShape shape, IFeatureProvider fp) { + return getChoicePoints(shape, fp, null, null); + } + + + public List<TrPoint> getTrPoints(StateGraph sg, ContainerShape shape, IFeatureProvider fp) { + return getTrPoints(sg, shape, fp, null, null); + } + + + private List<State> getStates(ContainerShape shape, IFeatureProvider fp, Map<String, Anchor> item2anchor, List<Shape> stateShapes) { + List<State> items = new ArrayList<State>(); + for (Shape ch : shape.getChildren()) { + Object bo = fp.getBusinessObjectForPictogramElement(ch); + if (bo instanceof State) { + items.add((State)bo); + if (item2anchor!=null) + item2anchor.put(getKey((State)bo), ch.getAnchors().get(0)); + if (stateShapes!=null) + stateShapes.add(ch); + } + } + return items; + } + + private List<ChoicePoint> getChoicePoints(ContainerShape shape, IFeatureProvider fp, Map<String, Anchor> item2anchor, + List<Shape> cpShapes) { + List<ChoicePoint> items = new ArrayList<ChoicePoint>(); + for (Shape ch : shape.getChildren()) { + Object bo = fp.getBusinessObjectForPictogramElement(ch); + if (bo instanceof ChoicePoint) { + items.add((ChoicePoint)bo); + if (item2anchor!=null) + item2anchor.put(getKey((ChoicePoint)bo), ch.getAnchors().get(0)); + if (cpShapes!=null) + cpShapes.add(ch); + } + } + return items; + } + + private List<TrPoint> getTrPoints(StateGraph sg, ContainerShape shape, IFeatureProvider fp, + Map<String, Anchor> item2anchor, List<Shape> tpShapes) { + List<TrPoint> items = new ArrayList<TrPoint>(); + for (Shape ch : shape.getChildren()) { + Object bo = fp.getBusinessObjectForPictogramElement(ch); + if (bo instanceof TrPoint) { + items.add((TrPoint)bo); + if (item2anchor!=null) + item2anchor.put(getKey((TrPoint)bo), ch.getAnchors().get(0)); + if (tpShapes!=null) + tpShapes.add(ch); + } + } + return items; + } + + private Map<Transition, Connection> getTransitionsMap(ContainerShape sgShape, IFeatureProvider fp) { + Diagram diagram = (Diagram) sgShape.eContainer(); + Map<Transition, Connection> transitions = new HashMap<Transition, Connection>(); + for (Connection conn : diagram.getConnections()) { + Object bo = fp.getBusinessObjectForPictogramElement(conn); + + // we only collect connections that have a starting point contained in our sgShape + if (bo instanceof Transition && EcoreUtil.isAncestor(sgShape, conn.getStart())) + transitions.put((Transition) bo, conn); + } + return transitions; + } + + private void getSubTpAnchors(ContainerShape sgShape, HashMap<String, Anchor> node2anchor) { + for (Shape childShape : sgShape.getChildren()) { + EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(childShape); + if (bo instanceof State) + getAnchors((State) bo, childShape, node2anchor); + } + } + + private void addInitialPointIff(IStateGraphContext ctx, IPositionProvider positionProvider, ContainerShape sgShape, + IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { + + // model + StateGraph sg = ctx.getInitialPoint(); + if(sg==null) + // (super class) diagram + sg = positionProvider.getInitialPoint(ctx.getStateGraph()); + if(sg==null) + return; + + PosAndSize pos = positionProvider.getPosition(sg); + AddContext addContext = new AddContext(); + addContext.setNewObject(sg); + addContext.setTargetContainer(sgShape); + if(pos != null){ + addContext.setX(pos.getX()); + addContext.setY(pos.getY()); + if (pos.getWidth()>0 && pos.getHeight()>0) { + addContext.setWidth(pos.getWidth()); + addContext.setHeight(pos.getHeight()); + } + } else { + addContext.setX(3*StateGraphSupport.MARGIN); + addContext.setY(3*StateGraphSupport.MARGIN); + } + + ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext); + assert(pe!=null): "initial point should have been created"; + assert(!pe.getAnchors().isEmpty()): "initial point should have an anchor"; + node2anchor.put(INITIAL, pe.getAnchors().get(0)); + } + + private void addTransitions(List<Transition> transitions, IPositionProvider positionProvider, ContainerShape sgShape, + IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { + + for (Transition trans : transitions) { + String from = (trans instanceof InitialTransition)? INITIAL:getKey(((NonInitialTransition)trans).getFrom()); + String to = getKey(trans.getTo()); + Anchor src = node2anchor.get(from); + Anchor dst = node2anchor.get(to); + + assert(src!=null && dst!=null): "transition endpoints must be present"; + + AddConnectionContext context = new AddConnectionContext(src, dst); + context.setNewObject(trans); + PictogramElement pe = fp.addIfPossible(context); + if (pe instanceof FreeFormConnection) { + FreeFormConnection conn = (FreeFormConnection) pe; + + // JH: workaround for correct bend points of inherited self transition + conn.getBendpoints().clear(); + + List<Pos> points = positionProvider.getPoints(trans); + if (points!=null && !points.isEmpty()) { + Iterator<Pos> it = points.iterator(); + + // first is label position + Pos pos = it.next(); + ConnectionDecorator cd = conn.getConnectionDecorators().get(1); + Graphiti.getGaService().setLocation(cd.getGraphicsAlgorithm(), pos.getX(), pos.getY()); + + // remaining are bend points + while (it.hasNext()) { + pos = it.next(); + Point pt = Graphiti.getGaService().createPoint(pos.getX(), pos.getY()); + conn.getBendpoints().add(pt); + } + } + else if (src==dst) { + ILocation begin = Graphiti.getPeService().getLocationRelativeToDiagram(conn.getStart()); + Point pt = Graphiti.getGaService().createPoint(begin.getX(), begin.getY()+StateGraphSupport.MARGIN*3); + conn.getBendpoints().add(pt); + } + } + } + } + + private <T extends StateGraphNode> List<PosAndSize> getPositions(List<T> nodes, IPositionProvider positionProvider, double scaleX) { + ArrayList<PosAndSize> result = new ArrayList<PosAndSize>(nodes.size()); + + if (nodes.isEmpty()) + return result; + + int n = 0; + for (T node : nodes) { + PosAndSize pt = positionProvider.getPosition(node); + result.add(pt); + if (pt==null) + n++; + } + + int delta = (int) (scaleX / (n+1)); + int pos = delta; + + int h = StateGraphSupport.MARGIN; + if (nodes.get(0) instanceof State) + h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/4; + else if (nodes.get(0) instanceof ChoicePoint) + h = StateGraphSupport.MARGIN + StateGraphSupport.DEFAULT_SIZE_Y/2; + else if (nodes.get(0) instanceof TrPoint) + h = StateGraphSupport.MARGIN; + else { + assert(false): "unexpected sub type"; + } + + for (int i=0; i<nodes.size(); ++i) { + if (result.get(i)==null) { + PosAndSize pt = new PosAndSize( + pos, + h, + 0, + 0 + ); + result.set(i, pt); + + pos += delta; + } + } + + return result; + } + + private void addStateGraphNodes(List<? extends StateGraphNode> nodes, IPositionProvider positionProvider, ContainerShape sgShape, + IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { + + List<PosAndSize> positions = getPositions(nodes, positionProvider, sgShape.getGraphicsAlgorithm().getWidth()); + + int idx = 0; + for (StateGraphNode node : nodes) { + addStateGraphNode(node, sgShape, positions.get(idx), fp, node2anchor); + ++idx; + } + } + + private void addStateGraphNode(StateGraphNode tp, ContainerShape sgShape, PosAndSize pos, + IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { + AddContext addContext = new AddContext(); + addContext.setNewObject(tp); + addContext.setTargetContainer(sgShape); + addContext.setX(pos.getX()); + addContext.setY(pos.getY()); + if (pos.getWidth()>0 && pos.getHeight()>0) { + addContext.setWidth(pos.getWidth()); + addContext.setHeight(pos.getHeight()); + } + + ContainerShape pe = (ContainerShape) fp.addIfPossible(addContext); + assert(pe!=null): tp.eClass().getName()+" should have been created"; + assert(!pe.getAnchors().isEmpty()): tp.eClass().getName()+" should have an anchor"; + node2anchor.put(getKey(tp), pe.getAnchors().get(0)); + } + + private void updateInitialPoint(Shape shape, IPositionProvider positionProvider, IFeatureProvider fp) { + if (shape==null) + return; + + StateGraph sg = (StateGraph) fp.getBusinessObjectForPictogramElement(shape); + PosAndSize ps = positionProvider.getPosition(sg); + if (ps==null) + return; + + // relocate and resize the invisible rectangle + GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); + + Graphiti.getLayoutService().setLocationAndSize( + ga, + ps.getX(), + ps.getY(), + ps.getWidth(), + ps.getHeight() + ); + + // have to call the layout to adjust the visible border + LayoutContext lc = new LayoutContext(shape); + fp.layoutIfPossible(lc); + } + + private void updateStateGraphNodes(List<? extends StateGraphNode> nodes, List<Shape> shapes, IPositionProvider positionProvider, IFeatureProvider fp) { + + ILinkService linkService = Graphiti.getLinkService(); + IGaService gaService = Graphiti.getGaService(); + + for (StateGraphNode node : nodes) { + PosAndSize ps = positionProvider.getPosition(node); + if (ps==null) + continue; + + // TODO: sub-optimal since quadratic effort - use combined list for nodes and shapes or similar solution + for (Shape shape : shapes) { + EObject bo = linkService.getBusinessObjectForLinkedPictogramElement(shape); + if (bo==node) { + // relocate and resize the invisible rectangle + GraphicsAlgorithm ga = shape.getGraphicsAlgorithm(); +// System.out.println(node + ": "+ga.getX()+" "+ga.getY()+" "+ga.getWidth()+" "+ga.getHeight()); +// System.out.println(" -> "+ps.getX()+" "+ps.getY()+" "+ps.getWidth()+" "+ps.getHeight()); + + int margin = 0; + if (node instanceof State) + margin = StateSupport.MARGIN; + else if (node instanceof TrPoint) + margin = TrPointSupport.MARGIN; + + gaService.setLocationAndSize( + ga, + ps.getX()-margin, + ps.getY()-margin, + ps.getWidth()+2*margin, + ps.getHeight()+2*margin + ); + + // have to call the layout to adjust the visible border + LayoutContext lc = new LayoutContext(shape); + fp.layoutIfPossible(lc); + + // update position of sub items + if(shape instanceof ContainerShape){ + ContainerShape container = (ContainerShape) shape; + for(Shape child : container.getChildren()){ + EObject childBo = linkService.getBusinessObjectForLinkedPictogramElement(child); + if(!(childBo instanceof StateGraphNode)) + continue; + + double[] relPos = positionProvider.getSubPosition((StateGraphNode) childBo); + if(relPos != null) + gaService.setLocation(child.getGraphicsAlgorithm(), (int)(relPos[0] * ps.getWidth()), (int)(relPos[1]*ps.getHeight())); + } + } + + break; + } + } + } + } + + private void updateTransitions(Map<Transition, Connection> transitions, IPositionProvider positionProvider, ContainerShape sgShape, + IFeatureProvider fp, HashMap<String, Anchor> node2anchor) { + + for(Entry<Transition, Connection> e: transitions.entrySet()){ + Transition trans = e.getKey(); + Connection conn = e.getValue(); + + String from = (trans instanceof InitialTransition)? INITIAL:getKey(((NonInitialTransition)trans).getFrom()); + String to = getKey(trans.getTo()); + Anchor newSrc = node2anchor.get(from); + Anchor newDst = node2anchor.get(to); + + assert(newSrc!=null && newDst!=null): "transition endpoints must be present"; + + if(conn.getStart()!=newSrc) + conn.setStart(newSrc); + if(conn.getEnd()!=newDst) + conn.setEnd(newDst); + + List<Pos> points = positionProvider.getPoints(trans); + Iterator<Pos> it = points.iterator(); + if (points==null || points.isEmpty()) + continue; + + // first is label position + Pos pos = it.next(); + ConnectionDecorator cd = conn.getConnectionDecorators().get(1); + Graphiti.getGaService().setLocation(cd.getGraphicsAlgorithm(), pos.getX(), pos.getY()); + + if (conn instanceof FreeFormConnection) { + FreeFormConnection fconn = (FreeFormConnection) conn; + + // remaining are bend points + fconn.getBendpoints().clear(); + List<Point> bendpoints = new ArrayList<Point>(); + while (it.hasNext()) { + pos = it.next(); + Point pt = Graphiti.getGaService().createPoint(pos.getX(), pos.getY()); + bendpoints.add(pt); + } + fconn.getBendpoints().addAll(bendpoints); + } + } + } + + private void getAnchors(State state, PictogramElement stateShape, final HashMap<String, Anchor> node2anchor) { + if (stateShape instanceof ContainerShape) { + node2anchor.put(getKey(state), ((ContainerShape)stateShape).getAnchors().get(0)); + for (Shape child : ((ContainerShape) stateShape).getChildren()) { + if (child instanceof ContainerShape) { + ContainerShape childShape = (ContainerShape) child; + if (!childShape.getAnchors().isEmpty()) { + if (!childShape.getLink().getBusinessObjects().isEmpty()) { + EObject obj = childShape.getLink().getBusinessObjects().get(0); + if (obj instanceof EntryPoint || obj instanceof ExitPoint) { + node2anchor.put(getKey(obj, true), childShape.getAnchors().get(0)); + } + } + } + } + } + } + } + + private String getKey(EObject obj) { + return getKey(obj, false); + } + + private String getKey(EObject obj, boolean subTp) { + if (obj instanceof TrPoint) { + TrPoint tp = (TrPoint) obj; + if (!subTp) + return TP+tp.getName(); + else { + if (tp.eContainer().eContainer() instanceof State) { + State s = (State) tp.eContainer().eContainer(); + return TP+tp.getName()+SEP+s.getName(); + } + else { + assert(false): "State expected"; + } + } + } + else if (obj instanceof State) { + return STATE+((State)obj).getName(); + } + else if (obj instanceof ChoicePoint) { + return CP+((ChoicePoint)obj).getName(); + } + else if (obj instanceof TransitionTerminal) { + TransitionTerminal tt = (TransitionTerminal) obj; + if (tt instanceof ChoicepointTerminal) { + return CP+((ChoicepointTerminal)tt).getCp().getName(); + } + else if (tt instanceof StateTerminal) { + return STATE+((StateTerminal)tt).getState().getName(); + } + else if (tt instanceof SubStateTrPointTerminal) { + SubStateTrPointTerminal sstt = (SubStateTrPointTerminal) tt; + return TP+sstt.getTrPoint().getName()+SEP+sstt.getState().getName(); + } + else if (tt instanceof TrPointTerminal) { + return TP+((TrPointTerminal)tt).getTrPoint().getName(); + } + else { + assert(false): "unexpected sub type"; + } + } + assert(false): "unexpected type"; + return null; + } + + + private void checkDuplicates(List<? extends StateGraphItem> items) { + FSMNameProvider fsmNameProvider = FSMSupportUtil.getInstance().getFSMNameProvider(); + for (StateGraphItem item : items) { + if (items.indexOf(item)!=items.lastIndexOf(item)) { + Assert.isTrue( + items.indexOf(item)==items.lastIndexOf(item), + "multiple occurrences of "+fsmNameProvider.getFullPath(item)); + } + } + } +} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramExtensions.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramExtensions.xtend new file mode 100644 index 000000000..6905d6821 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/DiagramExtensions.xtend @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support.util + +import org.eclipse.graphiti.mm.pictograms.PictogramElement +import org.eclipse.graphiti.services.Graphiti +import org.eclipse.graphiti.features.context.IPictogramElementContext +import org.eclipse.emf.ecore.EObject + +class DiagramExtensions { + + def static <T extends PictogramElement> getCastedPe(IPictogramElementContext ctx){ + ctx.pictogramElement as T + } + + def static <T extends EObject> getCastedBo(PictogramElement pe) { + Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(pe) as T + } +}
\ No newline at end of file diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/FSMSupportUtil.java b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/FSMSupportUtil.java new file mode 100644 index 000000000..d283a8b1a --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/FSMSupportUtil.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * Copyright (c) 2014 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: + * Henrik Rentz-Reichert (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support.util; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.etrice.core.fsm.fSM.ChoicePoint; +import org.eclipse.etrice.core.fsm.fSM.ChoicepointTerminal; +import org.eclipse.etrice.core.fsm.fSM.FSMFactory; +import org.eclipse.etrice.core.fsm.fSM.ModelComponent; +import org.eclipse.etrice.core.fsm.fSM.RefinedState; +import org.eclipse.etrice.core.fsm.fSM.RefinedTransition; +import org.eclipse.etrice.core.fsm.fSM.State; +import org.eclipse.etrice.core.fsm.fSM.StateGraph; +import org.eclipse.etrice.core.fsm.fSM.StateTerminal; +import org.eclipse.etrice.core.fsm.fSM.SubStateTrPointTerminal; +import org.eclipse.etrice.core.fsm.fSM.TrPoint; +import org.eclipse.etrice.core.fsm.fSM.TrPointTerminal; +import org.eclipse.etrice.core.fsm.fSM.Transition; +import org.eclipse.etrice.core.fsm.fSM.TransitionTerminal; +import org.eclipse.etrice.core.fsm.naming.FSMNameProvider; +import org.eclipse.etrice.core.fsm.ui.FSMUiModule; +import org.eclipse.etrice.core.fsm.util.FSMHelpers; +import org.eclipse.etrice.core.fsm.util.FSMNewNamingUtil; +import org.eclipse.etrice.core.fsm.validation.FSMValidationUtil; +import org.eclipse.graphiti.features.IFeatureProvider; +import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm; +import org.eclipse.graphiti.mm.pictograms.Anchor; +import org.eclipse.graphiti.mm.pictograms.Connection; +import org.eclipse.graphiti.mm.pictograms.ContainerShape; +import org.eclipse.graphiti.mm.pictograms.Diagram; +import org.eclipse.graphiti.mm.pictograms.PictogramElement; +import org.eclipse.graphiti.services.Graphiti; + +import com.google.inject.Inject; +import com.google.inject.Injector; + +/** + * Shared business logic, side-effect free util methods + */ +public class FSMSupportUtil { + + + private static FSMSupportUtil instance = null; + + /** + * @return the instance + */ + public static FSMSupportUtil getInstance() { + if (instance==null) { + // this class has members that have to be filled by the FSMUi injector + Injector injector = FSMUiModule.getInjector(); + instance = injector.getInstance(FSMSupportUtil.class); + } + return instance; + } + + @Inject + private FSMHelpers fsmHelpers; + @Inject + private FSMValidationUtil fsmValidationUtil; + @Inject + private FSMNameProvider fsmNameProvider; + @Inject + private FSMNewNamingUtil fsmNewNamingUtil; + + /** + * @return the roomHelpers + */ + public FSMHelpers getFSMHelpers() { + return fsmHelpers; + } + + /** + * @return the validationUtil + */ + public FSMValidationUtil getFSMValidationUtil() { + return fsmValidationUtil; + } + + /** + * @return the roomUtil + */ + public FSMNewNamingUtil getFSMNewNamingUtil() { + return fsmNewNamingUtil; + } + + /** + * @return the roomNameProvider + */ + public FSMNameProvider getFSMNameProvider() { + return fsmNameProvider; + } + + public boolean isInherited(Diagram diag, EObject obj) { + return isInherited(getModelComponent(diag), obj); + } + + public boolean isInherited(ModelComponent mc, EObject obj) { + if (obj instanceof StateGraph) + obj = obj.eContainer(); + else if (obj instanceof ModelComponent) + // the next line states: if a ModelComponent has no base class, then it is not inherited. + // And vice versa: if it has a base class it is inherited + // QUESTION: is this correct? + // However, this method isn't called with an obj instanceof ModelComponent + return ((ModelComponent) obj).getBase() != null; + + return obj instanceof RefinedState || obj instanceof RefinedTransition || !EcoreUtil.isAncestor(mc, obj); + } + + public boolean isOwnedBy(Diagram diag, EObject obj) { + return isOwnedBy(getModelComponent(diag), obj); + } + + public boolean isOwnedBy(ModelComponent mc, EObject obj) { + return EcoreUtil.isAncestor(mc, obj); + } + + public boolean showAsInherited(Diagram diag, State obj) { + + if (obj instanceof RefinedState) + return true; + + return fsmHelpers.getModelComponent(obj)!=getModelComponent(diag); + } + + public Diagram getDiagram(GraphicsAlgorithm ga) { + if (ga.eContainer() instanceof GraphicsAlgorithm) + return getDiagram((GraphicsAlgorithm)ga.eContainer()); + return getDiagram(ga.getPictogramElement()); + } + + public Diagram getDiagram(PictogramElement pe) { + while (pe.eContainer()!=null) { + if (pe.eContainer() instanceof Diagram) + return (Diagram) pe.eContainer(); + pe = (PictogramElement) pe.eContainer(); + } + return null; + } + + public ModelComponent getModelComponent(Diagram diag) { + EObject bo = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(diag); + if (bo instanceof ModelComponent) + return (ModelComponent) bo; + return null; + } + + public State getTargettingState(State state, Diagram diagram) { + ModelComponent mc = getModelComponent(diagram); + return fsmHelpers.getTargettingState(state, mc); + } + + /** + * This method exploits the fact that the immediate children of the diagram are + * associated with the state graphs. + * + * @param shape + * @return the container shape that is associated with the state graph of the diagram + */ + public ContainerShape getStateGraphContainer(ContainerShape shape) { + while (shape!=null) { + ContainerShape parent = shape.getContainer(); + if (parent instanceof Diagram) + return shape; + shape = parent; + } + return null; + } + + public StateGraph getStateGraph(ContainerShape cs, IFeatureProvider fp) { + ContainerShape shape = getStateGraphContainer(cs); + Object bo = fp.getBusinessObjectForPictogramElement(shape); + if (bo instanceof StateGraph) + return (StateGraph) bo; + else + assert(false): "state graph expected"; + + return null; + } + + public TransitionTerminal getTransitionTerminal(Anchor anchor, IFeatureProvider fp) { + if (anchor != null) { + Object obj = fp.getBusinessObjectForPictogramElement(anchor.getParent()); + if (obj instanceof TrPoint) { + Object parent = fp.getBusinessObjectForPictogramElement((ContainerShape) anchor.getParent().eContainer()); + if (parent instanceof State) { + State state = (parent instanceof RefinedState)? ((RefinedState)parent).getTarget() : (State)parent; + SubStateTrPointTerminal sstpt = FSMFactory.eINSTANCE.createSubStateTrPointTerminal(); + sstpt.setState(state); + sstpt.setTrPoint((TrPoint) obj); + return sstpt; + } + else { + TrPointTerminal tpt = FSMFactory.eINSTANCE.createTrPointTerminal(); + tpt.setTrPoint((TrPoint) obj); + return tpt; + } + } + else if (obj instanceof State) { + State state = (obj instanceof RefinedState)? ((RefinedState)obj).getTarget() : (State)obj; + StateTerminal st = FSMFactory.eINSTANCE.createStateTerminal(); + st.setState(state); + return st; + } + else if (obj instanceof ChoicePoint) { + ChoicepointTerminal ct = FSMFactory.eINSTANCE.createChoicepointTerminal(); + ct.setCp((ChoicePoint) obj); + return ct; + } + } + return null; + } + + public boolean isInitialPoint(Anchor anchor, IFeatureProvider fp) { + if (anchor!=null) { + Object obj = fp.getBusinessObjectForPictogramElement(anchor.getParent()); + if (obj instanceof StateGraph) { + Object parent = fp.getBusinessObjectForPictogramElement((ContainerShape) anchor.getParent().eContainer()); + if (parent instanceof StateGraph) + return true; + } + } + return false; + } + + public boolean canConnect(Anchor asrc, Anchor atgt, ContainerShape cs, IFeatureProvider fp) { + return canConnect(asrc, atgt, null, cs, fp); + } + + public boolean canConnect(Anchor asrc, Anchor atgt, Transition trans, ContainerShape cs, IFeatureProvider fp) { + TransitionTerminal src = getTransitionTerminal(asrc, fp); + TransitionTerminal tgt = getTransitionTerminal(atgt, fp); + + if (src==null && !isInitialPoint(asrc, fp)) + return false; + if (tgt==null) + return false; + + StateGraph sg = getStateGraph(cs, fp); + if (sg==null) + return false; + + return fsmValidationUtil.isConnectable(src, tgt, trans, sg).isOk(); + } + + public List<Transition> getTransitions(Diagram diagram, IFeatureProvider fp) { + List<Transition> transitions = new ArrayList<Transition>(); + for (Connection conn : diagram.getConnections()) { + Object bo = fp.getBusinessObjectForPictogramElement(conn); + if (bo instanceof Transition) + transitions.add((Transition) bo); + } + return transitions; + } + +} diff --git a/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/ModelEditingUtil.xtend b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/ModelEditingUtil.xtend new file mode 100644 index 000000000..357f254e6 --- /dev/null +++ b/plugins/org.eclipse.etrice.ui.behavior.fsm/src/org/eclipse/etrice/ui/behavior/fsm/support/util/ModelEditingUtil.xtend @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Juergen Haug (initial contribution) + * + *******************************************************************************/ + +package org.eclipse.etrice.ui.behavior.fsm.support.util + +import java.util.HashMap +import org.eclipse.etrice.core.fsm.fSM.FSMFactory +import org.eclipse.etrice.core.fsm.fSM.ModelComponent +import org.eclipse.etrice.core.fsm.fSM.RefinedState +import org.eclipse.etrice.core.fsm.fSM.State +import org.eclipse.etrice.core.fsm.fSM.StateGraph +import org.eclipse.graphiti.features.IFeatureProvider +import org.eclipse.graphiti.mm.pictograms.ContainerShape + +/** + * Shared model editing + */ +class ModelEditingUtil { + + def static public RefinedState getOrCreateRefinedStateFor(State s, ModelComponent mc) { + val target2rs = new HashMap<State, RefinedState>(); + for (State st : mc.getStateMachine().getStates()) { + if (st instanceof RefinedState) + target2rs.put((st as RefinedState).getTarget(), st as RefinedState); + } + + var RefinedState rs = null; + + // do we already have a RefinedState pointing to s? + if (target2rs.containsKey(s)) { + rs = target2rs.get(s); + } + else { + // we have to create one and place it in the best fitting context + var StateGraph sg = null; + var State parent = s; + var break = false; + while (parent.eContainer().eContainer() instanceof State && !break) { + parent = s.eContainer().eContainer() as State; + if (target2rs.containsKey(parent)) { + val bestFitting = target2rs.get(parent); + if (bestFitting.getSubgraph()===null) + bestFitting.setSubgraph(FSMFactory.eINSTANCE.createStateGraph()); + sg = bestFitting.getSubgraph(); + break = true; + } + } + + if (sg===null) + sg = mc.getStateMachine(); + + rs = FSMFactory.eINSTANCE.createRefinedState(); + rs.setTarget(s); + sg.getStates().add(rs); + } + return rs; + } + + + + def static public StateGraph getOrCreateSubGraphOfRefinedStateFor(State s, ModelComponent mc) { + val rs = getOrCreateRefinedStateFor(s, mc); + + if (rs.getSubgraph()===null) + rs.setSubgraph(FSMFactory.eINSTANCE.createStateGraph()); + + return rs.getSubgraph(); + } + + def static public StateGraph insertRefinedState(StateGraph sg, ModelComponent mc, ContainerShape targetContainer, IFeatureProvider fp) { + val sg2 = getOrCreateSubGraphOfRefinedStateFor(sg.eContainer() as State, mc); + fp.link(targetContainer, sg2); + return sg2; + } +}
\ No newline at end of file |