Dr. Stefan Winkler
freier Softwareentwickler und IT-Berater

So the year 2016 has already been upon us for three weeks, and one of my resolutions is to write more blog-posts. Let’s see how this turns out…

For one of my customers, I am currently developing a GEF/Draw2D-based editor. I chose GEF 3.x instead of GEF4 for the implementation mainly for two reasons:

  1. The target platform of my client as of now is Eclipse Luna and I am unsure if I would have been able to get GEF4 to work on Luna (there are other EMF features in the target platform used by different components, so I am not very flexible with respect to versions in the EMF field)
  2. Due to its maturity, there seems to be more documentation out there for GEF 3.x than there is for GEF4. For example, I have found the Kindle version of The Eclipse Graphical Editing Framework on Amazon. While this book does not contain the answer to all obstacles I came over, it contains a lot of answers and explanations, and I can recommend it as a good reference and tutorial.

In the next few blog posts, I will point out some of these obstacles which I were not able to find a solution right away, and I hope that by writing about them, and how I solved them, I will help others to find answers to similar issues faster.

So here goes–something simple to start off:

Untyped EditPart members

Obstacle:

Well—not really an "obstacle", but I found it quite annoying that org.eclipse.gef.editparts.AbstractGraphicalEditPart returns general types for getModel(), getFigure(), and getParent().

 I ended up with a lot of code like this:

  MyFigure fig = (MyFigure)getFigure();
  MyModel m = (MyModel)getModel();
  MyParentEditPart p = (MyParentEditPart)getParent();
<do something with fig, m, and p>

Solution:

So, I refactored my code and wrote a custom base class for my EditParts, which uses type parameters to specify the concrete types for the model, figure, and parent edit part types. Then I have overridden t he getXxx()-methods with their covariant specializations.

public abstract class EditPartBase<
           F extends Figure, 
           M extends Object, 
           P extends AbstractGraphicalEditPart
> extends AbstractGraphicalEditPart
{ ... }

This makes writing things like

((MyFigure)getFigure()).setModel((MyModel)getModel());

much more readable, because now I can write

getFigure().setModel(getModel());

and if you are using Xtend like me, you can even write

getFigure.model = model

Plus, this common base class is a good place for utility methods. For example, I need access to the ZoomManager in several edit parts, so I also added a getZoomManager() method.

More on Zooming in one of the next posts…

Here is the final EditPartBase class:

/**
 * Abstract base class for EditParts which narrows the types so the code of derived classes is easier to read
 * @param <F> The figure type created by this edit part
 * @param <M> The model type managed by this edit part
 * @param <P> The concrete type of this edit part's parent 
 */
public abstract class EditPartBase<F extends Figure, M extends Object, P extends AbstractGraphicalEditPart> extends AbstractGraphicalEditPart
{
  @Override
  @SuppressWarnings("unchecked")
  public M getModel()
  {
    return (M) super.getModel();
  }

  @Override
  @SuppressWarnings("unchecked")
  public F getFigure()
  {
    return (F) super.getFigure();
  }

  @Override
  @SuppressWarnings("unchecked")
  public P getParent()
  {
    return (P) super.getParent();
  }

  @Override
  protected abstract F createFigure();
 
  /**
   * Retrieve the {@link ZoomManager}
   * @return the ZoomManager of this parts scalable root part 
   */
  public ZoomManager getZoomManager() {
    return ((ZoomManager) getViewer().getProperty(ZoomManager.class.toString()));
  }
}

Until next time ... Happy Coding!