Skip to content

Customizing the Java source code generated by Eugenia

Occasionally, the Java source code generated by GMF to implement your graphical editor is not quite what you want, and it's not possible to polish the GMF models to incorporate your desired changes. Essentially, you'd like to change the code generation templates used by GMF.

In this situation, you have two options. The first option is to use GMF dynamic templates, which requires some knowledge of Xpand (the code generation language used by GMF) and can often involve hunting around in the GMF code generator for the right place to make your changes. Alternatively, you can use Eugenia's patch generation and application functionality (described below).

Running example

The remainder of this article demonstrates how to customize the source code for a generated GMF editor to change the size of the margins used for external labels. As shown below, the patched version of the GMF editor positions labels closer to their nodes:

Note that the models used by GMF to generate our editor don't provide a way to control the size of the margins, so we can't use a polishing transformation.

Automatically patching the source code of a generated GMF editor

After generating the GMF code for your editor, Eugenia will search for a patches directory in the same project as your Emfatic source. If the patches directory is found, Eugenia will apply to your workspace any .patch file found in that directory.

Creating and applying patches with Eugenia

Create .patch files using Eclipse's Team functionality:

  • Make your desired changes to the generated Java source code by hand.

  • Right-click the project containing your changes, and select Team→Create Patch...

  • Select Clipboard and click Finish

  • Create a patches directory in the project containing your Emfatic source.

  • Create a new file (e.g. patches/MyChanges.patch), paste your patch into the new file and save it.

  • The next time that you run EuGEnia, your .patch file will be automatically applied to the generated Java source code.

  • You can also apply or remove all of your patches by right-clicking your patches directory and selecting Eugenia→Apply patches or Eugenia→Remove applied patches.

In our running example, we devise the patch below to fix the margins of externally placed labels for the State model element type. We save the patch into patches/FixExternalLabelMarginsForState.patch

diff --git org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/StateEditPart.java org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/StateEditPart.java
index d0684d6..f162365 100644
--- org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/StateEditPart.java
+++ org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/StateEditPart.java
@@ -143,7 +143,7 @@
     if (borderItemEditPart instanceof StateNameEditPart) {
       BorderItemLocator locator = new BorderItemLocator(getMainFigure(),
           PositionConstants.SOUTH);
-      locator.setBorderItemOffset(new Dimension(-20, -20));
+      locator.setBorderItemOffset(new Dimension(-5, -5));
       borderItemContainer.add(borderItemEditPart.getFigure(), locator);
     } else {
       super.addBorderItem(borderItemContainer, borderItemEditPart);

Generating patches with Eugenia

It is possible to generate .patch files as part of the Eugenia code generation process. This allows you to include in .patch files information from your source metamodel, or from the GMF models generated by Eugenia. Generating .patch files is particularly useful when you want to apply the same type of change in several places in the Java source code for your GMF editor:

  • Create a file named GeneratePatches.egx in the same directory as your Emfatic source code.

  • In the GeneratePages.egx file, write a transformation rule for each element of the ECore or GMF models for which you want to generate a .patch file:

  • Create one or more EGL templates for use by your GeneratePages.egx file. Each EGL template is essentially a parameterised .patch file.

  • The next time that you run EuGEnia, your GeneratePatches.egx file will be automatically invoked to generate one or more .patch files, which will then be automatically applied to the generated Java source code.

  • You can also test your GeneratePatches.egx file, by right-clicking it and selecting Eugenia→Generate patches.

In our running example, we can generalise our State patch (above) such that it is applied to any element in our metamodel that has an external label. First, we create a GeneratePatches.egx file that produces a .patch file for every EClass in our ECore file that is annotated with label.placement set to external:

// Imports the EClass#getLabelPlacement() operation from Eugenia
import "platform:/plugin/org.eclipse.epsilon.eugenia/transformations/ECoreUtil.eol";

rule FixExternalLabelMargins
  // apply this rule to all EClasses where...
  transform c : ECore!EClass
{

  // ... the EClass is annotated with @gmf.node(label.placement="external")
  guard: c.getLabelPlacement() == "external"

  // invoke the following EGL template on the EClass
  template : "FixExternalLabelMargin.egl"

  // make the source directory and name of the node available to the template
  parameters : Map{ "srcDir" = getSourceDirectory(), "node" = c.name }

  // and save the generated text to the following .patch file
  target : "FixExternalLabelMarginsFor" + c.name + ".patch"
}

// Determine source directory from GMF Gen model
@cache
operation getSourceDirectory() {
  var genEditor = GmfGen!GenEditorGenerator.all.first;
  return genEditor.pluginDirectory.substring(1) + "/" +
         genEditor.packageNamePrefix.replace("\\.", "/");
}

We'll also need to provide a parameterised version of our State patch, saving it as an EGL template at FixExternalLabelMargin.egl:

diff --git [%=srcDir%]/edit/parts/[%=node%]EditPart.java [%=srcDir%]/edit/parts/[%=node%]EditPart.java
index d0684d6..f162365 100644
--- [%=srcDir%]/edit/parts/[%=node%]EditPart.java
+++ [%=srcDir%]/edit/parts/[%=node%]EditPart.java
@@ -143,7 +143,7 @@
     if (borderItemEditPart instanceof [%=node%]NameEditPart) {
       BorderItemLocator locator = new BorderItemLocator(getMainFigure(),
           PositionConstants.SOUTH);
-      locator.setBorderItemOffset(new Dimension(-20, -20));
+      locator.setBorderItemOffset(new Dimension(-5, -5));
       borderItemContainer.add(borderItemEditPart.getFigure(), locator);
     } else {
       super.addBorderItem(borderItemContainer, borderItemEditPart);
Note that the above template uses the srcDir and node variables made available by our EGX transformation rule.

The next time that Eugenia is invoked, a .patch file is generated and applied for every EClass in our ECore file that has an externally-placed label:

FAQ

Should my patches produce @generated NOT annotations?

No, because this can cause subsequent invocations of Eugenia and the GMF code generator to fail -- the GMF code generator will attempt to preserve code marked as @generated NOT and your .patch files will likely not apply cleanly to the code that has been preserved. The code that is applied via .patch files is generated code and should be treated as such.

One or more of my patches couldn't be applied. What should I do?

Firstly, check to ensure that Eclipse can apply your patch via the Team→Apply patch... menu item. If not, you'll need to fix your .patch file. Secondly, ensure that the order in which your patches are being applied is not causing problems. By default Eugenia orders patches alphabetically by filename: a.patch will be applied before z.patch

I'm using git-svn and my patch files can't be applied by Eugenia or by Eclipse's Team→Apply patch... menu item. What should I do?

You should edit the headers of any patch file generated by git-svn and remove the dummy a and b folders. For example:*

diff --git a/org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java b/org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
index 65e2685..109b568 100644
--- a/org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
+++ b/org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
@@ -152,6 +152,8 @@
...

becomes:

diff --git org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
index 65e2685..109b568 100644
--- org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
+++ org.eclipse.epsilon.eugenia.examples.executablestatemachine.graphical.diagram/src/esm/diagram/edit/parts/EndStateEditPart.java
@@ -152,6 +152,8 @@
...