Building an editor

Building an editor involves to main steps:
  1. Creating and registering the new editor and
  2. Populating the editor.

The following sections include step-by-step guides and useful information for completing both parts. Throughout this introduction the component editor located in org.fortiss.af3.component.ui.editor.fx is used as an example. Consult its code whenever something is unclear, as it is likely that the new editor will be similar in many aspects.

Creating and registering the editor

The following steps create a new editor and register it within the AF3 runtime. Once completed, the new editor can be opened but it will not contain any elements yet as it is still to be populated.

  1. Create a new package for the FX editor (e.g. org.fortiss.af3.component.ui.editor.fx).
  2. Create the new editor class deriving from LWFXEFEditorBase (see ComponentStructureFXEditor).
  3. Create a new EditorBinding and register it in the plugin.xml (see ComponentStructureFXEditorBinding). Be sure to implement the getEditorClass, getLabel and getPriority methods!
  4. Add a model factory implementing IModelFactory and implement its getRoot() method (see component.ui.editor.fx.ModelFactory). Let other methods return null or empty lists.
  5. Add a visual factory implementing IVisualFactory and returning null in all methods
  6. Create a sub-package controller and add a DiagramController class deriving from EObjectBasedDiagramControllerBase. Nothing needs to be implemented here.
  7. Add a controller factory implementing IControllerFactory and return an instance of DiagramController in createDiagramController. Other methods may return null.
  8. Return instances of the factory class in the respective methods of the editor class.
  9. Start AF3 and test if the new editor is appearing (with an empty background canvas).

Populating the editor

Having created and registered editor, it is now time to populate it.

Models, views and controllers

Editors are implemented using the MVC pattern with models, views and controllers. Hence, each editor has a ModelFactory, a VisualFactory and a ControllerFactory defining models, visuals and controllers for each of the elements to be shown and edited. For a standard boxes-and-wires diagram this includes contents (boxes), links (wires) and anchorages (ports used to connect wires to boxes). The following sections describe how to create the respective models, visuals and controllers for each of them.

Layout data

Whenever dealing with graphical editors it is of utmost importance to know where elements are to be located. This information can be accessed via the LayoutDataUtils and LayoutDataUIUtils classes. They provide methods to e.g. retrieve the position and the bounds of a node (LayoutDataUtils.getNodePosition(ILayoutedModelElement layouted) and LayoutDataUtils.getNodeBounds(ILayoutedModelElement layouted) respectively). For an exhaustive listing of all methods consult the classes' outline.

Populating the editor (finally)

Now onto populating the editor with contents, anchorages and links. Each of them will require the implementation of the classes and methods mentioned in the respective section. Instead of going through each of the methods in detail, it is advised to consult the implementation of the respective methods for the component editor.


Implement the following methods:

  • ModelFactory.getContentModels()
  • VisualFactory.createContentVisual()
  • ControllerFactory.createContentController()

Custom visuals and controller classes to extend in case you want to build a standard boxes-and-wires editor:

  • LayoutedRectangularContentVisualBase (e.g. SubComponentVisual)
  • EObjectBasedRectangularResizableContentControllerBase (e.g. SubComponentController)

In case you need custom shapes, you have to extend the org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.base.ContentVisualBase directly. Orient yourself at the implementation of org.eclipse.systemfocus.kernel.common.ui.javafx.lwfxef.visual.rectangular.RectangularContentVisualBase to know which methods to override and how.


There are two types of anchorages to take care of:

  • Diagram anchorages are attached to the parent element of the content shown in the diagram and are displayed directly on the editor's background without being attached to any element.
  • Content anchorages are attached to contents (i.e. boxes, ellipses etc.) shown in the editor and are displayed at the border of the respective shape.

Implement the following methods:

  • ModelFactory.getContentAnchorageModels()
  • ModelFactory.getDiagramAnchorageModels()
  • VisualFactory.createContentAnchorageVisual()
  • VisualFactory.createDiagramAnchorageVisual()
  • ControllerFactory.createContentAnchorageController()
  • ControllerFactory.createDiagramAnchorageController()

Custom visuals and controller classes to extend:

  • LayoutedCircularContentAnchorageVisualBase (e.g SubComponentPortVisual)
  • LayoutedCircularDiagramAnchorageVisualBase (e.g DiagramComponentPortVisual)
  • LayoutedModelElementBasedContentAnchorageController (e.g SubComponentPortController)
  • LayoutedModelElementBasedDiagramAnchorageController (e.g DiagramComponentPortController)

In order to specify which ports can be linked and which do not check the implementation of the canConnect method in the connection compositor of the editor's contents (e.g. ComponentConnectionCompositor.canConnect(EObject source, EObject target, IHierarchicElement parent, IConnectionCompositionContext context)).


Implement the following methods:

  • ModelFactory
    • getLinkModels()
    • getLinkStart()
    • getLinkEnd()
  • VisualFactory.createLinkVisual()
  • ControllerFactory.createLinkController()

Make sure to implement all three methods of the ModelFactory at the same time, as they depend on each other.

Custom visuals and controller classes to implement:

  • LayoutedLineLinkVisualBase (e.g. ChannelVisual)
  • LayoutedModelElementBasedLinkBendPointController (e.g. ChannelController)

Customizing the editor (optional)

Once created, registered and populated the editor can be further customized by overriding the customizeViewer method of your FXEditor (e.g. ComponentStructureFXEditor.customizeViewer()). The following code snipped shows how to set the indicator spacing and the background color:

/** {@inheritDoc} */
protected void customizeViewer() {
    DiagramViewerFeatures features = viewer.getFeatures();
    features.setIndicatorSpacing(new Dimension2D(12, 12));