Friday, January 28, 2011

How to reuse Eclipse EMF.edit to write GEF editors


If you are into Eclipse Plugin development you’ve definitely heard of Eclipse Modeling Framework (EMF).
EMF provides a framework to define, code-generate, extend etc, for user-defined structured data models.
There are various ways to define the data model. One example would be using a define data model in XSD and use EMF to code generation.
EMF handles the code-generation of the model as well it also generate a general GEF based editor to manipulate the model instances using a tree-view, list-view, table-view etc.
Apart from it EMF provides many features to seamlessly extend the model.

This blog-post talks about the basic initial steps to implement a eclipse editor using EMF.edit package. If you are not that much familiar with EMF.edit refer this documentation.

Few features provided by EMF.edit is
  1. Content provider and Label provider
  2. Property Source
  3. Command framework
  4. Change notifier
1. Content provider and Label provider
These classes are used to represent data to the end-user. Here I’m not going much deeper. I’ll show you a code snippet that can be used on top of EMF.edit code and reuse the content and label providers used by the EMF framework.

adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
adapterFactory.addAdapterFactory(new NamespaceItemProviderAdapterFactory());

TableViewer notificationsTableViewer;
notificationsTableViewer = new TableViewer(parent, SWT.SINGLE);
notificationsTableViewer.setContentProvider(new AdapterFactoryContentProvider(adaptorFactory));
notificationsTableViewer.setLabelProvider(new AdapterFactoryLabelProvider(adaptorFactory));
notificationsTableViewer.setInput(notifications);

2. Property Source
Property source provider is used to represent the properties involved with a particular model object. In EMF.edit the item provider classes implements org.eclipse.emf.edit.provider.IItemPropertySource.
Here is a code snippet that can be used to integrate property source providers generated from EMF framework.

propertySheetPage =new PropertySheetPage ();
propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(adapterFactory));

If you go into provider classes generated from EMF.edit, you’ll see those classes have three methods, that implement the interface IItemPropertySource.

List getPropertyDescriptors(Object object);
IItemPropertyDescriptor getPropertyDescriptor(Object object, Object propertyID);
Object getEditableValue(Object object);

So you can reuse/study the above three method implementations to represent properties for each element.

3. Command Framework
If you have heard of Eclipse Command Framework, you’ve already realized how it is easy and cool to use eclipse commands to edit the EMF model objects.
Here’s a sample code to add a new element to the parent. This code is not general for all commands. So you may need to refer some documentations on this.

Group group = _200803Factory.eINSTANCE.createGroup();
group.setName(“Group Name”);
List<group> list = new BasicEList<group>();
list.add(group);
 
Command addGroup= AddCommand.create(domain, group, _200803Package.eINSTANCE.getGroups_Group(), list);
if(addGroup.canExecute()){
  domain.getCommandStack().execute(addGroup);
}else {
  System.out.println("Cannot execute");
}

4. Change notifier
In EMF.edit framework item provider adapters extends ItemProviderAdapter class which extends AdapterImpl. The method NotifyChange() is implemented in order to notify the viewers related to changes occurred to a model.

public void notifyChanged(Notification notification) {
  updateChildren(notification);
  switch (notification.getFeatureID(TExtensibleElements.class)) {
    case _200803Package.TEXTENSIBLE_ELEMENTS__DOCUMENTATION:
    case _200803Package.TEXTENSIBLE_ELEMENTS__ANY:
    case _200803Package.TEXTENSIBLE_ELEMENTS__ANY_ATTRIBUTE:
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
  return;
  }
  super.notifyChanged(notification);
}

Take a look at the code of this method, you will find, fireNotifyChange() method is called with a parameter ViewerNotification, this method is defined in ItemProviderAdapter which implements the interface “IChangeNotifier”, both the viewers and property sheets are the listener of the IChangeNotifier (using addListener and removeListener method provided by ItemProviderAdapter to register as a listener of the item provider), and in the changeNotifier.fireNotifyChanged(notification) method will called all the listener’s notifyChange() method.

public void fireNotifyChanged(Notification notification) {
  if (changeNotifier != null) {
    changeNotifier.fireNotifyChanged(notification);
  }

  if (adapterFactory instanceof IChangeNotifier) {
    IChangeNotifier changeNotifier = (IChangeNotifier)adapterFactory;
    changeNotifier.fireNotifyChanged(notification);
  }
}

1 comment:

Unknown said...

Denis as in this article you include snipets of generated code from a .genmodel model.

Do you have an example (i.e.GEF editor) of how to reuse of this code used by a GEF editor?

And have you any automatization for creating a GEF editor?

Thanks,