Getting the basic structure for the editor is not very difficult. As for any other editor, we are contributing to the org.eclipse.ui.editor. In my specific case, I associate my editor to the wsprotocol extension. I want to provide an editor which supports a flyout palette, that is, a palette that can be docked and that can appear or disappear when the mouse passes over. There are several classes that you can subclass from the org.eclipse.gef.ui.parts package to feed the extension point. Here's what I did:

public class ProtocolEditor extends GraphicalEditorWithFlyoutPalette
{
    /**
     * The model instance.
     */
    protected BusinessProtocol protocol;

    /**
     * The palette.
     */
    protected static PaletteRoot PALETTE;
    (...)

Here I have an instance of my model as well as an instance of the palette that I need to display. Before we go any further, we have to understand a few things about GEF. I suggest that you read (if you haven't done it yet) the short GEF documentation provided by the Javadocs starting point. Even if you don't understand everything, you should have in mind the following rough picture:

  • the view is provided by Draw2D figures
  • the model is yours
  • the controller is made of EditParts that you will fill later
  • there are EditPartViewers to display your EditParts
  • there is a CommandStack for each editor: actions (like moving a figure, adding it, ...) are put in this stack which also maintains the dirty status (i.e. wether the model is in sync with the file or not)
  • there is one EditDomain per editor to put everything together.

Don't worry anyway, it always get much clearer when implementing things ;-) Here's the constructor:

public ProtocolEditor()
{
    super();
    setEditDomain(new DefaultEditDomain(this));
    getCommandStack().setUndoLimit(-1);
}

We just put a default edit domain and don't put any limit to the command stack. Putting actions into small bricks that you put in a stack makes it easy to undo / redo actions. There is not much that we are going to do with the command stack anyway, the overriden class provides us with everything. We just have to react to command stack events and set our editor as dirty (this means that something has changed in our model). We mark save points in the command stack everytime we save the file. These save points mark the editor as not dirty, the rest of the time it has to be:

public void commandStackChanged(EventObject event)
{
    firePropertyChange(IEditorPart.PROP_DIRTY);
    super.commandStackChanged(event);
}

We can now set-up the graphical viewer:

   protected void configureGraphicalViewer()
   {
       super.configureGraphicalViewer();

       GraphicalViewer viewer = getGraphicalViewer();
       viewer.setEditPartFactory(new BusinessProtocolEditPartFactory());
       viewer.setRootEditPart(new ScalableFreeformRootEditPart());
       viewer.setKeyHandler(new GraphicalViewerKeyHandler(viewer));
   }

   protected void initializeGraphicalViewer()
   {
       super.initializeGraphicalViewer();
       GraphicalViewer viewer = getGraphicalViewer();
       viewer.setContents(getModel());
   }

EditParts are built using a factory, but we will get back to this next time. For the moment, you can just feed an empty factory. We also feed the viewer with our model (getModel() is a simple getter to our model property). The Eclipse platform is also going to give us the file to open:

   protected void setInput(IEditorInput input)
   {
       super.setInput(input);
       IFile file = ((IFileEditorInput) input).getFile();
       try
       {
           InputStreamReader reader = new InputStreamReader(file.getContents());
           XmlIOManager manager = new XmlIOManager(new BusinessProtocolFactoryImpl());
           setModel(manager.readBusinessProtocol(reader));
           reader.close();
           setPartName(file.getName());
       }
       catch (DocumentException e)
       {
           handleLoadTimeException(e);
       }
       catch (CoreException e)
       {
           handleLoadTimeException(e);
       }
       catch (IOException e)
       {
           handleLoadTimeException(e);
       }
   }

Simple isn't it ? :-) However everything is not yet ready to work. You need to provide a palette, else you should get a very nice exception if you try to run your editor:

   protected FlyoutPreferences getPalettePreferences()
   {
       return ProtocolEditorPaletteFactory.createPalettePreferences();
   }
 
   protected PaletteRoot getPaletteRoot()
   {
       if (PALETTE == null)
       {
           PALETTE = ProtocolEditorPaletteFactory.createPalette();
       }
       return PALETTE;
   }

The ProtocolEditorPaletteFactory is heavily inspired of the one from the shapes editor sample. I suggets that you refer to it when you need to create your own palette, it is actually very easy to understand. Here are some extracts though:

   public static PaletteRoot createPalette()
   {
       PaletteRoot palette = new PaletteRoot();
       palette.add(createBasicToolsGroup(palette));
       palette.add(createStatesDrawer(palette));
       palette.add(createOperationsDrawer(palette));
       return palette;
   }

   protected static PaletteContainer createBasicToolsGroup(PaletteRoot palette)
   {
       // Basic tools
       PaletteDrawer drawer = new PaletteDrawer(Messages.toolsPaletteGroup);

       // Add a selection tool to the group
       ToolEntry tool = new PanningSelectionToolEntry();
       drawer.add(tool);
       palette.setDefaultEntry(tool);

       // Add a marquee tool to the group
       drawer.add(new MarqueeToolEntry());

       return drawer;
   }

   protected static PaletteContainer createStatesDrawer(PaletteRoot palette)
   {
       PaletteDrawer drawer = new PaletteDrawer(Messages.statesPaletteGroup);
       CombinedTemplateCreationEntry component;

       component = new CombinedTemplateCreationEntry(Messages.initialState, Messages.createInitialState,
               State.class, new StateCreationFactory(true, false), ImageDescriptor.createFromFile(
                       EditorPlugin.class, "icons/state_ini_16.png"), ImageDescriptor //$NON-NLS-1$
                       .createFromFile(EditorPlugin.class, "icons/state_ini_24.png")); //$NON-NLS-1$
       drawer.add(component);
    (...)

You can now run your Eclipse application to test the editor (that must appear blank actually). To do that, just create a new file in a project (for instance foo.wsprotocol) and open it. If you already have files for your model, you can also import one, this will save some I/O problems since a blank file can be invalid for your model reader ;-)

Next time we'll start populating the editor with EditParts. Please note that the above text has been redacted after the implementation, so I hope I did not miss anything that you need to do in this initialisation phase ;-)