Skip to content

Tag: graph

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

Previous Tutorial: Creating a GEF Editor – Part 9: Connections

This tutorial continues the development of our OPM editor, adding a rarely useful functionality: deleting links (only used by dumb people like me who never get things right the first time :-)). Furthermore, we must fix the Command used to delete things, since it does not deal with links at all (try deleting a thing that has a connecting link). Let’s get to work.

  1. The code to delete an OPMLink is fairly similar to the code used to delete an OPMThing only that a ConnectionEditPart uses a EditPolicy.CONNECTION_ROLE and a ConnectionEditPolicy to handle delete requests, instead of the EditPolicy.COMPONENT_ROLE and ComponentEditPolicy used by the OPMThingEditPart (Reading the code again just now, the javadoc of COMPONENT_ROLE states that this role can be used for any component of the graph, so maybe this would also work for a link. Added a TODO mark in the code to check this later). As usual, we’ll first code the Command, then the EditPolicy and finally change the EditPart so that the code always compiles cleanly
  2. The command to delete a link is pretty simple, just store all the information needed to undo the Command and detach the link from source, target and owner OPD:
    package com.vainolo.phd.opm.gef.editor.command;
    
    import org.eclipse.gef.commands.Command;
    
    import com.vainolo.phd.opm.model.OPMObjectProcessDiagram;
    import com.vainolo.phd.opm.model.OPMLink;
    import com.vainolo.phd.opm.model.OPMThing;
    
    /**
     * Command used to delete a link.
     * @author vainolo
     */
    public class OPMLinkDeleteCommand extends Command {
        /** Link to be deleted. */
        private OPMLink link;
        /** OPD that owns the link. */
        private OPMObjectProcessDiagram opd;
        /** Source of the link. */
        private OPMThing source;
        /** Target of the link. */
        private OPMThing target;
    
        /**
         * {@inheritDoc}
         */
        @Override public boolean canExecute() {
            return link != null;
        }
    
        /**
         * Disconnect link from source and target things and remove
         * from owner OPD.
         */
        @Override public void execute() {
            opd = link.getOpd();
            source = link.getSource();
            target = link.getTarget();
    
            link.setSource(null);
            link.setTarget(null);
            link.setOpd(null);
        }
    
        /**
         * Reconnect the link to the source and target and add
         * it to the owner OPD.
         */
        @Override public void undo() {
            link.setSource(source);
            link.setTarget(target);
            link.setOpd(opd);
        }
    
        /**
         * Set the link that will be delete from the diagram.
         * @param linkParam the link to delete from the diagram.
         */
        public void setLink(final OPMLink linkParam) {
            link = linkParam;
        }
    }
    
  3. The ConnectionEditPolicy is also very straightforward, creating and initializing the Command:
    package com.vainolo.phd.opm.gef.editor.policy;
    
    import org.eclipse.gef.editpolicies.ConnectionEditPolicy;
    import org.eclipse.gef.requests.GroupRequest;
    
    import com.vainolo.phd.opm.gef.editor.command.OPMLinkDeleteCommand;
    import com.vainolo.phd.opm.model.OPMLink;
    
    /**
     * Edit policy used by the OPMLink class to server delete requests.
     * @author vainolo
     *
     */
    public class OPMLinkConnectionEditPolicy extends ConnectionEditPolicy {
    
    	/**
    	 * Create a {@link OPMLinkDeleteCommand} and fill its details.
    	 * @param request the request that requires treatment.
    	 * @return a {@link OPMLinkDeleteCommand} that deletes a link from the model.
    	 */
    	@Override protected OPMLinkDeleteCommand getDeleteCommand(GroupRequest request) {
    		OPMLinkDeleteCommand command = new OPMLinkDeleteCommand();
    		command.setLink((OPMLink) getHost().getModel());
    		return command;
    	}
    }
    
  4. And to close things up, we install the new EditPolicy in the OPMLinkEditPart:
    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;
    
    import com.vainolo.phd.opm.gef.editor.policy.OPMLinkConnectionEditPolicy;
    
    /**
     * {@link EditPart} for the {@link OPMLink} model element.
     * @author vainolo
     */
    public class OPMLinkEditPart extends AbstractConnectionEditPart {
    
    	/**
    	 * Create and initialize a new {@link OPMLinkEditPart}.
    	 */
    	public OPMLinkEditPart() {
    		super();
    	}
    	
    	/**
    	 * Installs two edit policies:
    	 * <ol>
    	 *   <li>For the {@link EditPolicy#CONNECTION_ENDPOINTS_ROLE} a {@link ConnectionEndpoinEditPolicy}.</li>
    	 *   <li>For the {@link EditPolicy#CONNECTION_ROLE} a {@link OPMLinkConnectionEditPolicy}</li>
    	 */
    	@Override protected void createEditPolicies() {
    		installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE, new ConnectionEndpointEditPolicy());
    		installEditPolicy(EditPolicy.CONNECTION_ROLE, new OPMLinkConnectionEditPolicy());		
    	}
    
    	@Override protected IFigure createFigure() {
    		PolylineConnection conn = new PolylineConnection();
    		return conn; 
    	}
    }
    
  5. That was all that we needed to delete the link from the diagram. Go ahead and check your results, there is nothing more pleasurable than this.
  6. Now we have to fix the Command that we used to delete OPMThing instances, so that it also removes the incoming and outgoing links from the graph. This would be very very simple if we were not interested in an undoable command, but we are interested, therefore it gets a bit more complicated. What we have to do is store all of the links that we deleted in the Command, also storing their source and target OPMThing. The undo method of the Command restores these connections to their original state (Note also that since the OPMLink is contained in the OPMObjectProcessDiagram we must also detach it on execute and reattach it on undo).
    package com.vainolo.phd.opm.gef.editor.command;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    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;
    
    /**
     * Command used to delete a thing.
     * The functionality of this class fairly closed so it is declared final. 
     * @author vainolo
     *
     */
    public final class OPMThingDeleteCommand extends Command {
    	
        /** Thing to be deleted. */
    	private OPMThing thing;
    	/** OPD that owns the thing. */
    	private OPMObjectProcessDiagram opd;
    	/** Incoming and outgoing links. */
    	private List<OPMLink> links;
    	/** Sources for the links that start or end at this thing. */
    	private Map<OPMLink, OPMThing> linkSources;
    	/** Targets for the links that start or end at this thing. */ 
    	private Map<OPMLink, OPMThing> linkTargets;
    
    	@Override
    	public void execute() {
    		detachLinks();
    		thing.setOpd(null);
    	}
    
    	@Override
    	public void undo() {
    		reattachLinks();
    		thing.setOpd(opd);
    	}
    
    	/**
    	 * Detach all links from the thing and from the other
    	 * connecting thing, storing the connection information in local
    	 * data structures.
    	 */
    	private void detachLinks() {
    		links = new ArrayList<OPMLink>();
    		linkSources = new HashMap<OPMLink, OPMThing>();
    		linkTargets = new HashMap<OPMLink, OPMThing>();
    		links.addAll(thing.getIncomingLinks());
    		links.addAll(thing.getOutgoingLinks());
    		for (OPMLink link : links) {
    			linkSources.put(link, link.getSource());
    			linkTargets.put(link, link.getTarget());
    			link.setSource(null);
    			link.setTarget(null);
    			link.setOpd(null);
    		}
    	}
    
    	/**
    	 * Reattach all links to their source and target things.
    	 */
    	private void reattachLinks() {
    		for (OPMLink link : links) {
    			link.setSource(linkSources.get(link));
    			link.setTarget(linkTargets.get(link));
    			link.setOpd(opd);
    		}
    	}
    	
    	/**
    	 * Set the thing to delete from the diagram.
    	 * @param thing the Thing to delete from the diagram.
    	 */
    	public void setThing(OPMThing thing) {
    		this.thing = thing;
    		this.opd = thing.getOpd();
    	}
    }
    
  7. That should close all things. You now have a fully operational GEF editor!

You can find the final project files here.

GEF rocks!!!

Next Tutorial: Creating a GEF Editor – Part 11: Creating Link Bendpoints