Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to connect two default nodes programmatically #37

Open
danielemaddaluno opened this issue Oct 6, 2020 · 2 comments
Open

How to connect two default nodes programmatically #37

danielemaddaluno opened this issue Oct 6, 2020 · 2 comments

Comments

@danielemaddaluno
Copy link

I didn't manage to connect two simple nodes together programmatically.
In the demo it is done with the tree skin, but what if I just want to do it with the default skin?
I would add this to the wiki documentation too.

@danielemaddaluno
Copy link
Author

This is what I'm trying to do:

import java.util.Arrays;

import de.tesis.dynaware.grapheditor.Commands;
import de.tesis.dynaware.grapheditor.GraphEditor;
import de.tesis.dynaware.grapheditor.core.DefaultGraphEditor;
import de.tesis.dynaware.grapheditor.core.connections.ConnectionCommands;
import de.tesis.dynaware.grapheditor.model.GConnector;
import de.tesis.dynaware.grapheditor.model.GModel;
import de.tesis.dynaware.grapheditor.model.GNode;
import de.tesis.dynaware.grapheditor.model.GraphFactory;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

@SuppressWarnings("restriction")
public class GraphEditorTutorial extends Application {

	GraphEditor graphEditor;

	public static void main(final String[] args) {
		launch(args);
	}

	@Override
	public void start(final Stage primaryStage) throws Exception {

		graphEditor = new DefaultGraphEditor();

		Scene scene = new Scene(graphEditor.getView(), 800, 600);

		GModel model = GraphFactory.eINSTANCE.createGModel();
		graphEditor.setModel(model);
		addNodes(model);

		primaryStage.setScene(scene);
		primaryStage.show();

	}

	private GNode createNode() {
		GNode node = GraphFactory.eINSTANCE.createGNode();

		GConnector input = GraphFactory.eINSTANCE.createGConnector();
		GConnector output = GraphFactory.eINSTANCE.createGConnector();

		input.setType("left-input");
		output.setType("right-output");

		node.getConnectors().add(input);
		node.getConnectors().add(output);

		return node;
	}

	private void addNodes(GModel model) {
		GNode n1 = createNode();
		GNode n2 = createNode();

		n1.setX(150);
		n1.setY(150);

		n2.setX(400);
		n2.setY(200);
		n2.setWidth(200);
		n2.setHeight(150);

		Commands.addNode(model, n1);
		Commands.addNode(model, n2);

		
		GConnector source = n1.getConnectors().get(1);
		GConnector target = n2.getConnectors().get(0);
		
		// ERROR
		ConnectionCommands.addConnection(model, source, target, null, Arrays.asList());
		
		// WORKS:
		//new TreeSkinController(graphEditor, null);
		//ConnectionCommands.addConnection(model, source, target, "tree-connection", Arrays.asList());
	}

}

And this is the error that I get:

org.eclipse.emf.common.util.WrappedException: An exception was ignored during command execution
	at org.eclipse.emf.common.command.BasicCommandStack.handleError(BasicCommandStack.java:281)
	at org.eclipse.emf.common.command.BasicCommandStack.execute(BasicCommandStack.java:112)
	at de.tesis.dynaware.grapheditor.core.connections.ConnectionCommands.addConnection(ConnectionCommands.java:80)
	at com.graph.tests.demo.tests.GraphEditorTutorial.addNodes(GraphEditorTutorial.java:77)
	at com.graph.tests.demo.tests.GraphEditorTutorial.start(GraphEditorTutorial.java:35)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
	at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
	at java.util.ArrayList.rangeCheck(ArrayList.java:657)
	at java.util.ArrayList.get(ArrayList.java:433)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.restrictFirstAndLastJoints(SimpleConnectionSkin.java:198)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.addRectangularConstraints(SimpleConnectionSkin.java:186)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.setJointSkins(SimpleConnectionSkin.java:112)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.DefaultConnectionSkin.setJointSkins(DefaultConnectionSkin.java:70)
	at de.tesis.dynaware.grapheditor.core.skins.SkinManager.addJoints(SkinManager.java:358)
	at de.tesis.dynaware.grapheditor.core.skins.SkinManager.addConnections(SkinManager.java:204)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.updateSkinManager(GraphEditorController.java:254)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.reloadView(GraphEditorController.java:196)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.initializeAll(GraphEditorController.java:155)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.lambda$createCommandStackListener$41(GraphEditorController.java:183)
	at org.eclipse.emf.common.command.BasicCommandStack.notifyListeners(BasicCommandStack.java:270)
	at org.eclipse.emf.common.command.BasicCommandStack.execute(BasicCommandStack.java:104)
	... 9 more
Exception in Application start method
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
	at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
	at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
	at java.util.ArrayList.rangeCheck(ArrayList.java:657)
	at java.util.ArrayList.get(ArrayList.java:433)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.restrictFirstAndLastJoints(SimpleConnectionSkin.java:198)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.addRectangularConstraints(SimpleConnectionSkin.java:186)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.connection.SimpleConnectionSkin.setJointSkins(SimpleConnectionSkin.java:112)
	at de.tesis.dynaware.grapheditor.core.skins.defaults.DefaultConnectionSkin.setJointSkins(DefaultConnectionSkin.java:70)
	at de.tesis.dynaware.grapheditor.core.skins.SkinManager.addJoints(SkinManager.java:252)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.updateSkinManager(GraphEditorController.java:262)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.reloadView(GraphEditorController.java:196)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.initializeAll(GraphEditorController.java:155)
	at de.tesis.dynaware.grapheditor.core.GraphEditorController.lambda$createCommandStackListener$41(GraphEditorController.java:183)
	at org.eclipse.emf.common.command.BasicCommandStack.notifyListeners(BasicCommandStack.java:270)
	at org.eclipse.emf.common.command.BasicCommandStack.execute(BasicCommandStack.java:115)
	at de.tesis.dynaware.grapheditor.core.connections.ConnectionCommands.addConnection(ConnectionCommands.java:80)
	at com.graph.tests.demo.tests.GraphEditorTutorial.addNodes(GraphEditorTutorial.java:77)
	at com.graph.tests.demo.tests.GraphEditorTutorial.start(GraphEditorTutorial.java:35)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
	at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Exception running application com.graph.tests.demo.tests.GraphEditorTutorial

@nadrian4
Copy link

nadrian4 commented Dec 26, 2020

Hi,

if you are still facing this issue, I think i've got a solution. While dragging from one connector to another to create connection, the TailManager::snapPosition method is called, which calls GTailSkin::draw method. In DefaultTailSkin, this method adds some points (joitns) to the connection.

When you release your mouse while hovering over target connector, the releaseHandler for Connector is called, which, if the connection is valid, calls private ConnectorDragManager::addConnection method. It looks like this:

    private void addConnection(final GConnector source, final GConnector target) {

        final String connectionType = validator.createConnectionType(source, target);
        final String jointType = validator.createJointType(source, target);
        final List<Point2D> jointPositions = skinLookup.lookupTail(source).allocateJointPositions();

        final List<GJoint> joints = new ArrayList<>();

        for (final Point2D position : jointPositions) {

            final GJoint joint = GraphFactory.eINSTANCE.createGJoint();
            joint.setX(position.getX());
            joint.setY(position.getY());
            joint.setType(jointType);

            joints.add(joint);
        }

        final CompoundCommand command = ConnectionCommands.addConnection(model, source, target, connectionType, joints);

        // Notify the event manager so additional commands may be appended to this compound command.
        final GConnection addedConnection = model.getConnections().get(model.getConnections().size() - 1);
        connectionEventManager.notifyConnectionAdded(addedConnection, command);
    }

As you can see, this method collects joints and passes it as an argument to ConnectionCommands::addConnection. Your main problem was that you did not create any joints hence the method resulted in throwing IndexOutOfBoundsException.

So, if you want to add a connection programatically, you should call first:

graphEditor.getSkinLookup().lookupTail(source).draw(
                new Point2D(source.getX(), source.getX()),
                new Point2D(target.getX(), source.getY()),
                target,
                true
        );

and then:

final List<Point2D> jointPositions = graphEditor.getSkinLookup().lookupTail(source).allocateJointPositions();
final List<GJoint> joints = new ArrayList<>();
for (final Point2D position : jointPositions) {
	final GJoint joint = GraphFactory.eINSTANCE.createGJoint();
    joint.setX(position.getX());
    joint.setY(position.getY());
    joint.setType(null);
    joints.add(joint);
}
ConnectionCommands.addConnection(model, source, target, null, joints);

Which should result in adding the connection in the way you expected.

The connection path does not look perfectly, but you could try to deal with joints coordinates - i suppose it should help.

Hope you find it helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants