Eclipse Development Using the Graphical Editing Framework And the Eclipse Modeling Framework

 < Day Day Up > 


7.2 Architecture

In this section we describe the architecture of the sample application. We discuss the techniques that we use to connect the EMF model with the editor framework.

7.2.1 Mapping the EMF model to GEF EditParts

One of the key tasks in creating a GEF application is the process of mapping your applications EditParts with your model. In this section we discuss the process that we took to bind our sample application's EMF-based model with the editor framework. The GEF provides a lot of flexibility as far as how its EditParts relate to the underlying model. There are no strict requirements on how EditParts map to actual objects in the model. The first step, then, is to decide what this mapping will be in your application.

In general, there will probably be fewer EditParts than there are object classes in your model. For instance, in our sample application, we created the WorkflowNodeEditPart to be the base class for model elements that have connections. In the model, the ports are separate objects; but in the editor, we chose to have the WorkflowNodeEditPart represent both the node and all its ports. One criterion for making a determination about this mapping is to consider how dynamic the visual behavior of a component needs to be.

For instance, if a model object needs a visual representation that can be moved, resized, or can be individually added or deleted, then it may be a good candidate for mapping it to its own EditPart. In our sample application, we designed the EditPart class hierarchy shown in Figure 7-1.

Figure 7-1: The sample application's EditPart class hierarchy

EditPart functionality

The base class for our EditParts is the WorkflowElementEditPart class, which provides the following three main functions needed by all its subclasses:

7.2.2 Tracking model events in the editor

Once your EditPart to model mapping strategy has been designed, the next step is to enable your EditParts to be able to track changes in your model. As we have said, GEF itself does not provide nor require any specific event notification mechanism. If you are working with a model that does not include an event mechanism, one approach is to use the Java beans event support provided by the classes, java.beans.PropertyChangeSupport and java.beans.PropertyChangeListener.

This is the approach taken in the logic example that the GEF project provides. In our case we are fortunate to have the full-featured notification mechanism that is generated automatically in EMF classes. Recall that all the EditParts in our sample are registered as adapters on the EMF model class(es) that they represent. Each EditPart then provides an override of the notification method:

public void notifyChanged(Notification notification)

This method is called when any attribute of a model class is changed, or when a child object is added or removed. The Notification class provides extensive context describing the model change that has occurred. It includes information such as:

This information is used to filter out events so that each EditPart only processes changes that are unique to properties of that particular part. Processing of more generic changes, for instance a change to a part's size or location, should be delegated to the superclasses implementations of notifyChanged(). Notice that the notification mechanism provided by EMF is very thorough, so that a change to any attribute will result in a notification event. This means that a more complicated model operation, in which several attributes are manipulated, results in a large number of notification events. Ideally the EditPart's implementation will filter these events accordingly so that the visual representation is maintained accurately while events that do not require a change to the visual representation are ignored.

Remember that a single EditPart may be responsible for the representation of more than one object in the underlying model. In our sample application this is the case with WorkflowNodeEditParts, which represent a WorkflowNode with some number of Ports. In our model the action of adding or removing a connection is something that happens to ports, not the WorkflowNode to which it is attached. Therefore our WorkflowNodeEditPart needs to perform some additional registration to make itself a listener on its WorkflowNode's ports. Otherwise it will not be notified of connection changes to its ports. This is done in the notifyChanged() method of the WorkflowNodeEditPart, which is a base class for all the EditParts in our sample application that support connections. When a port is added to any WorkflowNode model element, the WorkflowNodeEditPart adds itself as a listener on the new port.

7.2.3 Refreshing

Once we have ensured that our EditParts are receiving all the notifications they require to track their model, we then need to add code in our EditParts that acts on this information. The implications of a model event to an EditPart can be distilled into three general operations. The EditPart must interpret the notification to decide which of these operations are required:

7.2.4 Factories

We use two factories in order to integrate between GEF and our EMF-based model. First we need to use the EMF-generated factory, WorkflowFactory, whenever we are creating new model objects. Typically this happens when a creation command is either initialized by a policy or when the creation command is executed. The factory is made available to these functions by setting it as the factory for the creation tools created in the palette, as we do in the WorkflowPaletteRoot class. The factory is set in the constructor for the CreationToolEntry class. The class ModelCreationFactory, which implements CreationFactory, is where the EMF factory is invoked. The getNewObject() method in this class is where objects are actually created, as show in the snippet in Example 7-5.

Example 7-5: A snippet of the getNewObject() factory method

public Object getNewObject() { Map registry = EPackage.Registry.INSTANCE; String workflowURI = WorkflowPackage.eNS_URI; WorkflowPackage workflowPackage = (WorkflowPackage) registry.get(workflowURI); WorkflowFactory factory = workflowPackage.getWorkflowFactory(); Object result = null; if( targetClass.equals( Task.class ) ) { result = factory.createTask(); } else if( targetClass.equals( CompoundTask.class ) ) { result = factory.createCompoundTask(); } else if(...) ) { } return result; }

In 7.2.3, "Refreshing" on page 208, we discussed the reconciliation process that GEF performs when our EditParts call refreshModelChildren, refreshTargetConnections or refreshSourceConnections. If GEF detects that there are model elements without an associated EditPart, it uses the graphical viewer's factory to create the missing EditPart. In the sample application the class GraphicalEditPartsFactory is our implementation of EditPartFactory that performs this function. This simple class is what ultimately specifies how our model's objects will be mapped to our application's EditParts.

7.2.5 Policies and commands

GEF editors only become interactive when the appropriate EditPolicy implementations are added to EditParts. The EditPolicies are responsible for creating commands to operate on the model and to provide feedback behaviors that allow figures to be selected, dragged, added, deleted, and edited. Our sample uses the following EditPolicies:


 < Day Day Up > 

Категории