Commit 281cb810 authored by Christian Hilden's avatar Christian Hilden
Browse files

[ui.behavior] Improve initial FSM layout

* Spread states from the top left to the bottom right of the diagram
* Spread self-transitions
* Spread transitions sharing the same path (nodeA <-> nodeB)
* Slightly reduce font size of transition labels
parent c8a5c7b6
Pipeline #3903 passed with stage
in 0 seconds
......@@ -17,6 +17,7 @@ package org.eclipse.etrice.core.fsm.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
......@@ -35,6 +36,7 @@ import org.eclipse.etrice.core.fsm.fSM.FSMPackage;
import org.eclipse.etrice.core.fsm.fSM.InitialTransition;
import org.eclipse.etrice.core.fsm.fSM.MessageFromIf;
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.SimpleState;
......@@ -51,6 +53,7 @@ import org.eclipse.etrice.core.fsm.fSM.TransitionChainStartTransition;
import org.eclipse.etrice.core.fsm.fSM.TransitionPoint;
import org.eclipse.etrice.core.fsm.fSM.TransitionTerminal;
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 com.google.common.base.Function;
......@@ -1298,6 +1301,19 @@ public class FSMHelpers extends BaseHelpers {
}
return null;
}
public Transition getInitTransitionForNodeList(Set<StateGraph> sgs, List<StateGraphNode> allowedTargetNodes) {
for (StateGraph sg : sgs) {
Transition initTrans = getInitTransition(sg);
if (initTrans != null) {
StateGraphNode target = getTerminalState(initTrans.getTo());
if (allowedTargetNodes.contains(target)) {
return initTrans;
}
}
}
return null;
}
/**
* @param sg a {@link StateGraph}
......@@ -1306,5 +1322,123 @@ public class FSMHelpers extends BaseHelpers {
public boolean hasInitTransition(StateGraph sg) {
return getInitTransition(sg)!=null;
}
public StateGraphNode getTerminalState(TransitionTerminal tt) {
if (tt instanceof SubStateTrPointTerminal) {
return ((SubStateTrPointTerminal) tt).getState();
}
return getTerminalNode(tt);
}
public StateGraphNode getTerminalNode(TransitionTerminal tt) {
if (tt instanceof ChoicepointTerminal)
{
return ((ChoicepointTerminal) tt).getCp();
}
if (tt instanceof SubStateTrPointTerminal) {
return ((SubStateTrPointTerminal) tt).getTrPoint();
}
if (tt instanceof TrPointTerminal) {
return ((TrPointTerminal) tt).getTrPoint();
}
if (tt instanceof StateTerminal) {
return ((StateTerminal) tt).getState();
}
return null;
}
public List<Transition> getTransitionsFromGraphNode(Set<StateGraph> sgs, StateGraphNode node) {
Set<Transition> result = new HashSet<>();
for (StateGraph sg : sgs) {
result.addAll(getTransitionsFromGraphNode(sg, node));
}
return new ArrayList<>(result);
}
/**
* @return all Transitions originating from the passed graph node
*/
public List<Transition> getTransitionsFromGraphNode(StateGraph sg, StateGraphNode node) {
ArrayList<Transition> result = new ArrayList<>();
for (Transition tr : sg.getTransitions()) {
if (tr instanceof NonInitialTransition) {
TransitionTerminal tt = ((NonInitialTransition) tr).getFrom();
if (getTerminalState(tt) == node) {
result.add(tr);
}
}
}
return result;
}
public List<Transition> getTransitionsToGraphNode(Set<StateGraph> sgs, StateGraphNode node) {
Set<Transition> result = new HashSet<>();
for (StateGraph sg : sgs) {
result.addAll(getTransitionsToGraphNode(sg, node));
}
return new ArrayList<>(result);
}
/**
* @return all Transitions ending in the passed graph node
*/
public List<Transition> getTransitionsToGraphNode(StateGraph sg, StateGraphNode node) {
ArrayList<Transition> result = new ArrayList<>();
for (Transition tr : sg.getTransitions()) {
TransitionTerminal tt = tr.getTo();
if (getTerminalState(tt) == node) {
result.add(tr);
}
}
return result;
}
/**
* @return All graph nodes (TrPoints + States + ChPoints) for the passed graph
*/
public List<StateGraphNode> getAllNodes(StateGraph sg) {
List<StateGraphNode> result = new LinkedList<>();
result.addAll(sg.getTrPoints());
result.addAll(sg.getStates());
result.addAll(sg.getChPoints());
return result;
}
/**
* @return true if the passed transition has the same source and destination graph node
*/
public boolean isSelfTransition(Transition trans) {
StateGraphNode from = (trans instanceof InitialTransition)? null:getTerminalState(((NonInitialTransition)trans).getFrom());
StateGraphNode to = getTerminalState(trans.getTo());
return from == to;
}
/**
* @return number of transitions on the same path (nodeA -> nodeB). Returns >= 1 for any valid transition.
*/
public int getSamePathTransitionCount(StateGraph sg, Transition trans) {
int count = 1;
StateGraphNode src = (trans instanceof InitialTransition) ? null : getTerminalState(((NonInitialTransition)trans).getFrom());
StateGraphNode dest = getTerminalState(trans.getTo());
for (Transition t : sg.getTransitions()) {
if (trans == t) {
continue;
}
StateGraphNode tSrc = (t instanceof InitialTransition) ? null : getTerminalState(((NonInitialTransition)t).getFrom());
StateGraphNode tDest = getTerminalState(t.getTo());
if (tSrc == src && tDest == dest || tSrc == dest && tDest == src) {
count++;
}
}
return count;
}
}
......@@ -82,6 +82,19 @@ public interface IPositionProvider {
public int getHeight() {
return height;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PosAndSize)) {
return false;
}
PosAndSize compareObj = (PosAndSize) obj;
return compareObj.getHeight() == this.height &&
compareObj.getWidth() == this.width &&
compareObj.getX() == this.getX() &&
compareObj.getY() == this.getY()
;
}
}
/**
......
......@@ -225,7 +225,8 @@ public class StateGraphSupport {
int w = containerGa.getWidth();
int h = containerGa.getHeight();
// Adjust rounded rect sizes
if (containerGa.getGraphicsAlgorithmChildren().size()>=1) {
GraphicsAlgorithm ga = containerGa.getGraphicsAlgorithmChildren().get(0);
ga.setWidth(w-2*MARGIN);
......@@ -236,6 +237,7 @@ public class StateGraphSupport {
anythingChanged = true;
}
// Adjust "path" label
if (containerShape.getChildren().size()>=1) {
GraphicsAlgorithm ga = containerShape.getChildren().get(0).getGraphicsAlgorithm();
ga.setWidth(w-2*MARGIN);
......
......@@ -14,10 +14,20 @@
package org.eclipse.etrice.ui.behavior.fsm.support;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.etrice.core.fsm.fSM.CPBranchTransition;
import org.eclipse.etrice.core.fsm.fSM.ChoicepointTerminal;
......@@ -98,6 +108,7 @@ import org.eclipse.graphiti.mm.algorithms.Polygon;
import org.eclipse.graphiti.mm.algorithms.Polyline;
import org.eclipse.graphiti.mm.algorithms.Text;
import org.eclipse.graphiti.mm.algorithms.styles.Color;
import org.eclipse.graphiti.mm.algorithms.styles.Font;
import org.eclipse.graphiti.mm.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.Connection;
......@@ -120,6 +131,7 @@ import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.themes.ColorAndFontProviderImpl;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.xbase.lib.Pair;
......@@ -346,7 +358,8 @@ public class TransitionSupport {
ConnectionDecorator textDecorator =
peCreateService.createConnectionDecorator(connection, true,
0.5, true);
Text text = gaService.createDefaultText(getDiagram(), textDecorator, getLabel(trans));
Text text = gaService.createText(getDiagram(), textDecorator, getLabel(trans), "Arial", 6);
text.setForeground(lineColor);
gaService.setLocation(text, 10, 0);
......
/*******************************************************************************
* Copyright (c) 2010 protos software gmbh (http://www.protos.de).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* CONTRIBUTORS:
* Christian Hilden (initial contribution)
*
*******************************************************************************/
package org.eclipse.etrice.ui.behavior.fsm.support.util
import org.eclipse.graphiti.mm.pictograms.ContainerShape
import org.eclipse.etrice.ui.behavior.fsm.support.StateGraphSupport
import org.eclipse.graphiti.mm.pictograms.Shape
import org.eclipse.graphiti.mm.pictograms.PictogramElement
import org.eclipse.graphiti.services.Graphiti
import org.eclipse.etrice.core.fsm.fSM.TransitionPoint
import org.eclipse.etrice.core.fsm.fSM.EntryPoint
import org.eclipse.etrice.core.fsm.fSM.ExitPoint
import org.eclipse.etrice.core.fsm.fSM.State
class FSMSizeAndPositionUtil {
/**
* Ensured the StateGraphContainer has enough size for all contained shapes
*/
static def void resizeDiagramFrame(ContainerShape sgShape) {
var minWidth = StateGraphSupport.DEFAULT_SIZE_X;
var minHeight = StateGraphSupport.DEFAULT_SIZE_Y;
for (Shape child : sgShape.getChildren()) {
val ga = child.getGraphicsAlgorithm();
minWidth = Math.max(minWidth, ga.getWidth() + ga.getX());
minHeight = Math.max(minHeight, ga.getHeight() + ga.getY());
}
val sgGa = sgShape.graphicsAlgorithm;
// GA children != shape children, first ga child of sgShape is rounded rect
// There are 2 rounded rect children. One with alpha filter + one with non alpha frame
val gaRoundedRect1 = sgGa.getGraphicsAlgorithmChildren().get(0);
val gaRoundedRect2 = sgGa.getGraphicsAlgorithmChildren().get(1);
val oldFrameWidth = gaRoundedRect1.width;
val oldFrameHeight = gaRoundedRect1.height;
if (sgGa.width < minWidth) {
sgGa.setWidth(minWidth + StateGraphSupport.MARGIN * 2);
gaRoundedRect1.setWidth(minWidth + StateGraphSupport.MARGIN);
gaRoundedRect2.setWidth(minWidth + StateGraphSupport.MARGIN);
}
if (sgGa.height < minHeight) {
sgGa.setHeight(minHeight + StateGraphSupport.MARGIN * 2);
gaRoundedRect1.setHeight(minHeight+ StateGraphSupport.MARGIN);
gaRoundedRect2.setHeight(minHeight+ StateGraphSupport.MARGIN);
}
// Fix all nodes which are stuck to the container border (transition points)
// For some reason the border and distances behave differently depending if we are in the root element or a SubStatemachine
val sg = Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(sgShape as PictogramElement);
val frameOffset = if (sg.eContainer instanceof State) StateGraphSupport.MARGIN else 0;
fixBorderNodesAfterResize(sgShape, oldFrameWidth, oldFrameHeight, gaRoundedRect1.width, gaRoundedRect1.height - frameOffset);
}
static def void fixBorderNodesAfterResize(
ContainerShape sgShape
, int oldFrameWidth
, int oldFrameHeight
, int newFrameWidth
, int newFrameHeight
) {
for (Shape child : sgShape.getChildren()) {
val bo = Graphiti.linkService.getBusinessObjectForLinkedPictogramElement(child as PictogramElement)
if (bo instanceof TransitionPoint || bo instanceof EntryPoint || bo instanceof ExitPoint) {
if (child.graphicsAlgorithm.x == oldFrameWidth) {
// right border
child.graphicsAlgorithm.x = newFrameWidth
} else if (child.graphicsAlgorithm.y == oldFrameHeight) {
// bottom border
child.graphicsAlgorithm.y = newFrameHeight
}
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment