Forum Controls
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

Java, the OLPC, and community responsibility

The "One Laptop Per Child" project has a great device ready to ship, but there's no Java on there. Let's think about working together to put Java on OLPC!
Replies: 3 - Pages: 1  
Threads: [ Previous | Next ]
  Click to reply to this thread Reply

Bridging EMF to the common navigator

At 2:40 PM on Oct 31, 2006, Jeffrey Ricker Blooming Javalobby Member wrote:

A common task in building plugins is to provide a new project structure within the navigator. The JDE created its own navigator, and in past projects I was force to do the same. Now there is the means to extend the base navigator for your project structures. There should be an easy way to bridge from the navigator content extension to any EMF model. That is my objective here.

You need to use the Project Explorer in your perspective or create your own viewer that implements the CommonNavigator class. You will not see your changes if you are looking at the Java Package Explorer or the Navigator view.

This project assumes that you have already generated the Edit and Editor plugins for your EMF model.

There are four things that we need to create:
1. Adapter factory provider
2. Adapter factory content provider
3. Adapter factory label provider
4. Changes to the plugin manifest

The first item is the adapter factory provider. The class org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider does not have a simple constructor. It expects an adapter factory in its constructor. Also, to work well, the adapter factory should be shared with the label provider. The class ProjectAdapterFactoryProvider provides a static method getAdapterFactory() that is used in the provider constructors.

/**
 * Provides the shared adapter factory for the content and label provider
 */
public final class ProjectAdapterFactoryProvider {
 
  private static ComposedAdapterFactory adapterFactory;
 
  public final static List<AdapterFactory> createFactoryList(){
    List<AdapterFactory> factories = new ArrayList<AdapterFactory>();
    // this is my provider generated in the .Edit plugin for me. Replace with yours.
    factories.add(new CoreItemProviderAdapterFactory());
    // these are EMF generic providers
    factories.add(new ResourceItemProviderAdapterFactory());
    factories.add(new ReflectiveItemProviderAdapterFactory());
    // ... add other provider adapter factories for your model as needed
    // if you don't know what to add, look at the creation of the adapter factory
    // in your generated editor
    return factories;
  }
 
  public final static ComposedAdapterFactory getAdapterFactory(){
    if (adapterFactory == null) 
      adapterFactory = new ComposedAdapterFactory(createFactoryList());
    return adapterFactory;
  }
}


The label provider is simpler, so we will show it next. Notice that the constructor calls the static method ProjectAdapterFactoryProvider.getAdapterFactory(). The label provider serves a simple purpose: If the object is a file, then it provides a file icon. If it is anything other than file, then it forwards the request to the regular EMF.Edit providers

public class ProjectAdapterFactoryLabelProvider extends AdapterFactoryLabelProvider{
 
  public ProjectAdapterFactoryLabelProvider(){
    super(ProjectAdapterFactoryProvider.getAdapterFactory());
  }
 
  /**
   * Returns the platform icon for a file. You can replace with your own icon
   * If not a IFile, then passes to the regular EMF.Edit providers 
   */
  public Image getImage(Object object) {
    if (object instanceof IFile)
      return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE);
    return super.getImage(object);
  }
 
  public String getText(Object object) {
    if (object instanceof IFile)
      return ((IFile)object).getName();
    return super.getText(object);
  }
}


The content provider is a little more complicated, but works on the exact same principle as the label provider. The content provider uses a single resource set. That may or may not meet your needs. The key method is getChildren(Object object) . If the object is a file, the the provider loads the EMF resource of the file and forwards the resource object to the EMF.Edit providers.

public class ProjectAdapterFactoryContentProvider extends AdapterFactoryContentProvider {
 
  private ResourceSet resourceSet;
  
  public ProjectAdapterFactoryContentProvider(){
    super(ProjectAdapterFactoryProvider.getAdapterFactory());
    resourceSet = new ResourceSetImpl();
  }
 
  public boolean hasChildren(Object object){
    if (object instanceof IFile)
      return true;
    return super.hasChildren(object);
  }
 
  public Object[] getChildren(Object object){
    if (object instanceof IFile){
      String path = ((IFile)object).getFullPath().toString();
      URI uri = URI.createPlatformResourceURI(path);
      object = resourceSet.getResource(uri, true);
    }
    return super.getChildren(object); 
  }	
 
  public Object getParent(Object object){
    if (object instanceof IFile)
      return ((IResource)object).getParent();
    return super.getParent(object);
  }
 
  public Object[] getElements(Object object){
    if (object instanceof IFile){
      String path = ((IFile)object).getFullPath().toString();
      URI uri = URI.createPlatformResourceURI(path);
      object = resourceSet.getResource(uri, true);
    }
    return super.getElements(object); 
  }
}


These three objects should work generically with any EMF project you created. The only thing you have to change is the list of providers used in the ProjectAdapterFactoryProvider.createFactoryList() method. The last part is to plug it in.

The first step is to add the content provider to the view as shown below. If you are not using the platform navigator, then replace the viewer ID org.eclipse.ui.navigator.ProjectExplorer with the ID of your navigator.

The next step is to associate the content providers with the appropriate objects. In this example, the extension for my model objects is "core". You should replace that extension with your own. Also, all of my EMF model objects inherit from an object com.di.myModel.ModelRootObject . You should change this to your root model object or simply use EObject.


<extension point="org.eclipse.ui.navigator.viewer">
<viewerContentBinding viewerId="org.eclipse.ui.navigator.ProjectExplorer">
<includes>
<contentExtension
isRoot="false"
pattern="com.di.myModel.editor.modelContent"/>
</includes>
</viewerContentBinding>
</extension>

<extension point="org.eclipse.ui.navigator.navigatorContent">
<navigatorContent
activeByDefault="true"
contentProvider="com.di.myModel.project.ProjectAdapterFactoryContentProvider"
id="com.di.myModel.editor.modelContent"
labelProvider="com.di.myModel.project.ProjectAdapterFactoryLabelProvider"
name="Model content"
priority="normal">
<triggerPoints>
<or>
<and>
<instanceof value="org.eclipse.core.resources.IResource"/>
<test
forcePluginActivation="true"
property="org.eclipse.core.resources.extension"
value="core"/>
</and>
<instanceof value="org.eclipse.emf.ecore.resource.Resource"/>
<instanceof value="com.di.myModel.ModelRootObject"/>
</or>
</triggerPoints>
<possibleChildren>
<or>
<instanceof value="org.eclipse.emf.ecore.resource.Resource"/>
<instanceof value="com.di.myModel.ModelRootObject"/>
</or>
</possibleChildren>
</navigatorContent>
</extension>


What I have not attempted is to make the navigation editable. Under the approach shown above, changes in the editor are not reflected in the navigator. In a future article, I will show how to open the editor using the same adapter factory and resource set of the navigator, which should fix this shortcoming.
  Click to reply to this thread Reply
1. At 3:23 AM on Dec 15, 2006, Pankaj M. Tolani Javalobby Newcomers wrote:

Re: Bridging EMF to the common navigator

This article is indeed very nice and helpful. But i had problems running it. I do not see any impact on the ProjectExplorer viewer. And when I create my own viewer, I do not see any resource, view is all empty. (I have a project, which has one of my model files). I have replaced the model name with mine, and qualifying resource with EObject. Also edited createFactoryList to include my ItemProviderAdapterFactory.

I marked breatpoints for getAdapterFactory(), ProjectAdapterFactoryContentProvider(), ProjectAdapterFactoryLabelProvider(), but none of this seem to have been called. How do I debug further? Any pointers are most welcome!

thanks,
pankaj
  Click to reply to this thread Reply
2. At 6:23 AM on May 10, 2007, Giulio Seregni Blooming Javalobby Member wrote:

Re: Bridging EMF to the common navigator

A small notice on the ProjectAdapterFactoryContentProvider class.
The resourceSet shold be declared private and static in this way

static private ResourceSetImpl RESOURCE_SET = new ResourceSetImpl();

to properly work when client use the NavigatorContentService based on our AdapterFactoryContentProvider on other viewers.

Otherwise the contents of resources will be recreated for every viewer.


--
giulio
  Click to reply to this thread Reply
3. At 11:00 AM on Jul 24, 2007, Bene Javalobby Newcomers wrote:

Re: Bridging EMF to the common navigator

> What I have not attempted is to make the navigation
> editable. Under the approach shown above, changes in
> the editor are not reflected in the navigator. In a
> future article, I will show how to open the editor
> using the same adapter factory and resource set of
> the navigator, which should fix this shortcoming.

Can you shortly explain what is neccessary to make the navigation editable and synchronize the navigator with the editor?
That would be great.

thread.rss_message