Eclipse4/RCP/Modeled UI/Contributing to the Model

From Eclipsepedia

< Eclipse4‎ | RCP‎ | Modeled UI
Jump to: navigation, search

Model Fragments

Your application model can be spread out across several e4xmi files, to be stiched together at startup. This mechanism allows adding new mode elements or referencing existing model elements to collections defined by other model elements. For example, you can use a fragment to define a new MWindow and add it to the MApplication's children (a set of windows). It is important that any model elements that you intend to reference have a unique elementId (e.g., the MApplication).

  1. Create a fragment file, typically called fragment.e4xmi
  2. Add the necessary imports to bring in model elements that will be referenced, as opposed to being extended
  3. Add StringModelFragments for each of the model elements to be extended. The parentElementId is the elementId of the element to be extended. featureame is the container feature name where new or existing elements will be added to.

For example, the following is a very simplified example of a fragment adding a command handler for the standard Exit/Quit command, where the command was defined elsewhere and thus imported:

<fragment:ModelFragments ...elided...>
  <!-- we now reference the "org.eclipse.ui.file.exit" command with "XXXX" -->
  <imports xsi:type="commands:Command" xmi:id="XXXX" elementId="org.eclipse.ui.file.exit"/>
 
  <!-- add a handler for the org.eclipse.ui.file.exit command to the app's global handlers -->
  <fragments xsi:type="fragment:StringModelFragment" xmi:id="..." featurename="handlers"
         parentElementId="my.e4.application">
    <elements xsi:type="commands:Handler" xmi:id="..." elementId="handler.exit"
       contributionURI="platform:/plugin/bundle/class.to.MyExitHandler" command="XXXX"/>
   </fragments>
</fragment:ModelFragments>

Although you can define such a file by hand if you like, we recommend using the Workbench Model Editor instead.

Finally, the fragment is made available through the org.eclipse.e4.workbench.model extension point.

<extension
         point="org.eclipse.e4.workbench.model">
      <fragment
            uri="fragment.e4xmi">
      </fragment>
</extension>

Creating Model Elements at Runtime

New elements are created and incorporated into the model using standard EMF patterns:

  1. Obtain the appropriate factory for the package.
  2. Create the desired object.
  3. Incorporate it into the model, typically by adding it to the appropriate container, to cause the element to be rendered.

For example, to create a new part:

// the container will hold the new element; maybe obtained using the EModelService
MPartStack container = ...; 
MPart part = MBasicFactory.INSTANCE.createPart();
part.setLabel("The Part Label");
part.setElementId("a-unique-identifier-for-this-part");
part.getPersistedState().put("input", "http://eclipse.org");
part.setContributionURI("platform:/plugin/bundle/classname");
 
container.getChildren().add(part);
container.setSelectedElement(part);  // raise to top


Manipulating the Model With Processors

Model processors are objects that provided the opportunity to modify and add to the model before its rendered. For example, we sketch here a model processor to ensure that a specific AddOn is configured for the application.

A model processor is configured through an extension to the org.eclipse.e4.workbench.model extension point.

<extension
         point="org.eclipse.e4.workbench.model">
      <!-- if beforefragment="true", then the processor is run before any fragments are stitched in -->
      <processor
            beforefragment="false"
            class="package.FooProcessor">
      </processor>
</extension>

A model processor is a normal injectable POJO class whose processing is triggered by ab @Execute-annotated method. For example, the basic template for a processor that acts to ensure that a particular addon is configured would look something like the following:

// ensure the FooAddOn is defined for this application
class FooProcessor {
	@Inject
	protected MApplication app;
 
	@Execute
	public void execute() {
		String addonId = FooAddOn.class.getName();
		for (MAddon addon : app.getAddons()) {
			if (addonId.equals(addon.getElementId())) {
				// our addon was found
				return;
			}
		}
 
		MAddon addon = MApplicationFactory.INSTANCE.createAddon();
		addon.setContributionURI("platform:/plugin/bundle/package.FooAddOn");
		addon.setElementId(addonId);
		app.getAddons().add(addon);
	}
}

Model processors differ from fragments in two key ways. First, a processor can perform more sophisticated manipulations of the model, such as deleting elements or moving elements within the model, as well as creating new elements. The fragment example above, that installed a handler for the org.eclipse.ui.file.exit command, may not perform as expected if there is an existing global handler for that command. Second, model processors are not specific to a particular application instance. Although our FooAddOn could have been installed through a model fragment, the fragment would have had to explicitly specify the application's elementId to be extended, and thus been locked-in. Typically fragments are used for application extensions, and model processors for installing services that are application-independent. This pattern is used in the E4AP itself, such as to configure the MacOS X Cocoa enhancement (found in org.eclipse.e4.ui.workbench.renderers.swt.cocoa).