Skip to main content

Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Sphinx/tutorials"

Line 1: Line 1:
==  Model Editing Enhancements ==
+
== Getting Started ==
  
===  Customizing Tree Views  ===
+
This tutorial will guide you through the development of a simple application based on Sphinx. The resulting application is quite simple (1 class, 2 projects, few extension point contributions). However, thanks to the power of Sphinx, it is really functional. To get started, we are going to configure Sphinx to obtain an enhanced couple of navigator and form editor, that allow to navigate efficiently into models and open individually any model element. For the purpose of this tutorial we will use the '''Extended Library Model Example''' provided by EMF as a running example. The following figure illustrates the expected results.
  
The EMF Edit framework and its code generator allow creating easily editors and tree views from EMF models. However, the structure that we want displaying into tree view may be often different to the EMF model structure. The EMF Edit framework provides also mechanisms allowing customizing editors and tree views.  
+
[[Image:Demo-sphinx-navigator.jpg|A demonstration of the resulting navigator]]<br> '''&nbsp;&nbsp;&nbsp; Figure 1: A demonstration of the resulting navigator.'''<br>
  
In the following sections, we’ll describe how to easily customize tree views in order to display customized tree view structure. There are several kings of tree view customization. For instance, we may want displaying object references as children, adding non-model elements or suppressing model objects in tree views. We’ll use an extract of the Hummingbird meta-model to illustrate these kinds of tree views customization, as shown in Figure 1:<br>
+
=== Step 1: Getting the example meta-model ===
  
[[Image:HummingbirdMetaModel20.jpg|An extract of the Hummingbird meta-model 2.0]]<br>
+
The example meta-model is provided by EMF. It consists in three generated plug-ins. Getting them is quite simple:
  
'''&nbsp;&nbsp;&nbsp; Figure 1: An extract of the Hummingbird meta-model 2.0.'''<br>
+
#Open menu File &gt; New &gt; Example... &gt; Eclipse Modeling Framework &gt; Extended Library Model Example;
 +
#Click Next &gt;;
 +
#Click Finish to generate the three related projects, '''org.eclipse.emf.examples.library''', '''org.eclipse.emf.examples.library.edit''' and '''org.eclipse.emf.examples.library.editor'''.
  
==== Displaying References as Children ====
+
=== Step 2: Creating the plug-in with meta-model descriptor ===
  
This section describes how displaying references as children into tree views. For example, we’ll display source port and target component (of a Connection object) as children of objects of Connection type. Realizing this kind of view customization is quite simple. The following figure illustrates this kind of tree view customization:<br>
+
The meta-model descriptor is a key-notion of Sphinx. It consists in a class identifying a meta-model to be used in the workspace. Each application based on Sphinx has to provide such a meta-model descriptor for each meta-model it uses.  
  
[[Image:ReferenceAsChildren.jpg|An example displaying references as children]] <br> '''&nbsp;&nbsp; Figure 2: An example displaying references as children.'''<br>
+
==== Step 2.1: Creating the enclosing project  ====
  
We must initially override the ''getChildren (Object object) ''method of the appropriate item provider (e.g., ''ConnectionItemProvider''. We decide creating an extended class of ''ConnectionItemProvider ''named ''ExtendedConnectionItemProvider'') like this:
+
#Open menu File &gt; New &gt; Project... &gt; Plug-In Project and click Next&nbsp;&gt;
 +
#Call it org.eclipse.sphinx.examples.library.ide and click Next&nbsp;&gt;
 +
#Disable option This plug-in will make contributions to the UI and click on Finish.
  
  @Override
+
==== Step 2.2: Adding the plug-in dependencies  ====
  
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
+
#Edit the MANIFEST.MF file in '''org.eclipse.sphinx.examples.library.ide/META-INF''';  
 +
#In the Dependencies tab, add the required plug-in '''org.eclipse.sphinx.emf'''.
  
    super.getChildrenFeatures(object);
+
==== Step 2.3: Creating the class  ====
  
childrenFeatures.'''add'''(InstanceModel20Package.Literals.CONNECTION__SOURCE_PORT); childrenFeatures.'''add'''(InstanceModel20Package.Literals.CONNECTION__TARGET_COMPONENT); return childrenFeatures;  
+
#Select the package contained by the '''org.eclipse.sphinx.examples.library.ide''' plug-in and create an new class (right-click, then New &gt; Class);  
 +
#Call it '''EXTLibraryMMDescriptor''';
 +
#Provide its superclass '''org.eclipse.sphinx.emf.metamodel.AbstractMetaModelDescriptor''';  
 +
#Click on Finish.
  
}
+
==== Step 2.4: Creating the constructor  ====
  
We must also override the notifyChanged(Notification notification) method of the ExtendedConnectionItemProvider class for refreshing the view if referenced objects (e.g., source port or target component) are set or modified toward the property sheet.
+
Edit the '''EXTLibraryMMDescriptor''' code to add the following default constructor:
  
  @Override
+
private static final String ID = "org.eclipse.sphinx.examples.extlibrary"; //$NON-NLS-1$
 +
private static final String NAMESPACE = "http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"; //$NON-NLS-1$
 +
private static final String NAME = "Extended Library"; //$NON-NLS-1$
  
public void notifyChanged(Notification notification) {  
+
protected EXTLibraryMMDescriptor() {
 +
super(ID, NAMESPACE, NAME);
 +
}
  
    '''updateChildren'''(notification);
+
<br>
  
    // For refreshing the view if source port and/or target component references are updated
+
==== Step 2.5: Contributing to the meta-model descriptor extension point  ====
  
switch (notification.getFeatureID(Connection.class)) {
+
This plug-in contributes to the meta-model descriptor provided by Sphinx.  
  
      case '''InstanceModel20Package.CONNECTION__SOURCE_PORT''':
+
#Open the META-INF/MANIFEST.MF file;
          fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
+
#Select the Extensions tab;
    case '''InstanceModel20Package.CONNECTION__TARGET_COMPONENT''':
+
#Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point ''org.eclipse.sphinx.emf.metaModelDescriptors''; then click Finish;  
          fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
+
#In '''org.eclipse.sphinx.emf.metaModelDescriptors''' add a new ''descriptor'' with the following property:  
          return;
+
#*id '''org.eclipse.sphinx.examples.extlibrary'''
 +
#*class '''org.eclipse.sphinx.examples.library.ide.metamodel.EXTLibraryMMDescriptor'''
  
} super.notifyChanged(notification);
+
=== Step 3: Creating the UI plug-in  ===
  
}
+
Now we will create a second plug-in which deals with all what is related to the user interface. This plug-in does not contain any code. It only contributes to extension points of the Eclipse UI.
  
If referenced objects are displayed as children under a transient node (i.e., a non-model object, please see section 1.1.2 for more details) then we must override in this case the ''notifyChanged(Notification notification) ''method of this transient node for refreshing node content like this:
+
==== Step 3.1: Creating the enclosing project  ====
  
  @Override
+
#Open menu File &gt; New &gt; Project... &gt; Plug-In Project and click Next &gt;;
 +
#Call it '''org.eclipse.sphinx.examples.library.ide.ui''' and click Next &gt;;
 +
#Enable option This plug-in will make contributions to the UI and click Finish.
  
public void notifyChanged(Notification notification) {
+
Now the project exists and may contribute to extension points.
  
    '''updateTransientItemProviderChildren'''(notification, this);
+
==== Step 3.2: Contributing to the navigator viewer  ====
  
    switch (notification.getFeatureID(Connection.class)) {
+
First, the UI plug-in contributes to the navigator viewer.  
  case '''InstanceModel20Package.CONNECTION__SOURCE_PORT''':
+
        fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
+
  case '''InstanceModel20Package.CONNECTION__TARGET_COMPONENT''':
+
        fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
+
        return;
+
  
} super.notifyChanged(notification);
+
#Open the META-INF/MANIFEST.MF file;
 +
#Select the Extensions tab;
 +
#Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point '''org.eclipse.ui.navigator.viewer'''; then click Finish;
 +
#In '''org.eclipse.ui.navigator.viewer''' add a new ''viewerContentBinding'' with the following property:
 +
#*viewerId '''org.eclipse.sphinx.examples.explorer.views.modelExplorer'''
 +
#In '''org.eclipse.sphinx.examples.explorer.views.modelExplorer''' add a new ''includes'';
 +
#In (''includes'') add a new ''contentExtension'' with the following property:
 +
#*pattern '''org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.extendedlibrary'''
  
}
+
==== Step 3.3: Contributing to the navigator content  ====
  
==== Adding Transient Nodes  ====
+
The UI plug-in contributes to the navigator content.
  
This section describes how to easily add transient nodes (i.e., non-model objects) between an object and its children into the tree view. We will for example introduce into the view, as shown in Figure 3, “'''Parameter Values'''and '''Outgoing Connections'''” transient nodes in order to separate children (of ''ParameterValue ''and ''Connection ''types) of Component model objects.  
+
#Click Add... and select extension point '''org.eclipse.ui.navigator.navigatorContent'''; then click Finish;
 +
#In '''org.eclipse.ui.navigator.navigatorContent''' add a new ''navigatorContent'' with the following properties:
 +
#*id '''org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.extendedLibrary'''
 +
#*name '''Extended Library Content'''
 +
#*contentProvider '''org.eclipse.sphinx.emf.explorer.BasicExplorerContentProvider'''
 +
#*labelProvider '''org.eclipse.sphinx.emf.explorer.BasicExplorerLabelProvider'''
 +
#In '''Library Content''' add a new ''triggerPoints'';
 +
#In (''triggerPoints'') add a new ''and'';
 +
#In (''and'') add a new ''instanceof'' with the following property:
 +
#*value '''org.eclipse.core.resources.IFile'''
 +
#In (''and'') add a new ''test'' with the following properties:
 +
#*property '''org.eclipse.sphinx.emf.isInScope'''  
 +
#*value '''true'''
 +
#In (''and'') add a new ''test'' with the following properties:
 +
#*property '''org.eclipse.sphinx.emf.metaModelIdMatches'''
 +
#*value '''org\.eclipse\.sphinx\.examples\.extlibrary'''
 +
#In ''Library Content'' add a new ''possibleChildren'';
 +
#In (''possibleChildren'') add a new ''and'';
 +
#In (''and'') add a new ''instanceof'' with the following property:
 +
#*value '''org.eclipse.emf.ecore.EObject'''
 +
#In (''and'') add a new ''test'' with the following properties:
 +
#*property '''org.eclipse.sphinx.emf.classNameMatches'''
 +
#*value '''org\.eclipse\.emf\.examples\.extlibrary\..*'''
 +
#In ''Library Content'' add a new ''dropAssistant'' with the following properties:
 +
#*id '''org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.dropAssistant.extendedLibrary'''
 +
#*class '''org.eclipse.sphinx.emf.explorer.BasicDropAdapterAssistant'''
 +
#In (''possibleDropTargets'') add a new ''instanceof'' with the following property:
 +
#*value '''org.eclipse.emf.ecore.EObject'''
  
[[Image:SphinxExampleAddingTransientNode.jpg]]
+
==== Step 3.4: Contributing to the Eclipse editors  ====
  
'''Figure 3: An example adding transient nodes.'''
+
The UI plug-in contributes to the Eclipse editors.  
  
The following are the main steps for adding non-model intermediary objects into views:  
+
#Click Add... and select extension point '''org.eclipse.ui.editors'''; then click Finish;
 +
#In '''org.eclipse.ui.editors''' provides the following properties to the editor:
 +
#*id '''org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary'''
 +
#*name '''Extended Library Example Editor'''
 +
#*icon &lt;path to a gif file used as an icon&gt;
 +
#*extensions '''Library, Writer, Book'''
 +
#*class '''org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor'''
 +
#*contributorClass '''org.eclipse.sphinx.emf.editors.forms.BasicTransactionalEditorActionBarContributor'''
 +
#In ''Library Example Editor'' add a new ''contentTypeBinding'' with the following property:  
 +
#*contentTypeId '''org.eclipse.emf.examples.library.extendedLibrary'''
  
'''Create a transient node item provider class''' (e.g. ''ParameterValuesItemProvider'') that extends '''org.eclipse.sphinx.emf.edit.TransientItemProvider''' class and overrides following methods:  
+
==== Step 3.5: Contributing to the Eclipse property contributor  ====
  
*The first thing consists of defining a constructor that calls its super for giving the parent class (e.g., ''Component ''in our example) of the element like this: <br>
+
'''TODO: Explain the object of this extension point.'''  
  
    public ParameterValuesItemProvider(AdapterFactory adapterFactory, '''Component '''component) {
+
The UI plug-in contributes to the property contributor.
  
super(adapterFactory, component);
+
#Click Add... and select extension point '''org.eclipse.ui.views.properties.tabbed.propertyContributor'''; then click Finish;
 +
#In '''org.eclipse.ui.views.properties.tabbed.propertyContributor''' provides the following properties to the ''propertyContributor'':
 +
#*contributorId '''org.eclipse.sphinx.examples.library.ide.ui.editors.extendedlibrary'''
 +
#*labelProvider '''org.eclipse.sphinx.examples.common.ui.providers.AppearanceExampleTabbedPropertySheetTitleProvider'''
 +
#In (''propertyContributor'') provides the following property to the ''propertyCategory'':
 +
#*category '''advanced'''
  
}
+
==== Step 3.6: Contributing to the Eclipse property tab  ====
  
*''getText''(Object object) - for specifying the transient node name:<br>
+
'''TODO: Explain the object of this extension point.'''
  
  @Override
+
The UI plug-in contributes to the property tab.
  
public String getText(Object object) {
+
#Click Add... and select extension point '''org.eclipse.ui.views.properties.tabbed.propertyTabs'''; then click Finish;
 +
#In '''org.eclipse.ui.views.properties.tabbed.propertyTabs''' provides the following property to the propertyTabs:
 +
#*contributorId '''org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary'''
 +
#In (''propertyTabs'') provides the following properties to the propertyTab:
 +
#*label '''Advanced'''
 +
#*category '''advanced'''
 +
#*id '''org.eclipse.sphinx.examples.library.ide.ui.propertyTabs.advanced'''
  
    return "Parameter Values"; //$NON-NLS-1$
+
==== Step 3.7: Contributing to the Eclipse property sections  ====
  
}
+
The UI plug-in contributes to the property sections.
  
*''getChildrenFeatures''(Object object) – for adding children feature (e.g., parameter values from a component) to display as children of the transient node in tree view:
+
#Click Add... and select extension point '''org.eclipse.ui.views.properties.tabbed.propertySections'''; then click Finish;
 +
#In '''org.eclipse.ui.views.properties.tabbed.propertySections''' provide the following property to the ''propertySections'':
 +
#*contributorId '''org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary'''  
 +
#In (''propertySections'') provide the following properties to the ''propertySection'':
 +
#*tab '''org.eclipse.sphinx.examples.library.ide.ui.propertyTabs.advanced'''
 +
#*id '''org.eclipse.sphinx.examples.library.ide.ui.propertySections.advanced'''
 +
#*class '''org.eclipse.sphinx.emf.ui.properties.BasicTransactionalAdvancedPropertySection'''
 +
#In '''org.eclipse.sphinx.examples.library.ide.ui.propertySections.advanced''' add a new input with the following property:  
 +
#*type '''java.lang.Object'''
  
  @Override
+
To test the resulting navigator, launch a runtime workbench, select the ''Model Explorer View'', create a new general project, and then create a library model. Right clic on the model, and choose "Open with Extended Library Example Editor".
  
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
+
<br>
  
    if (childrenFeatures == null) {
+
== &nbsp;&nbsp;Model Editing Enhancements  ==
super.getChildrenFeatures(object);
+
childrenFeatures.'''add'''(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES);
+
  
} return childrenFeatures;  
+
=== &nbsp;Customizing Tree Views  ===
  
}
+
The EMF Edit framework and its code generator allow creating easily editors and tree views from EMF models. However, the structure that we want displaying into tree view may be often different to the EMF model structure. The EMF Edit framework provides also mechanisms allowing customizing editors and tree views.
  
*''collectNewChildDescriptors''(Collection&lt;Object&gt; newChildDescriptors, Object object) – for adding New child actions to the transient node and allowing however creating children (e.g., parameter values) from this transient node.
+
In the following sections, we’ll describe how to easily customize tree views in order to display customized tree view structure. There are several kings of tree view customization. For instance, we may want displaying object references as children, adding non-model elements or suppressing model objects in tree views. We’ll use an extract of the Hummingbird meta-model to illustrate these kinds of tree views customization, as shown in Figure 1:<br>
  
  @Override
+
[[Image:HummingbirdMetaModel20.jpg|An extract of the Hummingbird meta-model 2.0]]<br>
  
protected void collectNewChildDescriptors(Collection&lt;Object&gt; newChildDescriptors, Object object) {
+
'''&nbsp;&nbsp;&nbsp; Figure 1: An extract of the Hummingbird meta-model 2.0.'''<br>
  
    super.collectNewChildDescriptors(newChildDescriptors, object);
+
==== Displaying References as Children  ====
  
    newChildDescriptors.'''add'''(createChildParameter(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES, 
+
This section describes how displaying references as children into tree views. For example, we’ll display source port and target component (of a Connection object) as children of objects of Connection type. Realizing this kind of view customization is quite simple. The following figure illustrates this kind of tree view customization:<br>
                      InstanceModel20Factory.eINSTANCE.createParameterValue()));
+
  
}
+
[[Image:ReferenceAsChildren.jpg|An example displaying references as children]] <br> '''&nbsp;&nbsp; Figure 2: An example displaying references as children.'''<br>
  
*''createDragAndDropCommand''(EditingDomain domain, Object owner, float location, int operations, int operation, Collection&lt;?&gt; collection) – for enabling dropping only possible children into the transient node.
+
We must initially override the ''getChildren (Object object) ''method of the appropriate item provider (e.g., ''ConnectionItemProvider''. We decide creating an extended class of ''ConnectionItemProvider ''named ''ExtendedConnectionItemProvider'') like this:
  
 
   @Override
 
   @Override
 +
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
 +
  super.getChildrenFeatures(object);
 +
  childrenFeatures.'''add'''(InstanceModel20Package.Literals.CONNECTION__SOURCE_PORT);
 +
  ChildrenFeatures.'''add'''(InstanceModel20Package.Literals.CONNECTION__TARGET_COMPONENT);
 +
  return childrenFeatures;
 +
  }
  
protected Command createDragAndDropCommand(EditingDomain domain, Object owner, float location, int operations, int operation, Collection&lt;?&gt; collection) {
+
We must also override the notifyChanged(Notification notification) method of the ExtendedConnectionItemProvider class for refreshing the view if referenced objects (e.g., source port or target component) are set or modified toward the property sheet.
  
     if (new '''AddCommand'''(domain, (EObject) owner, InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES, collection).'''canExecute'''()) {
+
  @Override
return super.createDragAndDropCommand(domain, owner, location, operations, operation, collection);
+
public void notifyChanged(Notification notification) {
 +
     '''updateChildren'''(notification);
 +
    // For refreshing the view if source port and/or target component references are update
 +
    switch (notification.getFeatureID(Connection.class)) {
 +
    case '''InstanceModel20Package.CONNECTION__SOURCE_PORT''':
 +
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 +
    case '''InstanceModel20Package.CONNECTION__TARGET_COMPONENT''':
 +
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 +
    return;
 +
    } super.notifyChanged(notification);
 +
}
  
} return UnexecutableCommand.INSTANCE;
+
If referenced objects are displayed as children under a transient node (i.e., a non-model object, please see section 1.1.2 for more details) then we must override in this case the ''notifyChanged(Notification notification) ''method of this transient node for refreshing node content like this:
 
+
}
+
 
+
*''getResourceLocator()'' for returning the resource locator for item provider's resources using specific plug-in Activator (e.g., org.eclipse.sphinx.examples.hummingbird20.edit.Activator).
+
  
 
   @Override
 
   @Override
 +
public void notifyChanged(Notification notification) {
 +
'''updateTransientItemProviderChildren'''(notification, this);
 +
switch (notification.getFeatureID(Connection.class)) {
 +
case '''InstanceModel20Package.CONNECTION__SOURCE_PORT''':
 +
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 +
  case '''InstanceModel20Package.CONNECTION__TARGET_COMPONENT''':
 +
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 +
    return;
 +
    } super.notifyChanged(notification);
 +
}
  
public ResourceLocator getResourceLocator() {
+
==== Adding Transient Nodes  ====
  
    return Activator.INSTANCE;
+
This section describes how to easily add transient nodes (i.e., non-model objects) between an object and its children into the tree view. We will for example introduce into the view, as shown in Figure 3, “'''Parameter Values'''” and “'''Outgoing Connections'''” transient nodes in order to separate children (of ''ParameterValue ''and ''Connection ''types) of Component model objects.  
  
}
+
[[Image:SphinxExampleAddingTransientNode.jpg]]
  
'''Create (or modify if exist) an extended item provider''' (e.g., ExtendedComponentItemProvider) that extends an existing item provider (e.g., ''ComponentItemProvider'') and overrides following methods:
+
'''Figure 3: An example adding transient nodes.'''  
  
*The first thing consists of adding required fields corresponding to transient nodes which are displaying as children of ''Component ''elements.
+
The following are the main steps for adding non-model intermediary objects into views:
  
  protected ParameterValuesItemProvider parameterValuesItemProvider;
+
'''Create a transient node item provider class''' (e.g. ''ParameterValuesItemProvider'') that extends '''org.eclipse.sphinx.emf.edit.TransientItemProvider''' class and overrides following methods:
  
protected OutgoingConnectionsItemProvider outgoingConnectionsItemProvider;
+
*The first thing consists of defining a constructor that calls its super for giving the parent class (e.g., ''Component ''in our example) of the element like this: <br>
  
*''getChildrenFeatures(Object object)'' – for no longer displaying directly ''ParameterValue ''and outgoing ''Connection ''objects as children of component objects into the view:
+
    public ParameterValuesItemProvider(AdapterFactory adapterFactory, '''Component '''component) {
 +
  super(adapterFactory, component);
 +
  }
 +
 
 +
*''getText''(Object object) - for specifying the transient node name:<br>
  
 
   @Override
 
   @Override
 +
  public String getText(Object object) {
 +
  return "Parameter Values"; //$NON-NLS-1$
 +
  }
  
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
+
*''getChildrenFeatures''(Object object) – for adding children feature (e.g., parameter values from a component) to display as children of the transient node in tree view:
  
    super.getChildrenFeatures(object);
+
  @Override
 +
  public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
 +
  if (childrenFeatures == null) {
 +
  super.getChildrenFeatures(object); childrenFeatures.'''add'''(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES);
 +
  } return childrenFeatures;
 +
  }
  
childrenFeatures.'''remove'''(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES); childrenFeatures.'''remove'''(InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS); return childrenFeatures;
+
*''collectNewChildDescriptors''(Collection&lt;Object&gt; newChildDescriptors, Object object) – for adding New child actions to the transient node and allowing however creating children (e.g., parameter values) from this transient node.
  
}  
+
  @Override
 +
  protected void collectNewChildDescriptors(Collection&lt;Object&gt; newChildDescriptors, Object object) {
 +
  super.collectNewChildDescriptors(newChildDescriptors, object);
 +
newChildDescriptors.'''add'''(createChildParameter(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES,InstanceModel20Factory.eINSTANCE.createParameterValue()));
 +
}  
  
*''getChildren(Object object)'' – for adding transient nodes (e.g., “'''Parameter Values'''” or “'''Outgoing Connections'''”) as children of component objects:
+
*''createDragAndDropCommand''(EditingDomain domain, Object owner, float location, int operations, int operation, Collection&lt;?&gt; collection) – for enabling dropping only possible children into the transient node.
  
  @Override
+
  @Override
 +
protected Command createDragAndDropCommand(EditingDomain domain, Object owner, float location, int operations, int operation, Collection&lt;?&gt; collection) {
 +
if (new '''AddCommand'''(domain, (EObject) owner, InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES, collection).'''canExecute'''()) {
 +
return super.createDragAndDropCommand(domain, owner, location, operations, operation, collection);
 +
}
 +
return UnexecutableCommand.INSTANCE;
 +
}
  
public Collection&lt;?&gt; getChildren(Object object) {
+
*''getResourceLocator()'' – for returning the resource locator for item provider's resources using specific plug-in Activator (e.g., org.eclipse.sphinx.examples.hummingbird20.edit.Activator).
  
    if (parameterValuesItemProvider == null) {
+
  @Override
  parameterValuesItemProvider = new ParameterValuesItemProvider(adapterFactory, (Component) object);
+
public ResourceLocator getResourceLocator() {  
 +
return Activator.INSTANCE;
 +
}
  
} if (outgoingConnectionsItemProvider == null) {
+
'''Create (or modify if exist) an extended item provider''' (e.g., ExtendedComponentItemProvider) that extends an existing item provider (e.g., ''ComponentItemProvider'') and overrides following methods:
  
    outgoingConnectionsItemProvider = new OutgoingConnectionsItemProvider(adapterFactory, (Component) object);
+
*The first thing consists of adding required fields corresponding to transient nodes which are displaying as children of ''Component ''elements.
  
}
+
  protected ParameterValuesItemProvider parameterValuesItemProvider;
 +
  protected OutgoingConnectionsItemProvider outgoingConnectionsItemProvider;
  
    List&lt;Object&gt; children = new ArrayList&lt;Object&gt;(super.getChildren(object));
+
*''getChildrenFeatures(Object object)'' – for no longer displaying directly ''ParameterValue ''and outgoing ''Connection ''objects as children of component objects into the view:
  
children.'''add'''(parameterValuesItemProvider); children.'''add'''(outgoingConnectionsItemProvider);  
+
  @Override
 +
  public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {
 +
  super.getChildrenFeatures(object);
 +
childrenFeatures.'''remove'''(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES);
 +
  childrenFeatures.'''remove'''(InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS); return childrenFeatures;
 +
  }
  
    return children;
+
*''getChildren(Object object)'' – for adding transient nodes (e.g., “'''Parameter Values'''” or “'''Outgoing Connections'''”) as children of component objects:
  
}  
+
  @Override
 +
  public Collection&lt;?&gt; getChildren(Object object) {
 +
  if (parameterValuesItemProvider == null) {
 +
  parameterValuesItemProvider = new ParameterValuesItemProvider(adapterFactory, (Component) object);
 +
  }
 +
  if (outgoingConnectionsItemProvider == null) {
 +
  outgoingConnectionsItemProvider = new OutgoingConnectionsItemProvider(adapterFactory, (Component) object);
 +
  }
 +
  List&lt;Object&gt; children = new ArrayList&lt;Object&gt;(super.getChildren(object));
 +
  children.'''add'''(parameterValuesItemProvider); children.'''add'''(outgoingConnectionsItemProvider);
 +
  return children;
 +
  }  
  
 
*''createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection, int index)'' and ''createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection)'' for setting the selection (i.e., the affected object) when adding or removing elements containing in transient nodes. The selection must be in this case the appropriate transient node.
 
*''createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection, int index)'' and ''createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection)'' for setting the selection (i.e., the affected object) when adding or removing elements containing in transient nodes. The selection must be in this case the appropriate transient node.
  
 
   @Override
 
   @Override
 
+
  protected Command createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection, int index) {  
protected Command createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection, int index) {  
+
  return createWrappedCommand(super.createAddCommand(domain, owner, feature, collection, index), owner, feature);
 
+
  }  
    return createWrappedCommand(super.createAddCommand(domain, owner, feature, collection, index), owner, feature);
+
 
+
}  
+
  
 
   @Override
 
   @Override
 
+
  protected Command createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection) {
protected Command createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection&lt;?&gt; collection) {  
+
  return createWrappedCommand(super.createRemoveCommand(domain, owner, feature, collection), owner, feature);
 
+
  }  
    return createWrappedCommand(super.createRemoveCommand(domain, owner, feature, collection), owner, feature);
+
 
+
}  
+
  
 
*Adds the ''createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature)'' method returning the appropriate transient node (i.e., the item provider) and the “real” affected object is its owner (e.g., the component object).
 
*Adds the ''createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature)'' method returning the appropriate transient node (i.e., the item provider) and the “real” affected object is its owner (e.g., the component object).
  
 
     protected Command createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature) {
 
     protected Command createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature) {
 
+
  if (feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES ||  
if (feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES ||  
+
  feature == InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS) {
 
+
  return '''new CommandWrapper'''(command) {
    feature == InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS) {
+
  @Override
  return '''new CommandWrapper'''(command) {
+
  public Collection&lt;?&gt; '''getAffectedObjects()''' {
      @Override
+
  Collection&lt;?&gt; affected = super.getAffectedObjects();
      public Collection&lt;?&gt; '''getAffectedObjects()''' {
+
      if (affected.contains(owner)) {
          Collection&lt;?&gt; affected = super.getAffectedObjects();
+
      affected = Collections.singleton(feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES&nbsp;? getParameterValues()&nbsp;: getOutgoingConnections());  
          if (affected.contains(owner)) {
+
      }
              affected = Collections.singleton(feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES&nbsp;?  
+
      return affected;
 
+
      }};
getParameterValues()&nbsp;: getOutgoingConnections());  
+
      } return command;  
 
+
  }  
                }
+
          return affected;
+
      }};
+
 
+
} return command;  
+
 
+
}  
+
  
 
*''dispose()'' – for disposing any remaining children wrappers (including transient nodes) in the children store.
 
*''dispose()'' – for disposing any remaining children wrappers (including transient nodes) in the children store.
  
 
   @Override
 
   @Override
 
+
  public void dispose() {  
public void dispose() {  
+
  super.dispose();
 
+
  if (parameterValuesItemProvider&nbsp;!= null &amp;&amp; outgoingConnectionsItemProvider&nbsp;!= null) {  
    super.dispose();
+
  ((IDisposable) parameterValuesItemProvider).dispose();
 
+
  ((IDisposable) outgoingConnectionsItemProvider).dispose();
if (parameterValuesItemProvider&nbsp;!= null &amp;&amp; outgoingConnectionsItemProvider&nbsp;!= null) {  
+
  }  
 
+
  }  
  ((IDisposable) parameterValuesItemProvider).dispose();
+
((IDisposable) outgoingConnectionsItemProvider).dispose();
+
 
+
}  
+
 
+
}  
+
  
 
*Adds getters methods returning transient node fields (i.e., transient item providers)
 
*Adds getters methods returning transient node fields (i.e., transient item providers)
  
 
   public Object getParameterValues() {
 
   public Object getParameterValues() {
 
+
return parameterValuesItemProvider;  
return parameterValuesItemProvider;  
+
}  
 
+
}  
+
public Object getOutgoingConnections() {  
 
+
return outgoingConnectionsItemProvider;
public Object getOutgoingConnections() {  
+
}  
 
+
    return outgoingConnectionsItemProvider;
+
 
+
}  
+
  
 
'''Create (or modify if exist) an extended item provider for each child of the transient node'''(e.g., ''ExtendedParameterValueItemProvider ''or ''ExtendedConnectionItemProvider ''classes) that extends existing item providers (e.g., respectively ''ParameterValueItemProvider ''or ''ConnectionItemProvider''):  
 
'''Create (or modify if exist) an extended item provider for each child of the transient node'''(e.g., ''ExtendedParameterValueItemProvider ''or ''ExtendedConnectionItemProvider ''classes) that extends existing item providers (e.g., respectively ''ParameterValueItemProvider ''or ''ConnectionItemProvider''):  
Line 271: Line 380:
  
 
   public ExtendedParameterValueItemProvider(AdapterFactory adapterFactory) {
 
   public ExtendedParameterValueItemProvider(AdapterFactory adapterFactory) {
 
+
  super(adapterFactory);  
super(adapterFactory);  
+
  }  
 
+
}  
+
  
 
*Overrides the ''getParent(Object object)'' method to return the appropriate transient node:
 
*Overrides the ''getParent(Object object)'' method to return the appropriate transient node:
  
 
   @Override
 
   @Override
 
+
  public Object getParent(Object object) {  
public Object getParent(Object object) {  
+
  Object component = super.getParent(object);
 
+
  ExtendedComponentItemProvider componentItemProvider = (ExtendedComponentItemProvider) adapterFactory.adapt(component, IEditingDomainItemProvider.class); return componentItemProvider&nbsp;!= null&nbsp;? componentItemProvider.getParameterValues()&nbsp;: null;  
    Object component = super.getParent(object);
+
  }  
 
+
ExtendedComponentItemProvider componentItemProvider = (ExtendedComponentItemProvider) adapterFactory.adapt(component, IEditingDomainItemProvider.class); return componentItemProvider&nbsp;!= null&nbsp;? componentItemProvider.getParameterValues()&nbsp;: null;  
+
 
+
}  
+
  
 
'''Create (or modify if exist) an extended item provider adapter factory''' (e.g., ''ExtendedInstanceModel20ItemProviderAdapterFactory'' class) that extends an existing adapter factory (e.g., ''InstanceModel20ItemProviderAdapterFactory'') and overrides methods allowing creating item providers to be use (for example objects of Component, ParameterValue or Connection types) and returning the appropriate extended item providers.  
 
'''Create (or modify if exist) an extended item provider adapter factory''' (e.g., ''ExtendedInstanceModel20ItemProviderAdapterFactory'' class) that extends an existing adapter factory (e.g., ''InstanceModel20ItemProviderAdapterFactory'') and overrides methods allowing creating item providers to be use (for example objects of Component, ParameterValue or Connection types) and returning the appropriate extended item providers.  
  
 
   @Override
 
   @Override
 +
  public Adapter createComponentAdapter() {
 +
  return new ExtendedComponentItemProvider(this);
 +
  }
  
public Adapter createComponentAdapter() {
+
@Override
 
+
public Adapter createParameterValueAdapter() {  
    return new ExtendedComponentItemProvider(this);
+
return new ExtendedParameterValueItemProvider(this);
 
+
}  
}
+
 
+
@Override  
@Override
+
public Adapter createConnectionAdapter() {  
 
+
return new ExtendedConnectionItemProvider(this);
public Adapter createParameterValueAdapter() {  
+
}  
 
+
    return new ExtendedParameterValueItemProvider(this);
+
 
+
}  
+
 
+
@Override public Adapter createConnectionAdapter() {  
+
 
+
    return new ExtendedConnectionItemProvider(this);
+
 
+
}  
+
  
 
'''Add the new created extended item provider adapter factory to those to be use''' (i.e., adds ''ExtendedInstanceModel20ItemProviderAdapterFactory'' to ''Hummingbird20ItemProviderAdapterFactory'' adapter factories to be use. Hummingbird20ItemProviderAdapterFactory must be used to give custom adapter factory in content and label provider classes.  
 
'''Add the new created extended item provider adapter factory to those to be use''' (i.e., adds ''ExtendedInstanceModel20ItemProviderAdapterFactory'' to ''Hummingbird20ItemProviderAdapterFactory'' adapter factories to be use. Hummingbird20ItemProviderAdapterFactory must be used to give custom adapter factory in content and label provider classes.  
  
 
   public class Hummingbird20ItemProviderAdapterFactory extends ComposedAdapterFactory {
 
   public class Hummingbird20ItemProviderAdapterFactory extends ComposedAdapterFactory {
 
+
  public '''Hummingbird20ItemProviderAdapterFactory'''() {  
public '''Hummingbird20ItemProviderAdapterFactory'''() {  
+
  super(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
 
+
  addAdapterFactory(new '''ExtendedInstanceModel20ItemProviderAdapterFactory'''());
    super(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
+
  }
  addAdapterFactory(new '''ExtendedInstanceModel20ItemProviderAdapterFactory'''());
+
  }  
 
+
}  
+
 
+
}  
+
  
 
==== Suppressing Model Objects in views  ====
 
==== Suppressing Model Objects in views  ====
Line 336: Line 428:
  
 
   @Override
 
   @Override
 
+
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {  
public Collection&lt;? extends EStructuralFeature&gt; getChildrenFeatures(Object object) {  
+
super.getChildrenFeatures(object);
 
+
childrenFeatures.'''remove'''(Common20Package.Literals.IDENTIFIABLE__DESCRIPTION); return childrenFeatures;  
    super.getChildrenFeatures(object);
+
}  
 
+
childrenFeatures.'''remove'''(Common20Package.Literals.IDENTIFIABLE__DESCRIPTION); return childrenFeatures;  
+
 
+
}  
+
  
 
A similar change can be done in the collectNewChildDescriptors(Collection&lt;Object&gt; newChildDescriptors, Object object) method for suppressing New child menu action allowing creating a Description element.  
 
A similar change can be done in the collectNewChildDescriptors(Collection&lt;Object&gt; newChildDescriptors, Object object) method for suppressing New child menu action allowing creating a Description element.  
Line 354: Line 442:
  
 
  @Override
 
  @Override
 
 
public List&lt;IItemPropertyDescriptor&gt; getPropertyDescriptors(Object object) {  
 
public List&lt;IItemPropertyDescriptor&gt; getPropertyDescriptors(Object object) {  
 
+
if (itemPropertyDescriptors == null) {
  if (itemPropertyDescriptors == null) {
+
super.getPropertyDescriptors(object);  
super.getPropertyDescriptors(object);
+
Port sourcePort = ((Connection) object).getSourcePort();
 
+
if (sourcePort&nbsp;!= null) {  
      Port sourcePort = ((Connection) object).getSourcePort();
+
addRequiredInterface(sourcePort.getRequiredInterface(), getString("_UI_Port_requiredInterface_feature"));  
if (sourcePort&nbsp;!= null) {
+
}  
    addRequiredInterface(sourcePort.getRequiredInterface(), getString("_UI_Port_requiredInterface_feature"));  
+
} return itemPropertyDescriptors;  
}
+
 
+
} return itemPropertyDescriptors;  
+
 
+
 
}  
 
}  
  
 
   private void addRequiredInterface(Interface requiredInterface, final String featureName) {
 
   private void addRequiredInterface(Interface requiredInterface, final String featureName) {
 
+
InterfaceItemProvider interfaceItemProvider = (InterfaceItemProvider) ((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory().adapt(requiredInterface, IItemPropertySource.class);  
InterfaceItemProvider interfaceItemProvider = (InterfaceItemProvider) ((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory().adapt(requiredInterface, IItemPropertySource.class); if (interfaceItemProvider&nbsp;!= null) {  
+
if (interfaceItemProvider&nbsp;!= null) {  
 
+
List&lt;IItemPropertyDescriptor&gt; descriptors = interfaceItemProvider.getPropertyDescriptors(requiredInterface);
    List&lt;IItemPropertyDescriptor&gt; descriptors = interfaceItemProvider.getPropertyDescriptors(requiredInterface);
+
for (IItemPropertyDescriptor descriptor&nbsp;: descriptors) {
+
for (IItemPropertyDescriptor descriptor&nbsp;: descriptors) {  
    itemPropertyDescriptors.add(new ItemPropertyDescriptorDecorator(requiredInterface, descriptor) {
+
itemPropertyDescriptors.add(new ItemPropertyDescriptorDecorator(requiredInterface, descriptor) {
        @Override
+
    @Override
        public String getCategory(Object thisObject) {
+
      public String getCategory(Object thisObject) {
              return featureName;
+
        return featureName;
        }
+
      }
 
+
      @Override
              @Override
+
      public String getId(Object thisObject) {
        public String getId(Object thisObject) {
+
        return featureName + getDisplayName(thisObject);
            return featureName + getDisplayName(thisObject);
+
      }
        }
+
  });
    });
+
  }
}
+
  }
 
+
}  
+
 
+
 
}  
 
}  
  
Line 395: Line 475:
  
 
   public class ExtendedTransactionalAdvancedPropertySection extends BasicTransactionalAdvancedPropertySection {
 
   public class ExtendedTransactionalAdvancedPropertySection extends BasicTransactionalAdvancedPropertySection {
 
+
 
protected AdapterFactory adapterFactory; @Override protected AdapterFactory getCustomAdapterFactory() {  
+
  protected AdapterFactory adapterFactory; @Override protected AdapterFactory getCustomAdapterFactory() {
 
+
  if (adapterFactory == null) {
    if (adapterFactory == null) {
+
  adapterFactory = new Hummingbird20ItemProviderAdapterFactory();
      adapterFactory = new Hummingbird20ItemProviderAdapterFactory();
+
  }
  }
+
  return adapterFactory;
  return adapterFactory;
+
  }  
 
+
  }  
}  
+
 
+
}  
+
  
 
The Figure 5 illustrates the property sheet customization result:  
 
The Figure 5 illustrates the property sheet customization result:  

Revision as of 10:51, 27 January 2012

Getting Started

This tutorial will guide you through the development of a simple application based on Sphinx. The resulting application is quite simple (1 class, 2 projects, few extension point contributions). However, thanks to the power of Sphinx, it is really functional. To get started, we are going to configure Sphinx to obtain an enhanced couple of navigator and form editor, that allow to navigate efficiently into models and open individually any model element. For the purpose of this tutorial we will use the Extended Library Model Example provided by EMF as a running example. The following figure illustrates the expected results.

A demonstration of the resulting navigator
    Figure 1: A demonstration of the resulting navigator.

Step 1: Getting the example meta-model

The example meta-model is provided by EMF. It consists in three generated plug-ins. Getting them is quite simple:

  1. Open menu File > New > Example... > Eclipse Modeling Framework > Extended Library Model Example;
  2. Click Next >;
  3. Click Finish to generate the three related projects, org.eclipse.emf.examples.library, org.eclipse.emf.examples.library.edit and org.eclipse.emf.examples.library.editor.

Step 2: Creating the plug-in with meta-model descriptor

The meta-model descriptor is a key-notion of Sphinx. It consists in a class identifying a meta-model to be used in the workspace. Each application based on Sphinx has to provide such a meta-model descriptor for each meta-model it uses.

Step 2.1: Creating the enclosing project

  1. Open menu File > New > Project... > Plug-In Project and click Next >
  2. Call it org.eclipse.sphinx.examples.library.ide and click Next >
  3. Disable option This plug-in will make contributions to the UI and click on Finish.

Step 2.2: Adding the plug-in dependencies

  1. Edit the MANIFEST.MF file in org.eclipse.sphinx.examples.library.ide/META-INF;
  2. In the Dependencies tab, add the required plug-in org.eclipse.sphinx.emf.

Step 2.3: Creating the class

  1. Select the package contained by the org.eclipse.sphinx.examples.library.ide plug-in and create an new class (right-click, then New > Class);
  2. Call it EXTLibraryMMDescriptor;
  3. Provide its superclass org.eclipse.sphinx.emf.metamodel.AbstractMetaModelDescriptor;
  4. Click on Finish.

Step 2.4: Creating the constructor

Edit the EXTLibraryMMDescriptor code to add the following default constructor:

private static final String ID = "org.eclipse.sphinx.examples.extlibrary"; //$NON-NLS-1$

private static final String NAMESPACE = "http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"; //$NON-NLS-1$ private static final String NAME = "Extended Library"; //$NON-NLS-1$

protected EXTLibraryMMDescriptor() { super(ID, NAMESPACE, NAME); }


Step 2.5: Contributing to the meta-model descriptor extension point

This plug-in contributes to the meta-model descriptor provided by Sphinx.

  1. Open the META-INF/MANIFEST.MF file;
  2. Select the Extensions tab;
  3. Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point org.eclipse.sphinx.emf.metaModelDescriptors; then click Finish;
  4. In org.eclipse.sphinx.emf.metaModelDescriptors add a new descriptor with the following property:
    • id org.eclipse.sphinx.examples.extlibrary
    • class org.eclipse.sphinx.examples.library.ide.metamodel.EXTLibraryMMDescriptor

Step 3: Creating the UI plug-in

Now we will create a second plug-in which deals with all what is related to the user interface. This plug-in does not contain any code. It only contributes to extension points of the Eclipse UI.

Step 3.1: Creating the enclosing project

  1. Open menu File > New > Project... > Plug-In Project and click Next >;
  2. Call it org.eclipse.sphinx.examples.library.ide.ui and click Next >;
  3. Enable option This plug-in will make contributions to the UI and click Finish.

Now the project exists and may contribute to extension points.

Step 3.2: Contributing to the navigator viewer

First, the UI plug-in contributes to the navigator viewer.

  1. Open the META-INF/MANIFEST.MF file;
  2. Select the Extensions tab;
  3. Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point org.eclipse.ui.navigator.viewer; then click Finish;
  4. In org.eclipse.ui.navigator.viewer add a new viewerContentBinding with the following property:
    • viewerId org.eclipse.sphinx.examples.explorer.views.modelExplorer
  5. In org.eclipse.sphinx.examples.explorer.views.modelExplorer add a new includes;
  6. In (includes) add a new contentExtension with the following property:
    • pattern org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.extendedlibrary

Step 3.3: Contributing to the navigator content

The UI plug-in contributes to the navigator content.

  1. Click Add... and select extension point org.eclipse.ui.navigator.navigatorContent; then click Finish;
  2. In org.eclipse.ui.navigator.navigatorContent add a new navigatorContent with the following properties:
    • id org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.extendedLibrary
    • name Extended Library Content
    • contentProvider org.eclipse.sphinx.emf.explorer.BasicExplorerContentProvider
    • labelProvider org.eclipse.sphinx.emf.explorer.BasicExplorerLabelProvider
  3. In Library Content add a new triggerPoints;
  4. In (triggerPoints) add a new and;
  5. In (and) add a new instanceof with the following property:
    • value org.eclipse.core.resources.IFile
  6. In (and) add a new test with the following properties:
    • property org.eclipse.sphinx.emf.isInScope
    • value true
  7. In (and) add a new test with the following properties:
    • property org.eclipse.sphinx.emf.metaModelIdMatches
    • value org\.eclipse\.sphinx\.examples\.extlibrary
  8. In Library Content add a new possibleChildren;
  9. In (possibleChildren) add a new and;
  10. In (and) add a new instanceof with the following property:
    • value org.eclipse.emf.ecore.EObject
  11. In (and) add a new test with the following properties:
    • property org.eclipse.sphinx.emf.classNameMatches
    • value org\.eclipse\.emf\.examples\.extlibrary\..*
  12. In Library Content add a new dropAssistant with the following properties:
    • id org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.dropAssistant.extendedLibrary
    • class org.eclipse.sphinx.emf.explorer.BasicDropAdapterAssistant
  13. In (possibleDropTargets) add a new instanceof with the following property:
    • value org.eclipse.emf.ecore.EObject

Step 3.4: Contributing to the Eclipse editors

The UI plug-in contributes to the Eclipse editors.

  1. Click Add... and select extension point org.eclipse.ui.editors; then click Finish;
  2. In org.eclipse.ui.editors provides the following properties to the editor:
    • id org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary
    • name Extended Library Example Editor
    • icon <path to a gif file used as an icon>
    • extensions Library, Writer, Book
    • class org.eclipse.sphinx.emf.editors.forms.BasicTransactionalFormEditor
    • contributorClass org.eclipse.sphinx.emf.editors.forms.BasicTransactionalEditorActionBarContributor
  3. In Library Example Editor add a new contentTypeBinding with the following property:
    • contentTypeId org.eclipse.emf.examples.library.extendedLibrary

Step 3.5: Contributing to the Eclipse property contributor

TODO: Explain the object of this extension point.

The UI plug-in contributes to the property contributor.

  1. Click Add... and select extension point org.eclipse.ui.views.properties.tabbed.propertyContributor; then click Finish;
  2. In org.eclipse.ui.views.properties.tabbed.propertyContributor provides the following properties to the propertyContributor:
    • contributorId org.eclipse.sphinx.examples.library.ide.ui.editors.extendedlibrary
    • labelProvider org.eclipse.sphinx.examples.common.ui.providers.AppearanceExampleTabbedPropertySheetTitleProvider
  3. In (propertyContributor) provides the following property to the propertyCategory:
    • category advanced

Step 3.6: Contributing to the Eclipse property tab

TODO: Explain the object of this extension point.

The UI plug-in contributes to the property tab.

  1. Click Add... and select extension point org.eclipse.ui.views.properties.tabbed.propertyTabs; then click Finish;
  2. In org.eclipse.ui.views.properties.tabbed.propertyTabs provides the following property to the propertyTabs:
    • contributorId org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary
  3. In (propertyTabs) provides the following properties to the propertyTab:
    • label Advanced
    • category advanced
    • id org.eclipse.sphinx.examples.library.ide.ui.propertyTabs.advanced

Step 3.7: Contributing to the Eclipse property sections

The UI plug-in contributes to the property sections.

  1. Click Add... and select extension point org.eclipse.ui.views.properties.tabbed.propertySections; then click Finish;
  2. In org.eclipse.ui.views.properties.tabbed.propertySections provide the following property to the propertySections:
    • contributorId org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary
  3. In (propertySections) provide the following properties to the propertySection:
    • tab org.eclipse.sphinx.examples.library.ide.ui.propertyTabs.advanced
    • id org.eclipse.sphinx.examples.library.ide.ui.propertySections.advanced
    • class org.eclipse.sphinx.emf.ui.properties.BasicTransactionalAdvancedPropertySection
  4. In org.eclipse.sphinx.examples.library.ide.ui.propertySections.advanced add a new input with the following property:
    • type java.lang.Object

To test the resulting navigator, launch a runtime workbench, select the Model Explorer View, create a new general project, and then create a library model. Right clic on the model, and choose "Open with Extended Library Example Editor".


  Model Editing Enhancements

 Customizing Tree Views

The EMF Edit framework and its code generator allow creating easily editors and tree views from EMF models. However, the structure that we want displaying into tree view may be often different to the EMF model structure. The EMF Edit framework provides also mechanisms allowing customizing editors and tree views.

In the following sections, we’ll describe how to easily customize tree views in order to display customized tree view structure. There are several kings of tree view customization. For instance, we may want displaying object references as children, adding non-model elements or suppressing model objects in tree views. We’ll use an extract of the Hummingbird meta-model to illustrate these kinds of tree views customization, as shown in Figure 1:

An extract of the Hummingbird meta-model 2.0

    Figure 1: An extract of the Hummingbird meta-model 2.0.

Displaying References as Children

This section describes how displaying references as children into tree views. For example, we’ll display source port and target component (of a Connection object) as children of objects of Connection type. Realizing this kind of view customization is quite simple. The following figure illustrates this kind of tree view customization:

An example displaying references as children
   Figure 2: An example displaying references as children.

We must initially override the getChildren (Object object) method of the appropriate item provider (e.g., ConnectionItemProvider. We decide creating an extended class of ConnectionItemProvider named ExtendedConnectionItemProvider) like this:

 @Override
public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) {
  super.getChildrenFeatures(object);
  childrenFeatures.add(InstanceModel20Package.Literals.CONNECTION__SOURCE_PORT);
  ChildrenFeatures.add(InstanceModel20Package.Literals.CONNECTION__TARGET_COMPONENT); 
  return childrenFeatures; 
  } 

We must also override the notifyChanged(Notification notification) method of the ExtendedConnectionItemProvider class for refreshing the view if referenced objects (e.g., source port or target component) are set or modified toward the property sheet.

 @Override
public void notifyChanged(Notification notification) { 
   updateChildren(notification);
   // For refreshing the view if source port and/or target component references are update
   switch (notification.getFeatureID(Connection.class)) {
   	case InstanceModel20Package.CONNECTION__SOURCE_PORT:
   	fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
   	case InstanceModel20Package.CONNECTION__TARGET_COMPONENT:
   	fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
   	return;
   } super.notifyChanged(notification);
} 

If referenced objects are displayed as children under a transient node (i.e., a non-model object, please see section 1.1.2 for more details) then we must override in this case the notifyChanged(Notification notification) method of this transient node for refreshing node content like this:

 @Override
public void notifyChanged(Notification notification) { 
	updateTransientItemProviderChildren(notification, this);
	switch (notification.getFeatureID(Connection.class)) {
		case InstanceModel20Package.CONNECTION__SOURCE_PORT:
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
 		case InstanceModel20Package.CONNECTION__TARGET_COMPONENT:
    fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false));
    return;
    } super.notifyChanged(notification); 
} 

Adding Transient Nodes

This section describes how to easily add transient nodes (i.e., non-model objects) between an object and its children into the tree view. We will for example introduce into the view, as shown in Figure 3, “Parameter Values” and “Outgoing Connections” transient nodes in order to separate children (of ParameterValue and Connection types) of Component model objects.

SphinxExampleAddingTransientNode.jpg

Figure 3: An example adding transient nodes.

The following are the main steps for adding non-model intermediary objects into views:

Create a transient node item provider class (e.g. ParameterValuesItemProvider) that extends org.eclipse.sphinx.emf.edit.TransientItemProvider class and overrides following methods:

  • The first thing consists of defining a constructor that calls its super for giving the parent class (e.g., Component in our example) of the element like this:
   public ParameterValuesItemProvider(AdapterFactory adapterFactory, Component component) {
  	super(adapterFactory, component); 
  } 
  • getText(Object object) - for specifying the transient node name:
  @Override
 public String getText(Object object) { 
 		return "Parameter Values"; //$NON-NLS-1$
 	} 
  • getChildrenFeatures(Object object) – for adding children feature (e.g., parameter values from a component) to display as children of the transient node in tree view:
  @Override
 public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) { 
 		if (childrenFeatures == null) {
 		super.getChildrenFeatures(object); 		childrenFeatures.add(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES); 
 		} return childrenFeatures; 
 	} 
  • collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) – for adding New child actions to the transient node and allowing however creating children (e.g., parameter values) from this transient node.
  @Override
 protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) { 
 		super.collectNewChildDescriptors(newChildDescriptors, object);

newChildDescriptors.add(createChildParameter(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES,InstanceModel20Factory.eINSTANCE.createParameterValue())); }

  • createDragAndDropCommand(EditingDomain domain, Object owner, float location, int operations, int operation, Collection<?> collection) – for enabling dropping only possible children into the transient node.
 @Override
protected Command createDragAndDropCommand(EditingDomain domain, Object owner, float location, int operations, int operation, Collection<?> collection) { 
		if (new AddCommand(domain, (EObject) owner, InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES, collection).canExecute()) {
		return super.createDragAndDropCommand(domain, owner, location, operations, operation, collection); 
		} 
		return UnexecutableCommand.INSTANCE; 
} 
  • getResourceLocator() – for returning the resource locator for item provider's resources using specific plug-in Activator (e.g., org.eclipse.sphinx.examples.hummingbird20.edit.Activator).
 @Override
public ResourceLocator getResourceLocator() { 
		return Activator.INSTANCE;
} 

Create (or modify if exist) an extended item provider (e.g., ExtendedComponentItemProvider) that extends an existing item provider (e.g., ComponentItemProvider) and overrides following methods:

  • The first thing consists of adding required fields corresponding to transient nodes which are displaying as children of Component elements.
  protected ParameterValuesItemProvider parameterValuesItemProvider;
 protected OutgoingConnectionsItemProvider outgoingConnectionsItemProvider; 
  • getChildrenFeatures(Object object) – for no longer displaying directly ParameterValue and outgoing Connection objects as children of component objects into the view:
  @Override
 public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) { 
 		super.getChildrenFeatures(object);
		childrenFeatures.remove(InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES);
 		childrenFeatures.remove(InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS); return childrenFeatures; 
 	} 
  • getChildren(Object object) – for adding transient nodes (e.g., “Parameter Values” or “Outgoing Connections”) as children of component objects:
  @Override
 public Collection<?> getChildren(Object object) {
 		if (parameterValuesItemProvider == null) {
 			parameterValuesItemProvider = new ParameterValuesItemProvider(adapterFactory, (Component) object);
 			} 
 		if (outgoingConnectionsItemProvider == null) { 
 			outgoingConnectionsItemProvider = new OutgoingConnectionsItemProvider(adapterFactory, (Component) object);
 			}
 		List<Object> children = new ArrayList<Object>(super.getChildren(object));
 		children.add(parameterValuesItemProvider); children.add(outgoingConnectionsItemProvider); 
 		return children;
 	} 
  • createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection, int index) and createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection) for setting the selection (i.e., the affected object) when adding or removing elements containing in transient nodes. The selection must be in this case the appropriate transient node.
  @Override
 protected Command createAddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection, int index) { 
 		return createWrappedCommand(super.createAddCommand(domain, owner, feature, collection, index), owner, feature);
 	} 
  @Override
 protected Command createRemoveCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection<?> collection) {
 		return createWrappedCommand(super.createRemoveCommand(domain, owner, feature, collection), owner, feature);
 	} 
  • Adds the createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature) method returning the appropriate transient node (i.e., the item provider) and the “real” affected object is its owner (e.g., the component object).
   protected Command createWrappedCommand(Command command, final EObject owner, final EStructuralFeature feature) {
  if (feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES || 
  feature == InstanceModel20Package.Literals.COMPONENT__OUTGOING_CONNECTIONS) {
  		return new CommandWrapper(command) {
  		@Override
  		public Collection<?> getAffectedObjects() {
  			Collection<?> affected = super.getAffectedObjects();
     		if (affected.contains(owner)) {
     			affected = Collections.singleton(feature == InstanceModel20Package.Literals.COMPONENT__PARAMETER_VALUES ? getParameterValues() : getOutgoingConnections()); 
     			}
     		return affected;
     	}};
     } return command; 
  } 
  • dispose() – for disposing any remaining children wrappers (including transient nodes) in the children store.
  @Override
 public void dispose() { 
 		super.dispose();
 		if (parameterValuesItemProvider != null && outgoingConnectionsItemProvider != null) { 
 			((IDisposable) parameterValuesItemProvider).dispose();
 			((IDisposable) outgoingConnectionsItemProvider).dispose();
 		} 
 	} 
  • Adds getters methods returning transient node fields (i.e., transient item providers)
 public Object getParameterValues() {
		return parameterValuesItemProvider; 
} 

public Object getOutgoingConnections() { 
		return outgoingConnectionsItemProvider;
} 

Create (or modify if exist) an extended item provider for each child of the transient node(e.g., ExtendedParameterValueItemProvider or ExtendedConnectionItemProvider classes) that extends existing item providers (e.g., respectively ParameterValueItemProvider or ConnectionItemProvider):

  • Creates a constructor that calls its super:
  public ExtendedParameterValueItemProvider(AdapterFactory adapterFactory) {
 		super(adapterFactory); 
 	} 
  • Overrides the getParent(Object object) method to return the appropriate transient node:
  @Override
 public Object getParent(Object object) { 
 		Object component = super.getParent(object);
 		ExtendedComponentItemProvider componentItemProvider = (ExtendedComponentItemProvider) adapterFactory.adapt(component, IEditingDomainItemProvider.class); return componentItemProvider != null ? componentItemProvider.getParameterValues() : null; 
 	} 

Create (or modify if exist) an extended item provider adapter factory (e.g., ExtendedInstanceModel20ItemProviderAdapterFactory class) that extends an existing adapter factory (e.g., InstanceModel20ItemProviderAdapterFactory) and overrides methods allowing creating item providers to be use (for example objects of Component, ParameterValue or Connection types) and returning the appropriate extended item providers.

  @Override
 public Adapter createComponentAdapter() { 
 		return new ExtendedComponentItemProvider(this);
 } 
	@Override

public Adapter createParameterValueAdapter() { return new ExtendedParameterValueItemProvider(this); }

@Override public Adapter createConnectionAdapter() { return new ExtendedConnectionItemProvider(this); }

Add the new created extended item provider adapter factory to those to be use (i.e., adds ExtendedInstanceModel20ItemProviderAdapterFactory to Hummingbird20ItemProviderAdapterFactory adapter factories to be use. Hummingbird20ItemProviderAdapterFactory must be used to give custom adapter factory in content and label provider classes.

  public class Hummingbird20ItemProviderAdapterFactory extends ComposedAdapterFactory {
 		public Hummingbird20ItemProviderAdapterFactory() { 
 			super(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
 			addAdapterFactory(new ExtendedInstanceModel20ItemProviderAdapterFactory());
 		}
 	} 

Suppressing Model Objects in views

It may often happen to want suppressing certain model objects from tree views. For example, elements of Connection or ParameterValue type may have a child of Description type (which can also have a child of Text type). We decide in our example to not display elements of Description type in the tree view. The following figure illustrates the current tree view (in the left side) and the improved tree view (in the right side).

SphinxExampleSuppressingModelObject.jpg

Figure 4: An example suppressing Description model objects into the view.

To suppress the Description element (and its children) as child of an element of Connection type from the view, we may override the getChildrenFeatures(Object object) method of the corresponding item provider class (i.e., ExtendedConnectionItemProvider) like this:

 @Override
public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) { 
		super.getChildrenFeatures(object);
		childrenFeatures.remove(Common20Package.Literals.IDENTIFIABLE__DESCRIPTION); return childrenFeatures; 
} 

A similar change can be done in the collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) method for suppressing New child menu action allowing creating a Description element.

Customizing Object Property Sheet

In Section 1.1.3, we saw how suppressing model objects in tree views. The information from these suppressed elements may be displayed as properties of their parent or grandparent object. This allows for instance the user to set or modify values of these properties. The information of children that are not suppressed can also be displayed. For example, an element of connection type has a source port that requires one interface. We can display for example the required interface as property of the connection element.

For displaying children properties to their parent object, we can override the List<IItemPropertyDescriptor> getPropertyDescriptors(Object object) method of the ExtendedConnectionItemProvider class like this:

@Override

public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object) { if (itemPropertyDescriptors == null) { super.getPropertyDescriptors(object); Port sourcePort = ((Connection) object).getSourcePort(); if (sourcePort != null) { addRequiredInterface(sourcePort.getRequiredInterface(), getString("_UI_Port_requiredInterface_feature")); } } return itemPropertyDescriptors; }

 private void addRequiredInterface(Interface requiredInterface, final String featureName) {
		InterfaceItemProvider interfaceItemProvider = (InterfaceItemProvider) ((ComposeableAdapterFactory) adapterFactory).getRootAdapterFactory().adapt(requiredInterface, IItemPropertySource.class); 
		if (interfaceItemProvider != null) { 
			List<IItemPropertyDescriptor> descriptors = interfaceItemProvider.getPropertyDescriptors(requiredInterface);
		
			for (IItemPropertyDescriptor descriptor : descriptors) { 
				itemPropertyDescriptors.add(new ItemPropertyDescriptorDecorator(requiredInterface, descriptor) {
    			@Override
     		public String getCategory(Object thisObject) {
        		return featureName;
     		}
     		@Override
     		public String getId(Object thisObject) {
        		return featureName + getDisplayName(thisObject);
     		}
 			});
 		}
 	}

}

In the addRequiredInterface() method that adds the required interface as property of element of Connection type, we delegate to the appropriate item provider (e.g. InterfaceItemProvider) for getting the required property descriptors. We override however, in our example, the getCategory() method of the created ItemPropertyDescriptorDecorator for grouping the children properties in a specific category. For having unique identifier for each children property, we override also the getId() method of the created ItemPropertyDescriptorDecorator. In the advanced property section, we must use the “right” adapter factory (e.g. Hummingbird20ItemProviderAdapterFactory). We must however create (or use) an extended class of org.eclipse.sphinx.emf.ui.properties.BasicTransactionalAdvancedPropertySection and use it in the specified Eclipse property section contribution. The ExtendedTransactionalAdvancedPropertySection class is defined as follows:

  public class ExtendedTransactionalAdvancedPropertySection extends BasicTransactionalAdvancedPropertySection {
 
 		protected AdapterFactory adapterFactory; @Override protected AdapterFactory getCustomAdapterFactory() {
 			if (adapterFactory == null) {
 				adapterFactory = new Hummingbird20ItemProviderAdapterFactory();
 			}
 			return adapterFactory;
 		} 
 	} 

The Figure 5 illustrates the property sheet customization result:

SphinxExampleCustomizePropertySheet.JPG

Figure 5: An example of customizing property sheet.

Back to the top