Developer Guide to Extending the Notational Meta-Model

Contents


Introduction

[back to top]

GMF is the project aimed to ease the creation of various graphical editors for different models by bridging between GEF (Graphical Editing Framework) and EMF (Eclipse Modeling Framework). The graphical editors use the Model-View-Controller architecture imposed by GEF.  GEF leaves the model part entirely opened for clients. GMF, as a GEF client project, fills the model gap with the EMF model.

The model in GMF consists of two parts: the semantic model and the notational model. The semantic model of an element describes its semantic properties such as name, etc. The notational model describes notational properties of the element such as its size, location, color etc. The meta-model for the semantic model is entirely implemented by a client, hence there is no lack of extensibility for the semantic part of the model. The notational meta-model is fully implemented by the GMF runtime component. Any notational element is a View. Different notational element can be created with the help of different styles, i.e. ShapeStyle, DrawerStyle, FontStyle, LineStyle, etc. that are installed on the View. For an example, a shape can be created with the help of ShapeStyle, however, if DrawerStyle is installed as well the element becomes a compartment shape. Notational meta-model defines a limited set of elements, Hence, the client may have difficulties introducing new notational data for his elements not covered by the elements present in the notational meta-model. (Refer to Developer Guide to the GMF Runtime Framework for more information on Notation Meta-model)

Notational data is added to views (notational model elements) via installing various styles on them. The number of styles in GMF’s notational meta-model is limited and each style has its own purpose defined and supported in the GMF runtime code. Therefore, if clients need to define extra notational data for a View via style it’s unlikely that they would find the proper style defined in GMF’s notational meta-model before 2.0. Consequently, it’s been decided to add a number of general purpose styles for clients in GMF 2.0 such that they have a possibility to introduce specific notational data for visual elements on their diagrams.

A general purpose style has a name and a value of some type.  Clients can choose one of the general purpose styles holding the appropriate type value defined in GMF 2.0 notational meta-model, name it, and install it on the View.  For an example, let’s say you wanted to have the ability to rotate a shape on your diagram.  You could install an IntValueStyle, named “RotationStyle”, on your shape’s view, which will hold the value of a rotation angle in degrees.


General Purpose Styles Design Diagram

[back to top]

The green boxes (green class shapes) represent general purpose styles clients can install on Views. Yellow boxes represent auxiliary data structures used by the styles. Red boxes (in our case just one box) represent elements referenced from the ECore meta-model.

 


General Purpose Styles Overview

[back to top]

The simplest general purpose style is NamedStyle which just has a name. All general purpose styles that hold a value are derived from NamedStyle and essentially just add values of various types to the style object. The general purpose styles can be subdivided into categories as follows: (it’s just a schema – not a UML Class diagram)

Primitive type value styles hold a java primitive type value or a list of such values. This is expected to be the most frequently used style. They are simple and easy to use in terms of notification events, because they are similar to the ones fired from other styles. Essentially, the same comment goes to EObject value styles that have a single reference to EObject and list of references to EObjects – they are also simple in terms of notifications.

Generic Value Styles

Generic value styles are the ones that can hold a value of potentially any type of Java object as long as clients provide a way to convert it to and from the String. The generic value styles must be provided with org.eclipse.emf.ecore.EDataType type of the value. The EDataType defines the actual Java type for the value (Integer, Double, etc.) and the mechanism to convert it to and from the String of the object of this type with the help of the EFactory of the EDataType. For example, SingleValueStyle can simulate IntValueStyle as follows:

SingleValueStyle style = NotationFactory.eINSTANCE.createSingleValueStyle();
style.setName(“MyIntValueStyle”);
style.setEDataType(EcorePackage.Literals.EINT);

The generic value the style holds is stored as the String at all times, however, there are utilities defined on generic styles that convert the String value to the java.lang.Object and vice versa. In fact, SingleValueStyle has utilities for setting and getting java.lang.Object value. Hence, to hold an integer value 5, we could do it in two ways: either set the string raw value (which will be validated against the EDataType of the style)

style.setRawValue(“5”);

or set the object.

style.setObject(new Integer(5));

The notification, however, that is fired due to the change to the value held by the style will have newValue and oldValue of type String, since only the String representation of the value is stored and therefore modified. These String values can be converted to the java.lang.Object (this is specified by the EDataType) with the help of getStringFromObject(Object) and getObjectFromString(String) methods defined on the style.

For any custom Java object type values that a style may hold, the ecore model must be created and an EDataType for this object defined with String to Java Object conversion methods implemented in the corresponding EFactory class. In this case, if you have a Java object that holds a boolean and the String value, for example, and you have defined the EDataType for this object, notification events will tell you that the value has changed even if you’ve changed only the boolean value of the object. If you’d like to receive events on changes to a specific attribute of your custom Java object value, you might be better off with the PropertiesSetStyle

Set of Generic Values Style

Suppose, you want to have a Java object type value in a style and the Java object is holding a mix of attributes of different Java primitive types or other types. Two possible solutions are:

1)      Install a number of SingleValueStyle with appropriate data types or even use the existing Primitive Type Value Styles. However, this would increase the memory consumption, since every style is an EObject and a possible confusion due to the fact that properties that belong together will be separated into multiple styles.

2)      Notational meta-model has PropertiesSetStyle. This style basically contains an EMap of property names (String) to property values (PropertyValue). PropertyValue is similar to a generic value style. It defines a holder for generic value. It has a rawValue of the object (its String representation) and instanceType (EDataType) of the object to be able to convert to and from String. A number of utility methods are defined on the PropertiesSetStyle to ease the work with the style. The disadvantage of this style is that notification coming in from changing property values look different from all other styles, hence handling of these events is bit more complex.


Example of PropertiesSetStyle Usage

[back to top]

An example of how to deal with the PropertiesSetStyle is encapsulated within the GMF Logic example editor. A feature of changing ports (or pins) color on Circuits and LEDs has been added with the help of  a PropertiesSetStyle. The style, in this case, contains only one entry in the map. The PropertyValue has an EIntegerObject data type from ecore. There is a menu item added “Modify Ports Color” on the popup menu on a LED and a Circuit, the request for modifying ports color assembled; there is an editpolicy that handles this request and creates the command for updating the style with a new color value and a code on corresponding editparts handling the notification event fired according to the change. Here, we’ll talk only about installing the style on a LED View, modifying the color value on the style from the command and handling the notification event the editpart receives due to the change of the color value. Code snippets are based on the implementation of “ports color” feature from Logic example editor.

Installing PropertiesSetStyle on a View

Since we’re installing the style on the LED view, we need to override the #createStyles() method on the LEDViewFactory. Create our PropertiesSetStyle, assign it a name, add appropriate properties to it (with the help of utility methods defined on the style, so we don’t need to access the map directly) and add our style to the list of styles.

Protected List createStyles(View view) {
         List styles = super.createStyles(view);
         PropertiesSetStyle properties = NotationFactory.eINSTANCE.createPropertiesSetStyle();
         properties.setName(StringConstants.PORTS_PROPERTIES_STYLE_NAME);
         properties.createProperty(StringConstants.PORTS_COLOR_PROPERTY_NAME, EcorePackage.Literals.EINTEGER_OBJECT, null);
         styles.add(properties);
         return styles;

}

The method #createProperty(String propertyName, EDataType instanceType, Object value) is one of the utility methods defined on the style. It creates the PropertyValue and inserts it in the map against the propertyName key. (See General Purpose Styles Design Diagram)

Modifying PropertyValue with the Command

We’ll assume that the command has the integer value for the color already as well as the View of a LED for which the ports color needs to be changed (see ModifyPortsColorCommand). Now to modify the color of the ports all we need is to get our PropertiesSetStyle the name of which is known and set the ports color property a value of the new color. So, to get our style we need to do the following:

PropertiesSetStyle properties = (PropertiesSetStyle)view.getNamedStyle(NotationPackage.Literals.PROPERTIES_SET_STYLE, StringConstants.PORT_PROPERTIES_STYLE_NAME);

Note that here we use the View#getNamedStyle(EClass eClass, String name) method that does the job of finding the style with given EClass and name on the View from the ones installed on it. This method should be used for getting any other general purpose styles from a View.

Now we need to update the ports color property with a new color value. Before we do so we ensure that the style has been found (i.e. it’s not null) and that the ports color property belongs to this style (just for safety, otherwise it may need to be created).

if (properties != null && properties.hasProperty(StringConstants.PORTS_COLOR_PROPERTY_NAME)) {
         properties.setProperty(StringConstants.PORTS_COLOR_PROPERTY_NAME, newColor);
}

This should update the LED View with the new ports color value. The next thing is handling the notification event fired for this model change.

Handling Notification Event

Since we’ve modified the feature on the PropertyValue, namely the rawValue, the feature in the notification will be NotationPackage.Literals.RAW_VALUE__PROPERTY_VALUE. The notification will have new and old value as strings (as for other generic value holder styles – mentioned above), so if you need those values you’ll have to convert them to Java objects as explained above (see Generic Value Styles). However, in our example we only care about the new value which we can get directly from the style, so there is no conversion involved.

First of all we need to ensure that the notification event came from our PropertiesSetStyle installed on the LED View. The notifier object for the notification is the PropertyValue. The event is caught on the View. If the PropertyValue belongs to our PropertiesSetStyle installed on the LED view then the following hierarchy must be satisfied: PropertyValue -> map entry -> PropertiesSetStyle -> view. We need to ensure that the view is our LED view, so that we handle an event that came from our editpart’s view - just a safety check.

View viewContainer = ViewUtil.getViewContainer((EObject)notification.getNotifier());
if (viewContainer != null && viewContainer.equals(this.getNotationView())) {
         /* Put the handling code here */
}

Note that the notification is handled on LEDEditPart which is a subclass of GMF’s GraphicalEditPart and that we use a utility method ViewUtil#getViewContainer(EObject eObject) that finds the first View parent of the passed EObject.

Now, we need to ensure that the PropertyValue belongs to our PropertiesSetStyle. The best way to check that is get our PropertiesSetStyle from the View of our editpart and get the PropertyValue from the EMap, since property name (the key) is known – we’re interested in ports color property here. Once we have this PropertyValue a simple comparison of a notifier object with the obtained PropertyValue will tell us whether the event needs to be handled. Handling of the event in this case will be just refreshing the ports figures (input/output terminals).

Therefore the chunk of code handling the change in ports color value including everything will look as following:

if (NotationPackage.Literals.RAW_VALUE__PROPERTY_VALUE.equals(notification.getFeature()) {
         View viewContainer = ViewUtil.getViewContainer((EObject)notification.getNotifier());
         if (viewContainer != null && viewContainer.equals(this.getNotationView())) {
                 PropertiesSetStyle style = (PropertiesSetStyle)this.getNotationView()
                          .getNamedStyle(NotationPackage.Literals.PROPERTIES_SET_STYLE, StringConstants. StringConstants.PORT_PROPERTIES_STYLE_NAME);
                 if (style != null && notification.getNotifier().equals(style.getPropertiesMap().get(StringConstants.PORTS_COLOR_PROPERTY_NAME))) {
                          /* Repaint ports figure with new color here */
                 }
         }
}
 


Conclusion

[back to top]

GMF 2.0 introduces a library of general purpose styles for clients, so that they can store notational information that their application requires. Clients are free to pick any style that best suites their purposes. Primitive Types Value Styles and EObject Value Styles are the easiest to use. Generic Value Styles are a bit more complicated because clients may want to define a custom EDataType for values as well as notifications will have new and old values as String rather than actual objects. PropertiesSetStyle is the most generic of all, yet the most complicated of all to use, since notifications will be arriving from PropertyValue (which is inside the map entry and map entry inside the style) rather than the style object itself as for any other style defined in Notational meta-model. Feel free to take a look at the example of use of PropertiesSetStyle in GMF’s Logic example editor.