Building a GEF-based Eclipse editor - part 3
Par Julien, jeudi 1 septembre 2005 à 08:38 :: Eclipse :: #170 :: rss
Continuing on the GEF series, let's tackle the EditParts.
First of all, sorry for the delay since the last GEF-related entry, but I had (and still have ...) a lot of work to do 
EditParts play a very essential role in the GEF architecture. We previously saw how to create the view elements and you are supposed to already have your model. EditParts are simply the controllers that will make the link between the model and the view. More precisely, each view element will be mapped to an EditPart. In turn, each EditPart is related to the model. In simple cases, you can just map one EditPart to one instance of your model. However in most situations, one view element will hold for several classes instances in your model. Indeed, you don't necessarly want to expose each element of your model as a visual component. For instance if you had a Person class which owns a list of children, you may want to expose the list of children inside the Person instance view. This kind of flexibility is essential. EditParts have to be organized as trees. If you don't see how your model maps to a tree, then you will have to think about it
Most of the time you have some kind of top-level class which is the root of your model. This will be mapped to a top-level EditPart whose view is the GEF editor container. The following picture gives an outline:

AbstractGraphicalEditPart should be subclassed to add EditParts that should be displayed in GEF. EditParts are expected to listen to the model changes. Doing so is easy if your model classes have events support via java.beans.PropertyChangeSupport. Connecting / disconnecting to the model is done the following way:
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.EditPart#activate()
*/
public void activate()
{
if (!isActive())
{
super.activate();
getCastedModel().addPropertyChangeListener(this);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.EditPart#deactivate()
*/
public void deactivate()
{
if (isActive())
{
super.deactivate();
getCastedModel().removePropertyChangeListener(this);
}
}
The getCastedModel() method is a convenient method that I add to convert the result of EditPart.getModel() to the actual class. EditParts should provide a list of children elements in the model if they have some. Proper EditParts are then instanciated. Here is an example:
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren()
*/
protected List getModelChildren()
{
List list = Collections.list(Collections.enumeration(getCastedModel().getStates()));
return list;
}
An EditPart should also provide a figure, for instance:
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#createFigure()
*/
protected IFigure createFigure()
{
StateImpl state = getCastedModel();
figure = new StateFigure(state.getName(), state.isInitialState(), state.isFinalState());
return figure;
}
EditParts are instanciated from the model. To do that, we need a factory like this one:
public class BusinessProtocolEditPartFactory implements EditPartFactory
{
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.EditPartFactory#createEditPart(org.eclipse.gef.EditPart,
* java.lang.Object)
*/
public EditPart createEditPart(EditPart context, Object model)
{
EditPart part;
if (model instanceof BusinessProtocol)
{
part = new BusinessProtocolEditPart();
}
else if (model instanceof State)
{
part = new StateEditPart();
}
else if (model instanceof Operation)
{
part = new OperationEditPart();
}
else
{
return null;
}
part.setModel(model);
return part;
}
}
The editor must know about this factory since when it will be provided with the model instance, it will ask for an EditPart of the top-level instance that will be given:
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.ui.parts.GraphicalEditor#configureGraphicalViewer()
*/
protected void configureGraphicalViewer()
{
super.configureGraphicalViewer();
GraphicalViewer viewer = getGraphicalViewer();
viewer.setEditPartFactory(new BusinessProtocolEditPartFactory());
(...)
In the editor that I have implemented, I had to display states. They will be nodes in the view, so their EditParts have to implement the NodeEditPart interface and provide visual anchors as well as the linking relations in the model:
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
*/
public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection)
{
return figure.getAnchor();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.ConnectionEditPart)
*/
public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection)
{
return figure.getAnchor();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.NodeEditPart#getSourceConnectionAnchor(org.eclipse.gef.Request)
*/
public ConnectionAnchor getSourceConnectionAnchor(Request request)
{
return figure.getAnchor();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.NodeEditPart#getTargetConnectionAnchor(org.eclipse.gef.Request)
*/
public ConnectionAnchor getTargetConnectionAnchor(Request request)
{
return figure.getAnchor();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelSourceConnections()
*/
protected List getModelSourceConnections()
{
return getCastedModel().getOutgoingOperations();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getModelTargetConnections()
*/
protected List getModelTargetConnections()
{
return getCastedModel().getIncomingOperations();
}
When you display relations between nodes (like here between states), you will need to provide an EditPart for the instances returned in getModelXXXConnections(). These EditParts will have to extend AbstractConnectionEditPart. Typically, their figures will be PolylineConnection subclasses or instances.
If you read carefuly the GEF documentation and this post, you should understand how to manage to get your editor display the figures, including nodes and relations between them. However you cannot move the figures ... this will be for next time 
Be sure to leave comments here, I might have forgotten a few things and there are parts were I can have been too fast on.


Commentaires
1. Le mercredi 7 septembre 2005 à 13:28, par Anatolii
2. Le jeudi 8 septembre 2005 à 04:29, par Julien
3. Le jeudi 8 septembre 2005 à 21:28, par Anatolii
4. Le vendredi 9 septembre 2005 à 01:48, par Julien
5. Le samedi 10 septembre 2005 à 09:26, par Anatolii
Ajouter un commentaire
Les commentaires pour ce billet sont fermés.