How to write automata extensions

The first thing you have to do is to create a new plug-in project (see for instance PDE Does Plug-ins). Open the Manifest file or the plugin.xml and go to the Dependencies tab. Add cwi.ea and org.eclipse.gef to the dependencies. You can of course add more plug-in dependencies later.

Now switch to the Extensions tab. Click on Add, select the org.ect.ea.extensions and press the Finish button. If it doesn't exist yet, create a new extensionDefinition using the context menu of org.ect.ea.extensions. Now fill out the form on the right-hand side. In the end it should look like in the following screenshot.

The first things you have to provide are a name and an ID for the extension. Moreover, the field enabledFor determines what this extension actually extends. It can one of automata, transitions or states. The field type determines how the extensions are presented in the graphical editor. The default value is textual. This means the extensions are shown as labels in the editor. You can also define dependencies and mutual exclusion constraints between the extension definitions.

The field providerClass points to a Java class that implements IExtensionProvider. If you have a textual extension then you should actually implement the interface ITextualExtensionProvider and analogously for custom extensions. For the above example, the extension provider could look like this:

/**
 * This provider adds an integer extension to transitions. 
 * The product is defined as the sum of the integers. 
 * The default value is 0.
 */
public class MyExtensionProvider implements ITextualExtensionProvider {

  /**
   * Create a default extension.
   * The owner is a transition in this case.
   */
  public IExtension createDefaultExtension(IExtendible owner) {
        return new IntegerExtension(0);
  }

  /**
   * Create a silent extension. The transition is a self-loop.
   */
  public IExtension createSilentExtension(Transition transition) {
        return createDefaultExtension();
  }

  /**
   * Check whether an extension is silent. In any case
   * it belongs to self-loop transition.
   */
  public boolean isSilentExtension(IExtension extension) {
        IntegerExtension ext = (IntegerExtension) extension;
        return ext.getValue()==0;
  }
  
  /**
   * Returns a string representation of an extension.
   * Used when the extension is edited.
   */
  public String editExtension(IExtension extension) {
        IntegerExtension ext = (IntegerExtension) extension;
        return ext.getValue() + "";
  }

  /**
   * Returns a string representation of an extension.
   * Used when the extension is displayed.
   */
  public String printExtension(IExtension extension) {
        return "(" + editExtension(extension) + ")";
  }
    
  /**
   * Parse an extension from a string.
   */
  public IExtension parseExtension(String value, IExtendible owner) throws ParseException {
        return new IntegerExtension(Integer.parseInt(value));
  }

  /**
    * Compute the product of two extensions.
    */
  public EList<IExtension> computeProductExtensions(IExtension x1, IExtension x2) {
        EList<IExtension> result = new BasicEList<IExtension>();
        int i1 = ((IntegerExtension) x1).getValue();
        int i2 = ((IntegerExtension) x2).getValue();
        result.add(new IntegerExtension(i1 + i2));
        return result;
  }

  /**
   * Validate an extension.
   */
  public IValidationResult validateExtension(IExtension extension) {
        int value = ((IntgerExtension) extension).getValue();
        if (value<0) {
             return ValidationResult.newErrorResult("Negative integers not allowed");
        } else {
             return ValidationResult.newOKResult();
        }
  }     

  public Color getFontColor(IExtension extension) {
        // You can also use different colors based on the value of an extension.
        return ColorConstants.black;
  }
  
  public boolean isReadOnly(IExtension extension) {
        return false;
  }

}

That's it! Now select your plug-in project in the package explorer and click on the Run button. Run it as an Eclipse application. Wait a couple of seconds until the second instance of Eclipse started up. Now create a dummy project and a new automata diagram inside of that project. Draw an automaton and check in the context menu of the automaton under Extensions whether your extension appears. Enable it and add a couple of states and transitions to the automaton. You should now see labels for your extensions. Last but not least, check if the product is compute correctly (again from the context menu).


How to define a product operation

If the default product operation does not work for your automata model, you have to provide your own product implementation. Product definitions are registered using the extension point org.ect.ea.products. The actual implementation is again given in a provider class. You have to implement the interface org.ect.ea.IProductProvider. The default implementation is the class Automata Product?, which you can also extend. The product definition could like this:

When you have done this and implemented your product operation, start up again a runtime workbench and try to invoke your product operation from the context menu.