Home » Eclipse Projects » Sirius » Problem with custom layout provider
Problem with custom layout provider [message #1743091] |
Mon, 12 September 2016 03:07  |
Eclipse User |
|
|
|
Hello,
I had a question about the order of execution of commands in CompoundCommand.
Implements a custom layout provider (click on the Arrange All), where the need to sequentially execute three actions
1. place the nodes on a specific position and set their size
2. ensure a minimum distance between nodes (protection zone)
3. connection nodes via edges with its own algorithm
I have several problems.
1. Individual commands are called sequentially, but in a graphical editor, it seems that all are executed simultaneously, ie. the animation shows how the nodes move and in same time are connected. This has the effect that it incorrectly operates my algorithm connection nodes because the nodes are not yet in place. How to correctly ensure that the command executed after the end of previous command?
2. Command execution will not always right, respectively. in debug are all the calculations algorithms correctly, but the graphics editor, I see that some changes are implemented only after repeated call Arrange All. How to ensure that the actions execute on the first call?
I have the code below.
Thanks for any advice.
Martin
public class CustomLayoutProvider implements LayoutProvider {
@Override
public AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container) {
if (isProcessDiagram(container)) {
if (this.layoutProvider == null) {
this.layoutProvider = new ExecuteLayoutProvider(container);
ArrangeRequest layoutRequest = new ArrangeRequest(ActionIds.ACTION_ARRANGE_ALL);
Animation.markBegin();
container.performRequest(layoutRequest);
// time animation
Animation.run(500);
}
}
return this.layoutProvider;
}
@Override
public boolean isDiagramLayoutProvider() {
return false;
}
@Override
public boolean provides(IGraphicalEditPart container) {
return isProcessDiagram(container);
}
private boolean isProcessDiagram(IGraphicalEditPart container) {
if (container instanceof AbstractDDiagramEditPart) {
AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
if (editPart.resolveSemanticElement() instanceof DDiagram) {
DDiagram diagram = (DDiagram) editPart.resolveSemanticElement();
if (diagram.getDescription() != null) {
DiagramDescription diagramDescription = diagram.getDescription();
String name = diagramDescription.getName();
if (name.equals(GraphicalProcessEditor.PROCESS_DIAGRAM_NAME) || name.equals(GraphicalProcessEditor.SUBPROCESS_DIAGRAM_NAME)) {
return true;
}
}
}
}
return false;
}
class ExecuteLayoutProvider extends AbstractLayoutProvider {
private IGraphicalEditPart container;
public ExecuteLayoutProvider(IGraphicalEditPart container) {
this.container = container;
}
@Override
public Command layoutEditParts(List selectedObjects, IAdaptable layoutHint) {
// load data
loadData();
if (selectedObjects.isEmpty()) {
return UnexecutableCommand.INSTANCE;
}
CompoundCommand command = new CompoundCommand();
// 1. command - placing nodes (setting location and size)
final PlacingNodesCommand placingNodesCommand = new PlacingNodesCommand(selectedObjects);
command.add(placingNodesCommand);
// 2. command - protection zone
final ProtectionZoneCommand protectionZoneCommand = new ProtectionZoneCommand(selectedObjects);
command.add(protectionZoneCommand);
// 3. command - routing edge - input left, output right
final RoutingInputOutputCommand routingInputOutputCommand = new RoutingInputOutputCommand(selectedObjects);
command.add(routingInputOutputCommand);
command.execute();
return command;
}
}
class PlacingNodesCommand extends Command {
private List<?> selectedObjects = null;
public PlacingNodesCommand(List<?> selectedObjects) {
super();
this.selectedObjects = selectedObjects;
}
@Override
public void execute() {
// filter all IGraphicalEditPart from the list of selected objects
for (IGraphicalEditPart graphicalEditPart : Iterables.filter(selectedObjects, IGraphicalEditPart.class)) {
View notationView = graphicalEditPart.getNotationView();
// element is a node
if (notationView instanceof Node) {
final Node node = (Node) notationView;
final LayoutConstraint layoutConstraint = node.getLayoutConstraint();
final EObject eObject = node.getElement();
ProcessElement processElement = getProcessElement(eObject);
if (processElement == null) {
logger.error("Process element is null.");
}
// set element - the position and size
setPositionAndSizeElements(layoutConstraint, processElement);
}
// refresh
graphicalEditPart.refresh();
}
}
}
class ProtectionZoneCommand extends Command {
private List<?> selectedObjects = null;
public ProtectionZoneCommand(List<?> selectedObjects) {
super();
this.selectedObjects = selectedObjects;
}
@Override
public void execute() {
setProtectionZone(selectedObjects);
}
}
class RoutingInputOutputCommand extends Command {
private List<?> selectedObjects = null;
public RoutingInputOutputCommand(List<?> selectedObjects) {
super();
this.selectedObjects = selectedObjects;
}
@SuppressWarnings("restriction")
@Override
public void execute() {
// filter all IGraphicalEditPart from the list of selected objects
for (IGraphicalEditPart graphicalEditPart : Iterables.filter(selectedObjects, IGraphicalEditPart.class)) {
View notationView = graphicalEditPart.getNotationView();
// element is an edge - for creating UI edges RelativeBendpoints
if (notationView instanceof Edge) {
final Edge edge = (Edge) notationView;
Bendpoints bendpoints = edge.getBendpoints();
if (bendpoints instanceof RelativeBendpoints) {
RelativeBendpoints relativeBendpoints = (RelativeBendpoints) bendpoints;
// list of new points of edges
List<RelativeBendpoint> newBendpoints = new ArrayList<>();
// get connection - between which the source node and the target node exists edge
Connection connection = (Connection) GMFHelper.getGraphicalEditPart(edge).get().getFigure();
Point sourceRefPoint = connection.getSourceAnchor().getReferencePoint();
Point targetRefPoint = connection.getTargetAnchor().getReferencePoint();
connection.translateToRelative(sourceRefPoint);
connection.translateToRelative(targetRefPoint);
IFigure sourceFigure = connection.getSourceAnchor().getOwner();
IFigure targetFigure = connection.getTargetAnchor().getOwner();
List<?> points = relativeBendpoints.getPoints();
// start point
...
// target point
...
relativeBendpoints.setPoints(newlist);
}
// refresh
graphicalEditPart.refresh();
}
}
}
|
|
|
Re: Problem with custom layout provider [message #1743093 is a reply to message #1743091] |
Mon, 12 September 2016 04:08   |
Eclipse User |
|
|
|
Hi.
In your implementation of "Command layoutEditParts(List selectedObjects, IAdaptable layoutHints)", I see that you execute the command yourself (by calling command.execute()), while you should only *build* the Command and return it to the framework, which will execute it at the appropriate time. I see the same pattern in getLayoutNodeProvider(), which is supposed to only return a layout provider, that will be invoked later; it should not execute the layout commands (which is triggered by the call to container.performRequest(layoutRequest)) in getLayoutNodeProvider() itself.
The Javadoc in GMF's AbstractLayoutEditPartProvider.layoutEditParts(GraphicalEditPart, IAdaptable) is a little confusing, as it says "Layout the objects in this container using the specified layout type.", but basically whenever a method in GMF returns a Command, it should only build/configure and return the Command object, and the framework will take care of invoking it (maybe with others) at a later time.
Regards,
Pierre-Charles
--
Need training or professional services for Sirius?
http://www.obeodesigner.com/sirius
|
|
| | |
Re: Problem with custom layout provider [message #1743307 is a reply to message #1743302] |
Wed, 14 September 2016 05:04   |
Eclipse User |
|
|
|
Quote:
I need to move the nodes that are too near each other and then connect those nodes.
I'm not sure I get this part. A layout provider can not create new connections, it can only move (or resize) things around, create/remove/move bendpoints etc.
Quote:
I need to ensure that the first nodes sequentially moved, and only then interconnected. It happens to me, however, that the move and interconnection is performed at the same time and that was often not guarantee correctly connected, because the individual does not fit RelativeBendpoint.
Note sure this is the cause of your issue, but if you write your layout algorithm as multiple successive steps/commands, you need to take into account the fact that except for the very first command in the sequence, the commands you create will see a different, already modified, state of the model. For example if you start with state S0, and create commands C1, C2:
* C1 will be executed on S0, producing a state S1;
* C2 will be executed the, on S1, producing a state S2;
So by the time you are *creating* C2, you must be aware that the state you see (S0 at that time) is not the one it will see when executed. You must create C2 in a way that compensate that when it will execute, C1 will already have happened.
|
|
| | | | |
Goto Forum:
Current Time: Wed Jul 23 08:41:51 EDT 2025
Powered by FUDForum. Page generated in 0.06520 seconds
|