Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Sirius » Problem with custom layout provider
Problem with custom layout provider [message #1743091] Mon, 12 September 2016 07:07 Go to next message
Martin Jedlicka is currently offline Martin JedlickaFriend
Messages: 121
Registered: January 2016
Senior Member
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 08:08 Go to previous messageGo to next message
Pierre-Charles David is currently offline Pierre-Charles DavidFriend
Messages: 491
Registered: July 2009
Senior Member
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


Pierre-Charles David - Obeo

Need training or professional services for Sirius?
http://www.obeodesigner.com/sirius
Re: Problem with custom layout provider [message #1743105 is a reply to message #1743093] Mon, 12 September 2016 10:23 Go to previous messageGo to next message
Martin Jedlicka is currently offline Martin JedlickaFriend
Messages: 121
Registered: January 2016
Senior Member
Hi.

Thanks for the reply. I understand it and I edited so that there was not a call.
However, still it remains my problem.

In the first command I want to move a node to have between them the same distance and the second command is I want to connect using the edges. It happens to me, however, that the shift of the node and connection is executed at the same time (thus not correctly create edges and it is necessary to call the command to create connection again). I need to first move the nodes and then to create a connection through via the edges.

Martin
Re: Problem with custom layout provider [message #1743302 is a reply to message #1743105] Wed, 14 September 2016 08:44 Go to previous messageGo to next message
Martin Jedlicka is currently offline Martin JedlickaFriend
Messages: 121
Registered: January 2016
Senior Member
Hi Pierre.

Please. See the previous message.

I need to move the nodes that are too near each other and then connect those nodes.
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.

You do not know how this will ensure?

Thanks.

Martin
Re: Problem with custom layout provider [message #1743307 is a reply to message #1743302] Wed, 14 September 2016 09:04 Go to previous messageGo to next message
Pierre-Charles David is currently offline Pierre-Charles DavidFriend
Messages: 491
Registered: July 2009
Senior Member
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.


Pierre-Charles David - Obeo

Need training or professional services for Sirius?
http://www.obeodesigner.com/sirius
Re: Problem with custom layout provider [message #1743412 is a reply to message #1743307] Thu, 15 September 2016 08:06 Go to previous messageGo to next message
Martin Jedlicka is currently offline Martin JedlickaFriend
Messages: 121
Registered: January 2016
Senior Member
Hi Pierre.

1. Yes you are right. I do not create connections, but only changes the edge by changing bendpoints.
2. I do not know if my problem properly describe.
- My point is that the need to ensure a minimum distance between nodes (protective zone), so if some nodes are close together and move so that they have between them given distance. On the first command I called ProtectionZoneCommand.
- Only when they are moved nodes, so I need to run the command RoutingInputOutputCommand that for every edge adjusts individual bendpoints so that answered my algorithm (the inputs edge on the left side of nodes and outputs edges are on the right side of nodes).

When you then click Arrange All and call my CustomLayoutProvider and is seen in the graphic editor (and in Debug mode) that move nodes and changes bendpoints run in parallel, which I do not want. Because when you change the position of the node, and then changes the individual bendpoints and does not fit me. Therefore, I need first to ensure moved nodes and only then started to change individual bendpoints.

Everything shown in the code above.

Thanks,

Martin
Re: Problem with custom layout provider [message #1743505 is a reply to message #1743412] Fri, 16 September 2016 06:09 Go to previous messageGo to next message
Martin Jedlicka is currently offline Martin JedlickaFriend
Messages: 121
Registered: January 2016
Senior Member
Hi Pierre.

Any idea how to solve my problem (see previous message)? Actually, you need to execute two commands. 1. Preparing for change bendpoints (move nodes). 2. And when they moved nodes and execute changes bendpoints. Custom trigger 'Arrange All'?
Some example code?

Thank you so much.

Martin

[Updated on: Fri, 16 September 2016 06:15]

Report message to a moderator

Re: Problem with custom layout provider [message #1743535 is a reply to message #1743505] Fri, 16 September 2016 09:15 Go to previous messageGo to next message
Pierre-Charles David is currently offline Pierre-Charles DavidFriend
Messages: 491
Registered: July 2009
Senior Member
Hi.

The organisation of your code in successive commands have no direct relation with the layout animations.

The model changes performed by the command are one thing, the visual presentation of the changes is another. However you structure your commands, they will always be executed as one single operation on the underlying EMF/GMF/Sirius models. Only then are the Draw2D figures updated according to the final state (and thus layout). See the javadoc of the Animation class you use in your example:

* A utility for coordinating figure animations. During animation, multiple
* <i>animators</i> are employed to capture the <em>initial</em> and
* <em>final</em> states for one or more figures. The animators then playback
* the animation by interpolating the intermediate states for each figure using
* the initial and final "keyframes".

Whatever intermediate state your models passed through during the execution of the Command are completely invisible to the graphical layer (Draw2D). The only thing it sees are the original state (position, size etc.) of the figures, and the updated state according to the final model state (the initial and final keyframes). Animator then does simple interpolation between those (see org.eclipse.draw2d.LayoutAnimator.playback(IFigure) for example).

If you need a different kind of animation, the changes you need to make are not at the Command level, but at the Drawd2D Animation/Animator level. This has nothing to do with Sirius itself and you will have a better chance of an answer in the GEF forum.

Regards,
Pierre-Charles

--
Need training or professional services for Sirius?
http://www.obeodesigner.com/sirius


Pierre-Charles David - Obeo

Need training or professional services for Sirius?
http://www.obeodesigner.com/sirius
Re: Problem with custom layout provider [message #1800962 is a reply to message #1743535] Thu, 10 January 2019 11:53 Go to previous message
Rakesh Nidavani is currently offline Rakesh NidavaniFriend
Messages: 21
Registered: March 2018
Junior Member
Hello Martin,

I am facing similar issue.

Did you get any solution for this ?

Regards,
Rakesh
Previous Topic:Drop in Diagram from custom source
Next Topic:How to convert sirius projects to eclipse RCP project ?
Goto Forum:
  


Current Time: Thu Oct 24 04:37:02 GMT 2019

Powered by FUDForum. Page generated in 0.02266 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top