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.
- The code to delete an
OPMLink
is fairly similar to the code used to delete anOPMThing
only that aConnectionEditPart
uses aEditPolicy.CONNECTION_ROLE
and aConnectionEditPolicy
to handle delete requests, instead of theEditPolicy.COMPONENT_ROLE
andComponentEditPolicy
used by theOPMThingEditPart
(Reading the code again just now, the javadoc ofCOMPONENT_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 theCommand
, then theEditPolicy
and finally change theEditPart
so that the code always compiles cleanly - 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; } }
- The
ConnectionEditPolicy
is also very straightforward, creating and initializing theCommand
: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; } }
- And to close things up, we install the new
EditPolicy
in theOPMLinkEditPart
: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; } }
- 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.
- Now we have to fix the
Command
that we used to deleteOPMThing
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 theCommand
, also storing their source and targetOPMThing
. Theundo
method of theCommand
restores these connections to their original state (Note also that since theOPMLink
is contained in theOPMObjectProcessDiagram
we must also detach it onexecute
and reattach it onundo
).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(); } }
- 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