|
@@ -1,323 +1,364 @@
|
|
-/**
|
|
|
|
- * Copyright (c) 2013 committers of YAKINDU and others.
|
|
|
|
- * 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:
|
|
|
|
- * committers of YAKINDU - initial API and implementation
|
|
|
|
- *
|
|
|
|
- */
|
|
|
|
-package org.yakindu.sct.refactoring.refactor.impl;
|
|
|
|
-
|
|
|
|
-import static org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil.createInlineStyle;
|
|
|
|
-import static org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil.getInlineStyle;
|
|
|
|
-
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.Iterator;
|
|
|
|
-import java.util.List;
|
|
|
|
-
|
|
|
|
-import org.eclipse.emf.common.util.EList;
|
|
|
|
-import org.eclipse.emf.common.util.TreeIterator;
|
|
|
|
-import org.eclipse.emf.ecore.EObject;
|
|
|
|
-import org.eclipse.emf.ecore.util.EcoreUtil;
|
|
|
|
-import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
|
|
|
|
-import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
|
|
|
|
-import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.BooleanValueStyle;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.Bounds;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.Diagram;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.Edge;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.Node;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.Style;
|
|
|
|
-import org.eclipse.gmf.runtime.notation.View;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Entry;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Exit;
|
|
|
|
-import org.yakindu.sct.model.sgraph.ReactionProperty;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Region;
|
|
|
|
-import org.yakindu.sct.model.sgraph.SGraphFactory;
|
|
|
|
-import org.yakindu.sct.model.sgraph.State;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Statechart;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Transition;
|
|
|
|
-import org.yakindu.sct.model.sgraph.Vertex;
|
|
|
|
-import org.yakindu.sct.model.stext.stext.EntryPointSpec;
|
|
|
|
-import org.yakindu.sct.model.stext.stext.ExitPointSpec;
|
|
|
|
-import org.yakindu.sct.model.stext.stext.StextFactory;
|
|
|
|
-import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
|
|
|
|
-import org.yakindu.sct.ui.editor.DiagramActivator;
|
|
|
|
-import org.yakindu.sct.ui.editor.editor.StatechartDiagramEditor;
|
|
|
|
-import org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil;
|
|
|
|
-import org.yakindu.sct.ui.editor.providers.SemanticHints;
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- *
|
|
|
|
- * @author andreas muelder - Initial contribution and API
|
|
|
|
- *
|
|
|
|
- */
|
|
|
|
-public class ExtractSubdiagramRefactoring extends AbstractRefactoring<View> {
|
|
|
|
-
|
|
|
|
- protected PreferencesHint preferencesHint = DiagramActivator.DIAGRAM_PREFERENCES_HINT;
|
|
|
|
- private Diagram subdiagram;
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public boolean isExecutable() {
|
|
|
|
- EObject element = getContextObject().getElement();
|
|
|
|
- if (!(element instanceof State)) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- State state = (State) element;
|
|
|
|
- BooleanValueStyle inlineStyle = getInlineStyle(getContextObject());
|
|
|
|
- return super.isExecutable() && state.isComposite() && (inlineStyle == null || inlineStyle.isBooleanValue());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- protected void internalExecute() {
|
|
|
|
- setNotationStyle();
|
|
|
|
- subdiagram = createSubdiagram();
|
|
|
|
- createEntryExitPoints(subdiagram);
|
|
|
|
- setPreferredSize();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- protected boolean internalDoUndo() {
|
|
|
|
- // close the sub diagram before undo will delete it
|
|
|
|
- return DiagramPartitioningUtil.closeSubdiagramEditors((State) subdiagram.getElement());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- protected void createEntryExitPoints(Diagram subdiagram) {
|
|
|
|
- TreeIterator<EObject> eAllContents = subdiagram.eAllContents();
|
|
|
|
- List<Edge> entryPointsToCreate = new ArrayList<Edge>();
|
|
|
|
- List<Edge> exitPointstoCreate = new ArrayList<Edge>();
|
|
|
|
- while (eAllContents.hasNext()) {
|
|
|
|
- EObject next = eAllContents.next();
|
|
|
|
- if (next instanceof View) {
|
|
|
|
- EList<Edge> targetEdges = ((View) next).getTargetEdges();
|
|
|
|
- for (Edge edge : targetEdges) {
|
|
|
|
- if (!EcoreUtil.isAncestor(subdiagram, edge.getSource()))
|
|
|
|
- entryPointsToCreate.add(edge);
|
|
|
|
- }
|
|
|
|
- EList<Edge> sourceEdges = ((View) next).getSourceEdges();
|
|
|
|
- for (Edge edge : sourceEdges) {
|
|
|
|
- if (!EcoreUtil.isAncestor(subdiagram, edge.getTarget()))
|
|
|
|
- exitPointstoCreate.add(edge);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- for (Edge edge : entryPointsToCreate) {
|
|
|
|
- createEntryPoint(edge, subdiagram);
|
|
|
|
- }
|
|
|
|
- for (Edge edge : exitPointstoCreate) {
|
|
|
|
- createExitPoint(edge, subdiagram);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected void createEntryPoint(Edge edge, Diagram subdiagram) {
|
|
|
|
- Transition transition = (Transition) edge.getElement();
|
|
|
|
- Region entryPointContainer = getEntryPointContainer(transition);
|
|
|
|
- Entry entryPoint = createSemanticEntryPoint(transition);
|
|
|
|
-
|
|
|
|
- // re-wire old transition to targeting the selected state
|
|
|
|
- transition.setTarget((State) subdiagram.getElement());
|
|
|
|
- View oldTarget = edge.getTarget();
|
|
|
|
- edge.setTarget(getContextObject());
|
|
|
|
-
|
|
|
|
- // create node for entry point
|
|
|
|
- View entryPointContainerView = helper.getViewForSemanticElement(entryPointContainer, subdiagram);
|
|
|
|
- View entryPointRegionCompartment = ViewUtil.getChildBySemanticHint(entryPointContainerView,
|
|
|
|
- SemanticHints.REGION_COMPARTMENT);
|
|
|
|
- Node entryNode = ViewService.createNode(entryPointRegionCompartment, entryPoint, SemanticHints.ENTRY,
|
|
|
|
- preferencesHint);
|
|
|
|
- ViewService.createEdge(entryNode, oldTarget, entryPoint.getOutgoingTransitions().get(0),
|
|
|
|
- SemanticHints.TRANSITION, preferencesHint);
|
|
|
|
-
|
|
|
|
- addEntryPointSpec(transition, entryPoint);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void addEntryPointSpec(Transition transition, Entry entryPoint) {
|
|
|
|
- EList<ReactionProperty> properties = transition.getProperties();
|
|
|
|
- EntryPointSpec entryPointSpec = StextFactory.eINSTANCE.createEntryPointSpec();
|
|
|
|
- // A transition can only have one entry point so alter the existing
|
|
|
|
- for (ReactionProperty reactionProperty : properties) {
|
|
|
|
- if (reactionProperty instanceof EntryPointSpec) {
|
|
|
|
- entryPointSpec = (EntryPointSpec) reactionProperty;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- entryPointSpec.setEntrypoint(entryPoint.getName());
|
|
|
|
- properties.add(entryPointSpec);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void addExitPointSpec(Transition transition, Exit exitPoint) {
|
|
|
|
- EList<ReactionProperty> properties = transition.getProperties();
|
|
|
|
- ExitPointSpec exitPointSpec = StextFactory.eINSTANCE.createExitPointSpec();
|
|
|
|
- // A transition can only have one exit point so alter the existing
|
|
|
|
- for (ReactionProperty reactionProperty : properties) {
|
|
|
|
- if (reactionProperty instanceof ExitPointSpec) {
|
|
|
|
- exitPointSpec = (ExitPointSpec) reactionProperty;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- exitPointSpec.setExitpoint(exitPoint.getName());
|
|
|
|
- properties.add(exitPointSpec);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected String getEntryPointName(Transition transition) {
|
|
|
|
- StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
- stringBuilder.append("entry_");
|
|
|
|
- stringBuilder.append(transition.getTarget().getName());
|
|
|
|
- int index = transition.getSource().getOutgoingTransitions().indexOf(transition);
|
|
|
|
- stringBuilder.append(index);
|
|
|
|
- return asIdentifier(stringBuilder.toString());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected String getExitPointName(Transition transition) {
|
|
|
|
- StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
- stringBuilder.append("exit_");
|
|
|
|
- stringBuilder.append(transition.getSource().getName());
|
|
|
|
- int index = transition.getSource().getOutgoingTransitions().indexOf(transition);
|
|
|
|
- stringBuilder.append(index);
|
|
|
|
- return asIdentifier(stringBuilder.toString());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected Entry createSemanticEntryPoint(Transition transition) {
|
|
|
|
- Region entryPointTarget = getEntryPointContainer(transition);
|
|
|
|
- String name = getEntryPointName(transition);
|
|
|
|
- Entry entryPoint = null;
|
|
|
|
- Iterator<Vertex> iterator = entryPointTarget.getVertices().iterator();
|
|
|
|
- while (iterator.hasNext()) {
|
|
|
|
- Vertex next = iterator.next();
|
|
|
|
- if (next instanceof Entry) {
|
|
|
|
- Entry current = (Entry) next;
|
|
|
|
- if (name.equals(current.getName())) {
|
|
|
|
- // Do nothing, there already exists an entry point
|
|
|
|
- return current;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- entryPoint = SGraphFactory.eINSTANCE.createEntry();
|
|
|
|
- entryPoint.setName(name);
|
|
|
|
- entryPointTarget.getVertices().add(entryPoint);
|
|
|
|
- Transition entryPointTransition = SGraphFactory.eINSTANCE.createTransition();
|
|
|
|
- entryPointTransition.setSource(entryPoint);
|
|
|
|
- entryPointTransition.setTarget(transition.getTarget());
|
|
|
|
-
|
|
|
|
- return entryPoint;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Exit createSemanticExitPoint(Transition transition) {
|
|
|
|
- Region exitPointContainer = getExitPointContainer(transition);
|
|
|
|
- String name = getExitPointName(transition);
|
|
|
|
-
|
|
|
|
- Exit exitPoint = null;
|
|
|
|
- Iterator<Vertex> iterator = exitPointContainer.getVertices().iterator();
|
|
|
|
- while (iterator.hasNext()) {
|
|
|
|
- Vertex next = iterator.next();
|
|
|
|
- if (next instanceof Exit) {
|
|
|
|
- Exit current = (Exit) next;
|
|
|
|
- if (name.equals(current.getName())) {
|
|
|
|
- // Do nothing, there already exists an entry point
|
|
|
|
- return current;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- exitPoint = SGraphFactory.eINSTANCE.createExit();
|
|
|
|
- exitPoint.setName(name);
|
|
|
|
- exitPointContainer.getVertices().add(exitPoint);
|
|
|
|
-
|
|
|
|
- return exitPoint;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Region getEntryPointContainer(Transition transition) {
|
|
|
|
- // entry point container is the subdiagram's state's region which
|
|
|
|
- // contains the transition target
|
|
|
|
- EObject firstParentRegion = transition.getTarget().getParentRegion();
|
|
|
|
- return getOutermostParentRegion(firstParentRegion);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Region getExitPointContainer(Transition transition) {
|
|
|
|
- // exit point container is the subdiagram's state's region which
|
|
|
|
- // contains the transition source
|
|
|
|
- EObject firstParentRegion = transition.getSource().getParentRegion();
|
|
|
|
- return getOutermostParentRegion(firstParentRegion);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Region getOutermostParentRegion(EObject element) {
|
|
|
|
- while (!(element.eContainer() instanceof Statechart)) {
|
|
|
|
- EObject container = element.eContainer();
|
|
|
|
- if (container instanceof State) {
|
|
|
|
- State parentState = (State) container;
|
|
|
|
- if (parentState.equals(subdiagram.getElement())) {
|
|
|
|
- return (Region) element;
|
|
|
|
- }
|
|
|
|
- element = parentState.getParentRegion();
|
|
|
|
- } else {
|
|
|
|
- element = element.eContainer();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected void createExitPoint(Edge edge, Diagram subdiagram) {
|
|
|
|
- Transition transition = (Transition) edge.getElement();
|
|
|
|
- // create semantic exit point
|
|
|
|
- Region exitPointContainer = getExitPointContainer(transition);
|
|
|
|
- Exit exitPoint = createSemanticExitPoint(transition);
|
|
|
|
-
|
|
|
|
- // create node for exit point
|
|
|
|
- View exitPointContainerView = helper.getViewForSemanticElement(exitPointContainer, subdiagram);
|
|
|
|
- View exitPointRegionCompartment = ViewUtil.getChildBySemanticHint(exitPointContainerView,
|
|
|
|
- SemanticHints.REGION_COMPARTMENT);
|
|
|
|
- Node exitNode = ViewService.createNode(exitPointRegionCompartment, exitPoint, SemanticHints.EXIT,
|
|
|
|
- preferencesHint);
|
|
|
|
-
|
|
|
|
- // re-wire existing transition to new exit point
|
|
|
|
- Vertex oldTransitionTarget = transition.getTarget();
|
|
|
|
- transition.setTarget(exitPoint);
|
|
|
|
- View oldEdgeTarget = edge.getTarget();
|
|
|
|
- edge.setTarget(exitNode);
|
|
|
|
-
|
|
|
|
- // create transition from selected state to former transition target
|
|
|
|
- Transition exitPointTransition = SGraphFactory.eINSTANCE.createTransition();
|
|
|
|
- exitPointTransition.setSource((State) subdiagram.getElement());
|
|
|
|
- exitPointTransition.setTarget(oldTransitionTarget);
|
|
|
|
- ViewService.createEdge(getContextObject(), oldEdgeTarget, exitPointTransition, SemanticHints.TRANSITION,
|
|
|
|
- preferencesHint);
|
|
|
|
-
|
|
|
|
- addExitPointSpec(exitPointTransition, exitPoint);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Sets the GMF inline {@link Style} to true
|
|
|
|
- */
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- protected void setNotationStyle() {
|
|
|
|
- BooleanValueStyle inlineStyle = getInlineStyle(getContextObject());
|
|
|
|
- if (inlineStyle == null) {
|
|
|
|
- inlineStyle = createInlineStyle();
|
|
|
|
- getContextObject().getStyles().add(inlineStyle);
|
|
|
|
- }
|
|
|
|
- inlineStyle.setBooleanValue(false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Creates a new {@link Diagram} and copies child elements
|
|
|
|
- */
|
|
|
|
- protected Diagram createSubdiagram() {
|
|
|
|
- View contextView = getContextObject();
|
|
|
|
- State contextElement = (State) contextView.getElement();
|
|
|
|
- Diagram subdiagram = ViewService.createDiagram(contextElement, StatechartDiagramEditor.ID, preferencesHint);
|
|
|
|
- View figureCompartment = ViewUtil.getChildBySemanticHint(contextView, SemanticHints.STATE_FIGURE_COMPARTMENT);
|
|
|
|
- getResource().getContents().add(subdiagram);
|
|
|
|
- while (figureCompartment.getChildren().size() > 0) {
|
|
|
|
- subdiagram.insertChild((View) figureCompartment.getChildren().get(0));
|
|
|
|
- }
|
|
|
|
- return subdiagram;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- protected void setPreferredSize() {
|
|
|
|
- Node node = (Node) getContextObject();
|
|
|
|
- Bounds bounds = (Bounds) node.getLayoutConstraint();
|
|
|
|
- bounds.setWidth(-1);
|
|
|
|
- bounds.setHeight(-1);
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
+/**
|
|
|
|
+ * Copyright (c) 2013 committers of YAKINDU and others.
|
|
|
|
+ * 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:
|
|
|
|
+ * committers of YAKINDU - initial API and implementation
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+package org.yakindu.sct.refactoring.refactor.impl;
|
|
|
|
+
|
|
|
|
+import static org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil.createInlineStyle;
|
|
|
|
+import static org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil.getInlineStyle;
|
|
|
|
+
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Iterator;
|
|
|
|
+import java.util.List;
|
|
|
|
+
|
|
|
|
+import org.eclipse.draw2d.geometry.Rectangle;
|
|
|
|
+import org.eclipse.emf.common.util.EList;
|
|
|
|
+import org.eclipse.emf.common.util.TreeIterator;
|
|
|
|
+import org.eclipse.emf.ecore.EObject;
|
|
|
|
+import org.eclipse.emf.ecore.util.EcoreUtil;
|
|
|
|
+import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint;
|
|
|
|
+import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
|
|
|
|
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
|
|
|
|
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
|
|
|
|
+import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramGraphicalViewer;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.BooleanValueStyle;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.Bounds;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.Diagram;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.Edge;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.Node;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.Style;
|
|
|
|
+import org.eclipse.gmf.runtime.notation.View;
|
|
|
|
+import org.eclipse.ui.IEditorPart;
|
|
|
|
+import org.yakindu.base.xtext.utils.jface.viewers.util.ActiveEditorTracker;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Entry;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Exit;
|
|
|
|
+import org.yakindu.sct.model.sgraph.ReactionProperty;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Region;
|
|
|
|
+import org.yakindu.sct.model.sgraph.SGraphFactory;
|
|
|
|
+import org.yakindu.sct.model.sgraph.State;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Statechart;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Transition;
|
|
|
|
+import org.yakindu.sct.model.sgraph.Vertex;
|
|
|
|
+import org.yakindu.sct.model.stext.stext.EntryPointSpec;
|
|
|
|
+import org.yakindu.sct.model.stext.stext.ExitPointSpec;
|
|
|
|
+import org.yakindu.sct.model.stext.stext.StextFactory;
|
|
|
|
+import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
|
|
|
|
+import org.yakindu.sct.ui.editor.DiagramActivator;
|
|
|
|
+import org.yakindu.sct.ui.editor.editor.StatechartDiagramEditor;
|
|
|
|
+import org.yakindu.sct.ui.editor.factories.StateViewFactory;
|
|
|
|
+import org.yakindu.sct.ui.editor.partitioning.DiagramPartitioningUtil;
|
|
|
|
+import org.yakindu.sct.ui.editor.providers.SemanticHints;
|
|
|
|
+import org.yakindu.sct.ui.editor.utils.GMFNotationUtil;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ *
|
|
|
|
+ * @author andreas muelder - Initial contribution and API
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+public class ExtractSubdiagramRefactoring extends AbstractRefactoring<View> {
|
|
|
|
+
|
|
|
|
+ protected PreferencesHint preferencesHint = DiagramActivator.DIAGRAM_PREFERENCES_HINT;
|
|
|
|
+ private Diagram subdiagram;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isExecutable() {
|
|
|
|
+ EObject element = getContextObject().getElement();
|
|
|
|
+ if (!(element instanceof State)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ State state = (State) element;
|
|
|
|
+ BooleanValueStyle inlineStyle = getInlineStyle(getContextObject());
|
|
|
|
+ return super.isExecutable() && state.isComposite() && (inlineStyle == null || inlineStyle.isBooleanValue());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected void internalExecute() {
|
|
|
|
+ setNotationStyle();
|
|
|
|
+ subdiagram = createSubdiagram();
|
|
|
|
+ createEntryExitPoints(subdiagram);
|
|
|
|
+ setPreferredSize();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected boolean internalDoUndo() {
|
|
|
|
+ // close the sub diagram before undo will delete it
|
|
|
|
+ return DiagramPartitioningUtil.closeSubdiagramEditors((State) subdiagram.getElement());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ protected void createEntryExitPoints(Diagram subdiagram) {
|
|
|
|
+ TreeIterator<EObject> eAllContents = subdiagram.eAllContents();
|
|
|
|
+ List<Edge> entryPointsToCreate = new ArrayList<Edge>();
|
|
|
|
+ List<Edge> exitPointstoCreate = new ArrayList<Edge>();
|
|
|
|
+ while (eAllContents.hasNext()) {
|
|
|
|
+ EObject next = eAllContents.next();
|
|
|
|
+ if (next instanceof View) {
|
|
|
|
+ EList<Edge> targetEdges = ((View) next).getTargetEdges();
|
|
|
|
+ for (Edge edge : targetEdges) {
|
|
|
|
+ if (!EcoreUtil.isAncestor(subdiagram, edge.getSource()))
|
|
|
|
+ entryPointsToCreate.add(edge);
|
|
|
|
+ }
|
|
|
|
+ EList<Edge> sourceEdges = ((View) next).getSourceEdges();
|
|
|
|
+ for (Edge edge : sourceEdges) {
|
|
|
|
+ if (!EcoreUtil.isAncestor(subdiagram, edge.getTarget()))
|
|
|
|
+ exitPointstoCreate.add(edge);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for (Edge edge : entryPointsToCreate) {
|
|
|
|
+ createEntryPoint(edge, subdiagram);
|
|
|
|
+ }
|
|
|
|
+ for (Edge edge : exitPointstoCreate) {
|
|
|
|
+ createExitPoint(edge, subdiagram);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void createEntryPoint(Edge edge, Diagram subdiagram) {
|
|
|
|
+ Transition transition = (Transition) edge.getElement();
|
|
|
|
+ Region entryPointContainer = getEntryPointContainer(transition);
|
|
|
|
+ Entry entryPoint = createSemanticEntryPoint(transition);
|
|
|
|
+
|
|
|
|
+ // re-wire old transition to targeting the selected state
|
|
|
|
+ transition.setTarget((State) subdiagram.getElement());
|
|
|
|
+ View oldTarget = edge.getTarget();
|
|
|
|
+ edge.setTarget(getContextObject());
|
|
|
|
+
|
|
|
|
+ // create node for entry point
|
|
|
|
+ View entryPointContainerView = helper.getViewForSemanticElement(entryPointContainer, subdiagram);
|
|
|
|
+ View entryPointRegionCompartment = ViewUtil.getChildBySemanticHint(entryPointContainerView,
|
|
|
|
+ SemanticHints.REGION_COMPARTMENT);
|
|
|
|
+ Node entryNode = ViewService.createNode(entryPointRegionCompartment, entryPoint, SemanticHints.ENTRY,
|
|
|
|
+ preferencesHint);
|
|
|
|
+ ViewService.createEdge(entryNode, oldTarget, entryPoint.getOutgoingTransitions().get(0),
|
|
|
|
+ SemanticHints.TRANSITION, preferencesHint);
|
|
|
|
+
|
|
|
|
+ addEntryPointSpec(transition, entryPoint);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void addEntryPointSpec(Transition transition, Entry entryPoint) {
|
|
|
|
+ EList<ReactionProperty> properties = transition.getProperties();
|
|
|
|
+ EntryPointSpec entryPointSpec = StextFactory.eINSTANCE.createEntryPointSpec();
|
|
|
|
+ // A transition can only have one entry point so alter the existing
|
|
|
|
+ for (ReactionProperty reactionProperty : properties) {
|
|
|
|
+ if (reactionProperty instanceof EntryPointSpec) {
|
|
|
|
+ entryPointSpec = (EntryPointSpec) reactionProperty;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ entryPointSpec.setEntrypoint(entryPoint.getName());
|
|
|
|
+ properties.add(entryPointSpec);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void addExitPointSpec(Transition transition, Exit exitPoint) {
|
|
|
|
+ EList<ReactionProperty> properties = transition.getProperties();
|
|
|
|
+ ExitPointSpec exitPointSpec = StextFactory.eINSTANCE.createExitPointSpec();
|
|
|
|
+ // A transition can only have one exit point so alter the existing
|
|
|
|
+ for (ReactionProperty reactionProperty : properties) {
|
|
|
|
+ if (reactionProperty instanceof ExitPointSpec) {
|
|
|
|
+ exitPointSpec = (ExitPointSpec) reactionProperty;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ exitPointSpec.setExitpoint(exitPoint.getName());
|
|
|
|
+ properties.add(exitPointSpec);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected String getEntryPointName(Transition transition) {
|
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
+ stringBuilder.append("entry_");
|
|
|
|
+ stringBuilder.append(transition.getTarget().getName());
|
|
|
|
+ int index = transition.getSource().getOutgoingTransitions().indexOf(transition);
|
|
|
|
+ stringBuilder.append(index);
|
|
|
|
+ return asIdentifier(stringBuilder.toString());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected String getExitPointName(Transition transition) {
|
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
+ stringBuilder.append("exit_");
|
|
|
|
+ stringBuilder.append(transition.getSource().getName());
|
|
|
|
+ int index = transition.getSource().getOutgoingTransitions().indexOf(transition);
|
|
|
|
+ stringBuilder.append(index);
|
|
|
|
+ return asIdentifier(stringBuilder.toString());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected Entry createSemanticEntryPoint(Transition transition) {
|
|
|
|
+ Region entryPointTarget = getEntryPointContainer(transition);
|
|
|
|
+ String name = getEntryPointName(transition);
|
|
|
|
+ Entry entryPoint = null;
|
|
|
|
+ Iterator<Vertex> iterator = entryPointTarget.getVertices().iterator();
|
|
|
|
+ while (iterator.hasNext()) {
|
|
|
|
+ Vertex next = iterator.next();
|
|
|
|
+ if (next instanceof Entry) {
|
|
|
|
+ Entry current = (Entry) next;
|
|
|
|
+ if (name.equals(current.getName())) {
|
|
|
|
+ // Do nothing, there already exists an entry point
|
|
|
|
+ return current;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ entryPoint = SGraphFactory.eINSTANCE.createEntry();
|
|
|
|
+ entryPoint.setName(name);
|
|
|
|
+ entryPointTarget.getVertices().add(entryPoint);
|
|
|
|
+ Transition entryPointTransition = SGraphFactory.eINSTANCE.createTransition();
|
|
|
|
+ entryPointTransition.setSource(entryPoint);
|
|
|
|
+ entryPointTransition.setTarget(transition.getTarget());
|
|
|
|
+
|
|
|
|
+ return entryPoint;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Exit createSemanticExitPoint(Transition transition) {
|
|
|
|
+ Region exitPointContainer = getExitPointContainer(transition);
|
|
|
|
+ String name = getExitPointName(transition);
|
|
|
|
+
|
|
|
|
+ Exit exitPoint = null;
|
|
|
|
+ Iterator<Vertex> iterator = exitPointContainer.getVertices().iterator();
|
|
|
|
+ while (iterator.hasNext()) {
|
|
|
|
+ Vertex next = iterator.next();
|
|
|
|
+ if (next instanceof Exit) {
|
|
|
|
+ Exit current = (Exit) next;
|
|
|
|
+ if (name.equals(current.getName())) {
|
|
|
|
+ // Do nothing, there already exists an entry point
|
|
|
|
+ return current;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ exitPoint = SGraphFactory.eINSTANCE.createExit();
|
|
|
|
+ exitPoint.setName(name);
|
|
|
|
+ exitPointContainer.getVertices().add(exitPoint);
|
|
|
|
+
|
|
|
|
+ return exitPoint;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Region getEntryPointContainer(Transition transition) {
|
|
|
|
+ // entry point container is the subdiagram's state's region which
|
|
|
|
+ // contains the transition target
|
|
|
|
+ EObject firstParentRegion = transition.getTarget().getParentRegion();
|
|
|
|
+ return getOutermostParentRegion(firstParentRegion);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Region getExitPointContainer(Transition transition) {
|
|
|
|
+ // exit point container is the subdiagram's state's region which
|
|
|
|
+ // contains the transition source
|
|
|
|
+ EObject firstParentRegion = transition.getSource().getParentRegion();
|
|
|
|
+ return getOutermostParentRegion(firstParentRegion);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Region getOutermostParentRegion(EObject element) {
|
|
|
|
+ while (!(element.eContainer() instanceof Statechart)) {
|
|
|
|
+ EObject container = element.eContainer();
|
|
|
|
+ if (container instanceof State) {
|
|
|
|
+ State parentState = (State) container;
|
|
|
|
+ if (parentState.equals(subdiagram.getElement())) {
|
|
|
|
+ return (Region) element;
|
|
|
|
+ }
|
|
|
|
+ element = parentState.getParentRegion();
|
|
|
|
+ } else {
|
|
|
|
+ element = element.eContainer();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void createExitPoint(Edge edge, Diagram subdiagram) {
|
|
|
|
+ Transition transition = (Transition) edge.getElement();
|
|
|
|
+ // create semantic exit point
|
|
|
|
+ Region exitPointContainer = getExitPointContainer(transition);
|
|
|
|
+ Exit exitPoint = createSemanticExitPoint(transition);
|
|
|
|
+
|
|
|
|
+ // create node for exit point
|
|
|
|
+ View exitPointContainerView = helper.getViewForSemanticElement(exitPointContainer, subdiagram);
|
|
|
|
+ View exitPointRegionCompartment = ViewUtil.getChildBySemanticHint(exitPointContainerView,
|
|
|
|
+ SemanticHints.REGION_COMPARTMENT);
|
|
|
|
+ Node exitNode = ViewService.createNode(exitPointRegionCompartment, exitPoint, SemanticHints.EXIT,
|
|
|
|
+ preferencesHint);
|
|
|
|
+
|
|
|
|
+ // re-wire existing transition to new exit point
|
|
|
|
+ Vertex oldTransitionTarget = transition.getTarget();
|
|
|
|
+ transition.setTarget(exitPoint);
|
|
|
|
+ View oldEdgeTarget = edge.getTarget();
|
|
|
|
+ edge.setTarget(exitNode);
|
|
|
|
+
|
|
|
|
+ // create transition from selected state to former transition target
|
|
|
|
+ Transition exitPointTransition = SGraphFactory.eINSTANCE.createTransition();
|
|
|
|
+ exitPointTransition.setSource((State) subdiagram.getElement());
|
|
|
|
+ exitPointTransition.setTarget(oldTransitionTarget);
|
|
|
|
+ ViewService.createEdge(getContextObject(), oldEdgeTarget, exitPointTransition, SemanticHints.TRANSITION,
|
|
|
|
+ preferencesHint);
|
|
|
|
+
|
|
|
|
+ addExitPointSpec(exitPointTransition, exitPoint);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Sets the GMF inline {@link Style} to true
|
|
|
|
+ */
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ protected void setNotationStyle() {
|
|
|
|
+ BooleanValueStyle inlineStyle = getInlineStyle(getContextObject());
|
|
|
|
+ if (inlineStyle == null) {
|
|
|
|
+ inlineStyle = createInlineStyle();
|
|
|
|
+ getContextObject().getStyles().add(inlineStyle);
|
|
|
|
+ }
|
|
|
|
+ inlineStyle.setBooleanValue(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Creates a new {@link Diagram} and copies child elements
|
|
|
|
+ */
|
|
|
|
+ protected Diagram createSubdiagram() {
|
|
|
|
+ View contextView = getContextObject();
|
|
|
|
+ State contextElement = (State) contextView.getElement();
|
|
|
|
+ Diagram subdiagram = ViewService.createDiagram(contextElement, StatechartDiagramEditor.ID, preferencesHint);
|
|
|
|
+ View figureCompartment = ViewUtil.getChildBySemanticHint(contextView, SemanticHints.STATE_FIGURE_COMPARTMENT);
|
|
|
|
+ getResource().getContents().add(subdiagram);
|
|
|
|
+
|
|
|
|
+ boolean isHorizontal = isHorizontal(figureCompartment);
|
|
|
|
+ int offset = 0;
|
|
|
|
+ while (figureCompartment.getChildren().size() > 0) {
|
|
|
|
+ Node child = (Node) figureCompartment.getChildren().get(0);
|
|
|
|
+ Rectangle actualBounds = getActualBounds(child);
|
|
|
|
+ if (actualBounds != Rectangle.SINGLETON) {
|
|
|
|
+ Bounds modelBounds = (Bounds) child.getLayoutConstraint();
|
|
|
|
+ modelBounds.setWidth(actualBounds.width());
|
|
|
|
+ modelBounds.setHeight(actualBounds.height());
|
|
|
|
+ if (isHorizontal) {
|
|
|
|
+ modelBounds.setX(offset);
|
|
|
|
+ offset += actualBounds.width();
|
|
|
|
+ } else {
|
|
|
|
+ modelBounds.setY(offset);
|
|
|
|
+ offset += actualBounds.height();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ subdiagram.insertChild(child);
|
|
|
|
+ }
|
|
|
|
+ return subdiagram;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected boolean isHorizontal(View child) {
|
|
|
|
+ BooleanValueStyle style = GMFNotationUtil.getBooleanValueStyle((View) child.eContainer(),
|
|
|
|
+ StateViewFactory.ALIGNMENT_ORIENTATION);
|
|
|
|
+ return (style != null) ? style.isBooleanValue() : true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected Rectangle getActualBounds(Node child) {
|
|
|
|
+ IEditorPart lastActiveEditor = ActiveEditorTracker.getLastActiveEditor();
|
|
|
|
+ if (lastActiveEditor instanceof StatechartDiagramEditor) {
|
|
|
|
+ IDiagramGraphicalViewer viewer = ((StatechartDiagramEditor) lastActiveEditor).getDiagramGraphicalViewer();
|
|
|
|
+ IGraphicalEditPart editPart = (IGraphicalEditPart) viewer.getEditPartRegistry().get(child);
|
|
|
|
+ return editPart.getFigure().getBounds();
|
|
|
|
+ }
|
|
|
|
+ return Rectangle.SINGLETON;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void setPreferredSize() {
|
|
|
|
+ Node node = (Node) getContextObject();
|
|
|
|
+ Bounds bounds = (Bounds) node.getLayoutConstraint();
|
|
|
|
+ bounds.setWidth(-1);
|
|
|
|
+ bounds.setHeight(-1);
|
|
|
|
+ }
|
|
|
|
+}
|