Creating a GEF Editor – Part 9: Connections

Previous Tutorial: Creating a GEF Editor – Part 8: Delete, Undo and Redo

Having a functional editor on which we can add figures is already pretty neat, but we are still missing one very important element in our editor: connections. Connections are generally used to describe some kind of relation between different entities in the diagram, and are shown as lines that connect two different figures. In this tutorial you will learn how to add basic GEF connections, and if it doesn’t get too long, we’ll also add to them some extra functionality. This is going to be fun! Enjoy.

  1. Knowing that we wanted to create connections in our editor, our model already contains an EClass that represents these connections, called OPMLink. An OPMLink simply points to a source and target OPMThing in the model (it also contains a list of bendpoints that we will use to draw our connection, but more on this later). So we don’t have to do anything to implement connections in our model. Whoppi!
  2. Now we’ll add to the editor a new EditPart called OPMLinkEditPart. An EditPart that is used as a connection implements the ConnectionEditPartinterface (either directly or by subclassing the AbstractConnectionEditPart class as we do), which requires the class to provide functionality to get/set source and target EditPart instances. Our first connection implementation is going to be very simple, having only a line that connects between to two diagram entities:
    package com.vainolo.phd.opm.gef.editor.part;
    
    import org.eclipse.draw2d.IFigure;
    import org.eclipse.draw2d.PolylineConnection;
    import org.eclipse.gef.EditPolicy;
    import org.eclipse.gef.editparts.AbstractConnectionEditPart;
    import org.eclipse.gef.editpolicies.ConnectionEndpointEditPolicy;
    
    public class OPMLinkEditPart extends AbstractConnectionEditPart {
    
    	public OPMLinkEditPart() {
    		super();
    	}
    	
    	@Override protected void createEditPolicies() {
    		installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE, new ConnectionEndpointEditPolicy());
    	}
    
    	@Override protected IFigure createFigure() {
    		PolylineConnection conn = new PolylineConnection();
    		return conn; 
    	}
    
    }
    
  3. Now we start all of the setup required for the connections. First we are going to add connection anchors to our OPMThing figures. Connection anchors define where the connection is connected to its endpoint (source or target EditPart). We use both ChopBoxAnchor and EllipseAnchor, which simply sets the anchor in the intersection point between the connection and the edge of the figure (this is better explained in pictures):
    • ChopBoxAnchor: will be used for OPMObject.
    • EllipseAnchor: will be used for OPMProcess.

    To add the anchors, we modify the OPMThingFigure interface adding it a getConnectionAnchor method:

    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.ConnectionAnchor;
    import org.eclipse.draw2d.IFigure;
    import org.eclipse.draw2d.Label;
    
    public interface OPMThingFigure extends IFigure {
    	public Label getNameLabel();
    	public ConnectionAnchor getConnectionAnchor();	
    }
    

    And we implement in both in the OPMObjectFigure and OPMProcessFigure:

    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.ChopboxAnchor;
    import org.eclipse.draw2d.ConnectionAnchor;
    import org.eclipse.draw2d.Figure;
    import org.eclipse.draw2d.Graphics;
    import org.eclipse.draw2d.Label;
    import org.eclipse.draw2d.RectangleFigure;
    import org.eclipse.draw2d.XYLayout;
    import org.eclipse.draw2d.geometry.Rectangle;
    
    public class OPMObjectFigure extends Figure implements OPMThingFigure {
    	private Label nameLabel;
    	private RectangleFigure rectangle;
    	private ConnectionAnchor connectionAnchor;
    	
    	public OPMObjectFigure() {
    		setLayoutManager(new XYLayout());
    		rectangle = new RectangleFigure();
    		add(rectangle);
    		nameLabel = new Label();
    		add(nameLabel);
    	}
    
    	@Override protected void paintFigure(Graphics graphics) {
    		Rectangle r = getBounds().getCopy();
    		setConstraint(rectangle, new Rectangle(0, 0, r.width, r.height));
    		setConstraint(nameLabel, new Rectangle(0, 0, r.width, r.height));
    		nameLabel.invalidate();		
    		rectangle.invalidate();
    	}
    	
    	public Label getNameLabel() {
    		return nameLabel;
    	}
    	
    	public ConnectionAnchor getConnectionAnchor() {
    		if (connectionAnchor == null) {
    			connectionAnchor = new ChopboxAnchor(this);
    		}
    		return connectionAnchor;
    	}
    }
    
    package com.vainolo.phd.opm.gef.editor.figure;
    
    import org.eclipse.draw2d.ConnectionAnchor;
    import org.eclipse.draw2d.Ellipse;
    import org.eclipse.draw2d.EllipseAnchor;
    import org.eclipse.draw2d.Figure;
    import org.eclipse.draw2d.Graphics;
    import org.eclipse.draw2d.Label;
    import org.eclipse.draw2d.XYLayout;
    import org.eclipse.draw2d.geometry.Rectangle;
    
    public class OPMProcessFigure extends Figure implements OPMThingFigure {
    	private Label nameLabel;
    	private Ellipse ellipse;
    	private ConnectionAnchor connectionAnchor;	
    	
    	public OPMProcessFigure() {
    		setLayoutManager(new XYLayout());
    		ellipse = new Ellipse();
    		add(ellipse);
    		nameLabel = new Label();
    		add(nameLabel);
    	}
    
    	@Override protected void paintFigure(Graphics graphics) {
    		Rectangle r = getBounds().getCopy();
    		setConstraint(ellipse, new Rectangle(0, 0, r.width, r.height));
    		setConstraint(nameLabel, new Rectangle(0, 0, r.width, r.height));
    		ellipse.invalidate();
    		nameLabel.invalidate();
    	}
    	
    	public Label getNameLabel() {
    		return nameLabel;
    	}
    	
    	public ConnectionAnchor getConnectionAnchor() {
    		if (connectionAnchor == null) {
    			connectionAnchor = new EllipseAnchor(this);
    		}
    		return connectionAnchor;
    	}		
    }
    
  4. The connection anchors we just created are used by the OPMThingEditPart when adding new connections to the diagram. I should show you this code now, but the thing is that I like to display full files (no “…” in the middle) and also to do things so that the code compiles at all times. So please bear with me for a moment. Since we will be adding new connections in the diagram, and diagram operations are done using a Command and an EditPolicy, we have to implement one of each. Implementing the Command is fairly simple:
    package com.vainolo.phd.opm.gef.editor.command;
    
    import org.eclipse.gef.commands.Command;
    
    import com.vainolo.phd.opm.model.OPMLink;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public class OPMLinkCreateCommand extends Command {
    	
    	private OPMThing source;
    	private OPMThing target;
    	private OPMLink link;
    	private OPMObjectProcessDiagram opd;
    
    	@Override 
    	public boolean canExecute() {
    		return source != null && target != null && link != null;
    	}
    	
    	@Override public void execute() {
    		link.setSource(source);
    		link.setTarget(target);
    		link.setOpd(opd);
    	}
    
    	@Override public void undo() {
    		link.getSource().getOutgoingLinks().remove(link);
    		link.setSource(null);
    		link.getTarget().getIncomingLinks().remove(link);
    		link.setTarget(null);
    		link.setOpd(null);
    	}
    
    	public void setTarget(OPMThing target) {
    		this.target = target;
    	}
    	
    	public void setSource(OPMThing source) {
    		this.source = source;
    	}
    	
    	public void setLink(OPMLink link) {
    		this.link = link;
    	}
    	
    	public void setOPD(OPMObjectProcessDiagram opd) {
    		this.opd = opd;
    	}
    }
    

    The EditPolicy that creates this command is a subclass of GraphicalNodeEditPolicy, a policy used for creating and reconnecting connections. The Command is created when the user selects the source of the connection (by clicking on it after selecting a connection creation tool – which we will implement in a few more steps) and updated when the user select the target of the connection. In the middle of the process the Command cannot be executed because of the code we inserted in the canExecute method. I’m not sure if the framework tries to execute it right after the source is selected, but it seems that this can happen. It also seems possible to execute two different commands to create a link, one when the source is select and one when the target is selected, and I will investigate this in the future. But for now, this is the GraphicalNodeEditPolicy that we’ll use:

    package com.vainolo.phd.opm.gef.editor.policy;
    
    import org.eclipse.gef.commands.Command;
    import org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy;
    import org.eclipse.gef.requests.CreateConnectionRequest;
    import org.eclipse.gef.requests.ReconnectRequest;
    
    import com.vainolo.phd.opm.gef.editor.command.OPMLinkCreateCommand;
    import com.vainolo.phd.opm.model.OPMLink;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public class OPMThingGraphicalNodeEditPolicy extends GraphicalNodeEditPolicy {
    
    	@Override protected Command getConnectionCompleteCommand(CreateConnectionRequest request) {
    		OPMLinkCreateCommand result = (OPMLinkCreateCommand) request.getStartCommand();
    		result.setTarget((OPMThing)getHost().getModel());
    		return result;
    	}
    
    	@Override protected Command getConnectionCreateCommand(CreateConnectionRequest request) {
    		OPMLinkCreateCommand result = new OPMLinkCreateCommand();
    		result.setSource((OPMThing)getHost().getModel());
    		result.setLink((OPMLink) request.getNewObject());
    		result.setOPD(((OPMThing)getHost().getModel()).getOpd());
    		request.setStartCommand(result);
    		return result;
    	}
    
    	@Override protected Command getReconnectTargetCommand(ReconnectRequest request) {
    		return null;
    	}
    
    	@Override protected Command getReconnectSourceCommand(ReconnectRequest request) {
    		return null;
    	}
    }
    
  5. OK, we can now make all the changes to the OPMThingEditPart. First, we make it implement the NodeEditPart interface, which is used by other GEF classes (like AbstractConnectionEditPart) to better manage the connections in the diagram. This interface requires that the class provide ConnectionAnchor instances for the ConnectionEditPart instances which are connected to it, and also for connections that are currently being created (using Request instances). Second, we add the newly created OPMThingGraphicalNodeEditPolicy to the OPMThingEditPart. And last, we provide the GEF framework with a way to know which connections there are in the diagram by implementing the getModelSourceConnections and getModelTargetConnections methods, just like when we implemented the getModelChildren method in the OPMObjectProcessDiagramEditPart to make it know which model elements existed in our diagram. The GEF framework calls these methods and for each unique OPMLink instance that is found it creates a new OPMLinkEditPart and adds it to the diagram:
    package com.vainolo.phd.opm.gef.editor.part;
    
    import java.util.List;
    
    import org.eclipse.draw2d.ConnectionAnchor;
    import org.eclipse.draw2d.Label;
    import org.eclipse.emf.common.notify.Adapter;
    import org.eclipse.emf.common.notify.Notification;
    import org.eclipse.emf.common.notify.Notifier;
    import org.eclipse.gef.ConnectionEditPart;
    import org.eclipse.gef.EditPolicy;
    import org.eclipse.gef.NodeEditPart;
    import org.eclipse.gef.Request;
    import org.eclipse.gef.RequestConstants;
    import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
    import org.eclipse.jface.viewers.TextCellEditor;
    
    import com.vainolo.phd.opm.gef.editor.figure.OPMThingFigure;
    import com.vainolo.phd.opm.gef.editor.policy.OPMThingComponentEditPolicy;
    import com.vainolo.phd.opm.gef.editor.policy.OPMThingDirectEditPolicy;
    import com.vainolo.phd.opm.gef.editor.policy.OPMThingGraphicalNodeEditPolicy;
    import com.vainolo.phd.opm.model.OPMLink;
    import com.vainolo.phd.opm.model.OPMThing;
    
    public abstract class OPMThingEditPart extends AbstractGraphicalEditPart implements NodeEditPart {
    
    	private OPMThingAdapter adapter;
    	
    	public OPMThingEditPart() {
    		super();
    		adapter = new OPMThingAdapter();
    	}
    	
    	@Override protected void createEditPolicies() {
    		installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new OPMThingDirectEditPolicy());
    		installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new OPMThingGraphicalNodeEditPolicy());
    		installEditPolicy(EditPolicy.COMPONENT_ROLE, new OPMThingComponentEditPolicy());
    	}
    
    	@Override protected List<OPMLink> getModelSourceConnections() {
    		OPMThing model = (OPMThing)getModel();
    		return model.getOutgoingLinks();
    	}
    
    	@Override protected List<OPMLink> getModelTargetConnections() {
    		OPMThing model = (OPMThing)getModel();
    		return model.getIncomingLinks();
    	}
    
    	@Override protected void refreshVisuals() {
    		OPMThingFigure figure = (OPMThingFigure)getFigure();
    		OPMThing model = (OPMThing)getModel();
    		OPMObjectProcessDiagramEditPart parent = (OPMObjectProcessDiagramEditPart) getParent();
    		
    		figure.getNameLabel().setText(model.getName());
    		parent.setLayoutConstraint(this, figure, model.getConstraints());
    	}
    
    	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
    		return ((OPMThingFigure)getFigure()).getConnectionAnchor();
    	}
    
    	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
    		return ((OPMThingFigure)getFigure()).getConnectionAnchor();
    	}
    
    	@Override public ConnectionAnchor getSourceConnectionAnchor(Request request) {
    		return ((OPMThingFigure)getFigure()).getConnectionAnchor();
    	}
    
    	@Override public ConnectionAnchor getTargetConnectionAnchor(Request request) {
    		return ((OPMThingFigure)getFigure()).getConnectionAnchor();
    	}	
    	
    	@Override public void activate() {
    		if(!isActive()) {
    			((OPMThing)getModel()).eAdapters().add(adapter);
    		}
    		super.activate();
    	}
    
    	@Override public void deactivate() {
    		if(isActive()) {
    			((OPMThing)getModel()).eAdapters().remove(adapter);
    		}
    
    		super.deactivate();
    	}
    	
    	@Override public void performRequest(Request req) {
    		if(req.getType() == RequestConstants.REQ_DIRECT_EDIT) {
    			performDirectEditing();
    		}
    	}
    	
    	private void performDirectEditing() {
    		Label label = ((OPMThingFigure)getFigure()).getNameLabel();
    		OPMThingDirectEditManager manager = new OPMThingDirectEditManager(this, TextCellEditor.class, new OPMThingCellEditorLocator(label), label);
    		manager.show();
    	}	
    	
    	public class OPMThingAdapter implements Adapter {
    
    		// Adapter interface
    		@Override public void notifyChanged(Notification notification) {
    			refreshVisuals();
    			refreshSourceConnections();
    			refreshTargetConnections();
    		}
    
    		@Override public Notifier getTarget() {
    			return (OPMThing)getModel();
    		}
    
    		@Override public void setTarget(Notifier newTarget) {
    			// Do nothing.
    		}
    
    		@Override public boolean isAdapterForType(Object type) {
    			return type.equals(OPMThing.class);
    		}
    	}
    }
    
  6. To finish the job, we must implement a factory that creates OPMLink instances and add a tool to the OPMGraphicalEditorPalette to handle the creation of new connections. First comes the factory:
    package com.vainolo.phd.opm.gef.editor.factory;
    
    import org.eclipse.gef.requests.CreationFactory;
    
    import com.vainolo.phd.opm.model.OPMFactory;
    import com.vainolo.phd.opm.model.OPMLink;
    
    public class OPMLinkFactory implements CreationFactory {
    
    	@Override public Object getNewObject() {
    		return OPMFactory.eINSTANCE.createOPMLink();
    	}
    
    	@Override public Object getObjectType() {
    		return OPMLink.class;
    	}
    
    }
    

    And second comes the tool:

    package com.vainolo.phd.opm.gef.editor;
    
    import org.eclipse.gef.palette.ConnectionCreationToolEntry;
    import org.eclipse.gef.palette.CreationToolEntry;
    import org.eclipse.gef.palette.PaletteGroup;
    import org.eclipse.gef.palette.PaletteRoot;
    import org.eclipse.gef.palette.SelectionToolEntry;
    
    import com.vainolo.phd.opm.gef.editor.factory.OPMLinkFactory;
    import com.vainolo.phd.opm.gef.editor.factory.OPMObjectFactory;
    import com.vainolo.phd.opm.gef.editor.factory.OPMProcessFactory;
    import com.vainolo.phd.opm.gef.editor.tool.CreationAndDirectEditTool;
    
    public class OPMGraphicalEditorPalette extends PaletteRoot {
    
    	PaletteGroup group;
    	
    	public OPMGraphicalEditorPalette() {
    		addGroup();
    		addSelectionTool();
    		addOPMObjectTool();
    		addOPMProcessTool();
    		addOPMLinkTool();
    	}
    	
    	private void addSelectionTool() {
    		SelectionToolEntry entry = new SelectionToolEntry();
    		group.add(entry);
    		setDefaultEntry(entry);
    	}
    	
    	private void addGroup() {
    		group = new PaletteGroup("OPM Controls");
    		add(group);
    	}
    	
    	private void addOPMObjectTool() {
    		CreationToolEntry entry = new CreationToolEntry("OPMObject", "Create a new Object", new OPMObjectFactory(), null, null);
    		entry.setToolClass(CreationAndDirectEditTool.class);		
    		group.add(entry);
    	}
    	
    	private void addOPMProcessTool() {
    		CreationToolEntry entry = new CreationToolEntry("OPMProcess", "Create a new Process", new OPMProcessFactory(), null, null);
    		entry.setToolClass(CreationAndDirectEditTool.class);		
    		group.add(entry);
    	}
    	
    	
    	private void addOPMLinkTool() {
    		ConnectionCreationToolEntry entry = new ConnectionCreationToolEntry("Link", "Creates a new link", new OPMLinkFactory(), null, null);
    		group.add(entry);
    	}	
    }
    
  7. One last thing (and thanks to Ouri for the comment), we have to add the OPMLink model to the OPMEditPartFactory so the edit parts are created by the framework when needed
    package com.vainolo.phd.opm.gef.editor.part;
    	
    import com.vainolo.phd.opm.model.OPMLink;
    import com.vainolo.phd.opm.model.OPMObject;
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMProcess;
    import org.eclipse.gef.EditPart;
    import org.eclipse.gef.EditPartFactory;
    	
    public class OPMEditPartFactory implements EditPartFactory {
    
        @Override public EditPart createEditPart(EditPart context, Object model) {
            EditPart part = null;
    			
            if(model instanceof OPMObjectProcessDiagram) {
                part = new OPMObjectProcessDiagramEditPart();
            } else if(model instanceof OPMObject) {
                part = new OPMObjectEditPart();
            } else if(model instanceof OPMProcess) {
                part = new OPMProcessEditPart();
            } else if(model instanceof OPMLink) {
                part = new OPMLinkEditPart();
            }
    			
            if(part != null) {
                part.setModel(model);
            }
    
            return part;
        }
    }
    
  8. Fire up your editor and add one or two links to it. Looks good, doesn’t it? But don’t get too exited because we still haven’t implemented connection removal so every link you add will stay until we do this… hopefully soon. We must also fix the command that removes things because it must also remove the connections… but it’s late and I think we’ve had enough for today.

You can find the final project files here.

I really hope you enjoyed this tutorial. So long, and thanks for all the fish :-).

Next Tutorial: Creating a GEF Editor – Part 10: Deleting Connections and Fixing of Thing Delete Command

22 thoughts on “Creating a GEF Editor – Part 9: Connections

  1. I guess that when adding the OPMLinkEditPart, it should be added to the OPMEditPartFactory as well? I did not see it mentioned here, so I am not sure about it?

    • Yea. Guess I missed writing this in the post (although it is implemented in the code). Thanks for the comment!

  2. Hello Arieh,
    I am trying to put the CONNECTION_LAYER behind the PRIMARY_LAYER in your editor in order for connections not to go over figures. I am trying to achieve that by overriding ScalableRootEditPart as suggested by google findings. createPrintableLayers() is the overridden method and the order of layers is switched – first connection, then primary layer.
    I have set the overridden RootEditPart on OPMGraphicalEditor in configureGraphicalViewer.
    Unfortunately this does not seem to work. People who suggested this didn’t seem to have problems apart from setting figures to opaque.
    http://www.eclipse.org/forums/index.php?t=msg&S=c5a4cc6dbfd634c8a3ae2d6c6e944963&th=73558&goto=229956

    Do you see what is wrong with what I did? Maybe some prerequisites must be fulfilled – such as the order of children on the opd.

    Maybe you have some other idea how to manipulate z-order. I just want to put connections behind figures.

    Regards,
    Bojan

    • Hi Bojan.
      I changed my configureGraphicalViewer method as follows:

      	protected void configureGraphicalViewer() {
      		super.configureGraphicalViewer();
      		getGraphicalViewer().setEditPartFactory(new OPMEditPartFactory());
      		getActionRegistry().registerAction(new ToggleGridAction(getGraphicalViewer()));
      		getActionRegistry().registerAction(new ToggleSnapToGeometryAction(getGraphicalViewer()));
      		getGraphicalViewer().setContextMenu(
      				new OPMGraphicalEditorContextMenuProvider(getGraphicalViewer(), getActionRegistry()));
      		getGraphicalViewer().setRootEditPart(new ScalableRootEditPart() {
      			@Override
      			protected LayeredPane createPrintableLayers() {
      				LayeredPane pane = new LayeredPane();
      
      				Layer layer = new ConnectionLayer();
      				layer.setPreferredSize(new Dimension(5, 5));
      				pane.add(layer, CONNECTION_LAYER);
      
      				layer = new Layer();
      				layer.setLayoutManager(new StackLayout());
      				pane.add(layer, PRIMARY_LAYER);
      
      				return pane;
      			}
      		});
      	}
      

      And now the connections are below the figures and I can see the connections below my figures. But do you need to do this?

      • Interestingly enough I just came to write that I succeeded to implement what I need and I saw your response.

        First to answer your question. My editor layouts figures into columns. Elements within one column can be interconnected and for one particular type of connection anchors have to be positioned on the top and on the bottom side of the figure (basic rectangle). That leads to many connections crossing all the figures in the way. So the best thing to do is to go under the figure. We know which two figures are connected by connection decorations (e.g. ArrowLocator).

        To my problem (the solution is obvious, but I needed to have clear mind obviously): actually switching the order of primary and connection layer did the trick but I could not witness that because all the figures had setFill(false) (how did you confirm your code had put connections behind? did you change this setting as well?).
        With this change in place I could actually see connections beneath figures.
        One more thing left: we need to change the order of rectangle and label figures on the OPMObjectFigure in order for label to appear on top of rectangle which is now filled.

        So the GEF rendering rule holds true :) – the order of the children really dictates the z-order

        Thank you for your reply,
        Bojan

  3. I realize this post is a bit old but people (like me) are still reading it, so here’s my suggestion:

    You might want to add a line about modifying the OPMThingAdapter in step 5 for people that aren’t copying the source code for the entire class. Took me quite some time to figure out why the connections I drew didn’t show up. The method calls I missed were
    refreshSourceConnections();

    refreshTargetConnections();

    in notifyChanged(). Otherwise thanks for a great tutorial. :)

  4. Another great part of the tutorial, thanks Arieh!

    Got stuck on this though, because the (3rd party) model I use doesn’t follow the GEF structure where connections are a feature of the node. Instead, my connections are features of the graph. This is a discrepancy with the GEF structure, which led to my connections initially not being displayed on the editor when added. Why? Because the Adapter on my NodeEditPart didn’t register any changes (cos there weren’t any), and hence didn’t refresh the source & target connections. The solution was to refresh the two NodeEditParts programatically.

    I’ve written a wee blog post about this (http://wp.me/p2qdAI-1t). Just sharing in case anyone comes across the same problem.

    Thanks again, your tutorial is great!

  5. Hi GEF Expert, I would like to know, how to highlights rectangle in GEF?. I hope you can answer.Thanks in advance!

    • Highlighting a rectangle is a semantic operation, not something that is built-in in GEF. What you can do is override a SelectionEditPolicy, specificaly the showSelection and hideSelection methods in this class, and do your highlighting here. These functions will be called when you select (and deselect) the EditPart.

  6. Pingback: How to refresh model source/target connection “children” of GEF NodeEditParts | New Code on the Block

  7. This is a damn great tutorial, still I had a problem within the OPMLinkCreateCommand’s execute() method.

    Specifically, you set the source, target and opd instances for the OPMLink’s instance.

    I had to add also these two lines:
    source.getOutgoingLinks().add(link);
    target.getIncomingLinks().add(link);

    Obviously, setting the instances won’t add those to the List of incoming/outgoing edges of a given model.. maybe you overrode those methods to do so? Did I miss that part?

    I never used the code you attached to each part of the tutorial (I was just reading the code and then I tried to do everything by myself) so maybe I missed something in the previous parts.

    I know this is quite old now, but maybe you still remember something! :D

    Thank you!

  8. Hi what is the simplest way to create a connection? Is it necessary to implement mvc when I have the source and target nodes already in my method.
    Thanks

    • I you are using GEF you must use MVC. The connections are created by requesting connection source and target connections (using the edit part’s getModelSourceConnections() and getModelTargetConnections()). If you want to create links directly you can use draw2d but this is more difficult.

Leave a Reply