Sphinx/tutorials
Contents
- 1 Getting Started
- 1.1 Step 1: Getting the example meta-model
- 1.2 Step 2: Creating the plug-in with meta-model descriptor
- 1.3 Step 3: Creating the UI plug-in
- 1.3.1 Step 3.1: Creating the enclosing project
- 1.3.2 Step 3.2: Contributing to the navigator viewer
- 1.3.3 Step 3.3: Contributing to the navigator content
- 1.3.4 Step 3.4: Contributing to the Eclipse editors
- 1.3.5 Step 3.5: Contributing to the Eclipse property contributor
- 1.3.6 Step 3.6: Contributing to the Eclipse property tab
- 1.3.7 Step 3.7: Contributing to the Eclipse property sections
- 2 Model Editing Enhancements
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.
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:
- Open menu File > New > Example... > Eclipse Modeling Framework > Extended Library Model Example
- Click Next >
- Click Finish to generate the three related projects,
org.eclipse.emf.examples.library
,org.eclipse.emf.examples.library.edit
andorg.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
- Open menu File > New > Project... > Plug-In Project and click Next >
- Call it
org.eclipse.sphinx.examples.library.ide
and click Next > - Disable option This plug-in will make contributions to the UI and click on Finish.
Step 2.2: Adding the plug-in dependencies
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide/META-INF
- Select the Dependencies tab
- Add the required plug-in
org.eclipse.sphinx.emf
.
Step 2.3: Creating the class
- Select the package
org.eclipse.sphinx.examples.library.ide
in the new plug-in and create an new class (right-click, then New > Class) - Call it
EXTLibraryMMDescriptor
- Provide its superclass
org.eclipse.sphinx.emf.metamodel.AbstractMetaModelDescriptor
- Click on Finish.
Step 2.4: Filling the class
Fill the class with the following code:
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$ /** * Singleton instance. */ public static final EXTLibraryMMDescriptor INSTANCE = new EXTLibraryMMDescriptor(); /** * Constructor of the class. */ protected EXTLibraryMMDescriptor() { super(ID, NAMESPACE, NAME); } /** * Returns the identifier of the default content type for the described * meta-model. */ @Override public String getDefaultContentTypeId() { return "org.eclipse.emf.examples.library.extendedLibrary"; }
Step 2.5: Contributing to the meta-model descriptor extension point
This plug-in contributes to the meta-model descriptor extension point provided by Sphinx. By this extension point, it declares its own meta-model descriptor.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide/META-INF
- Select the Extensions tab
- 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 - Right-click on org.eclipse.sphinx.emf.metaModelDescriptors and add a new descriptor
- Give the following properties to the descriptor:
- id:
org.eclipse.sphinx.examples.extlibrary
(this is the ID that is used in the constructor of the class we refer in the following property) - class:
org.eclipse.sphinx.examples.library.ide.EXTLibraryMMDescriptor
(this is the name of the class we created just before)
- id:
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
- Open menu File > New > Project... > Plug-In Project and click Next >
- Call it
org.eclipse.sphinx.examples.library.ide.ui
and click Next > - Enable option This plug-in will make contributions to the UI and click on Finish.
Now the project exists and may contribute to extension points.
First, the UI plug-in contributes to the navigator viewer. This extension point offers a way to extend a common viewer and common navigator to support the new meta-model.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- 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 - Eclipse should propose you to add
org.eclipse.ui.navigator
to the list of plug-in dependencies. Click Yes - Right-click on org.eclipse.ui.navigator.viewer and add a new viewerContentBinding
- Give the following property to the viewerContentBinding:
- viewerId:
org.eclipse.sphinx.examples.explorer.views.modelExplorer
(this viewer is declared by plug-inorg.eclipse.sphinx.examples.explorer
)
- viewerId:
- Right-click on org.eclipse.sphinx.examples.explorer.views.modelExplorer (viewerContentBinding) and add a new includes
- Right-click on (includes) and add a new contentExtension
- Give the following property to the contentExtension:
- pattern:
org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.extendedLibrary
- pattern:
The UI plug-in contributes to the navigator content. This extension point offers a way to declare kinds of contents that may appear in the common navigator.
We can note a test in the trigger point declaration to ensure that the elements are in the scope. This enables in particular the visibility from one project to the related projects, but prevents the visibility to other projects.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- In the Dependencies tab of the manifest editor, add the following plug-in to the Required Plug-ins list:
org.eclipse.sphinx.emf.explorer
- 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.navigatorContent
; then click Finish - Right-click on org.eclipse.ui.navigator.navigatorContent and add a new navigatorContent
- Give the following properties to the navigatorContent:
- 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
- id:
- Right-click on Extended Library Content (navigatorContent) and add a new triggerPoints
- Right-click on (triggerPoints) and add a new and
- Right-click on (and) and add a new instanceof
- Give the following property to the instanceof:
- value:
org.eclipse.core.resources.IFile
- value:
- Right-click on (and) and add a new test
- Give the following properties to the test:
- property:
org.eclipse.sphinx.emf.isInScope
- value:
true
- property:
- Right-click on (and) and add a new test
- Give the following properties to the test:
- property:
org.eclipse.sphinx.emf.metaModelIdMatches
- value:
org\.eclipse\.sphinx\.examples\.extlibrary
- property:
- Right-click on Extended Library Content (navigatorContent) and add a new possibleChildren
- Right-click on (possibleChildren) and add a new and
- Right-click on (and) and add a new instanceof
- Give the following property to the instanceof:
- value:
org.eclipse.emf.ecore.EObject
- value:
- Right-click on (and) and add a new test
- Give the following properties to the test:
- property:
org.eclipse.sphinx.emf.classNameMatches
- value:
org\.eclipse\.emf\.examples\.extlibrary\..*
- property:
- Right-click on Extended Library Content (navigatorContent) and add a new dropAssistant
- Give the following properties to the dropAssistant:
- id:
org.eclipse.sphinx.examples.library.ide.ui.navigatorContent.dropAssistant.extendedLibrary
- class:
org.eclipse.sphinx.emf.explorer.BasicDropAdapterAssistant
- id:
- Right-click on (possibleDropTargets) and add a new instanceof
- Give the following property to the instanceof:
- value:
org.eclipse.emf.ecore.EObject
- value:
Step 3.4: Contributing to the Eclipse editors
The UI plug-in contributes to the Eclipse editors. This extension point offers a way to declare a new editor.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- Select the Extensions tab
- Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point
org.eclipse.ui.editors
; then click Finish - In org.eclipse.ui.editors, give 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
- id:
- Right-click on Extended Library Example Editor (editor) and add a new contentTypeBinding
- Give the following property to the contentTypeBinding:
- contentTypeId:
org.eclipse.emf.examples.library.extendedLibrary
(this identifier is declared by plug-inorg.eclipse.emf.examples.library
)
- contentTypeId:
In the Dependencies tab of the manifest editor, add the following plug-in to the Required Plug-ins list:
-
org.eclipse.sphinx.emf.editors.forms
Step 3.5: Contributing to the Eclipse property contributor
The UI plug-in contributes to the property contributor.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- Select the Extensions tab
- Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point
org.eclipse.ui.views.properties.tabbed.propertyContributor
; then click Finish - In org.eclipse.ui.views.properties.tabbed.propertyContributor, give 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
- contributorId:
- Give the following property to the propertyCategory:
- category:
advanced
- category:
In the Dependencies tab of the manifest editor, add the following plug-in to the Required Plug-ins list:
-
org.eclipse.sphinx.examples.common.ui
Step 3.6: Contributing to the Eclipse property tab
The UI plug-in contributes to the property tab.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- Select the Extensions tab
- Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point
org.eclipse.ui.views.properties.tabbed.propertyTabs
; then click Finish - In org.eclipse.ui.views.properties.tabbed.propertyTabs, give the following property to the propertyTabs:
- contributorId:
org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary
- contributorId:
- Give the following properties to the propertyTab:
- label:
Advanced
- category:
advanced
- id:
org.eclipse.sphinx.examples.library.ide.ui.propertyTabs.advanced
- label:
Step 3.7: Contributing to the Eclipse property sections
The UI plug-in contributes to the property sections.
- Open the
MANIFEST.MF
file inorg.eclipse.sphinx.examples.library.ide.ui/META-INF
- Select the Extensions tab
- Click Add..., uncheck option Show only extension points from the required plug-ins and select extension point
org.eclipse.ui.views.properties.tabbed.propertySections
; then click Finish - In org.eclipse.ui.views.properties.tabbed.propertySections, give the following property to the propertySections:
- contributorId:
org.eclipse.sphinx.examples.library.ide.ui.editors.extendedLibrary
- contributorId:
- Give 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
- tab:
- Right-click on org.eclipse.sphinx.examples.library.ide.ui.propertySections.advanced (propertySection) and add a new input
- Give the following property to the input:
- type:
java.lang.Object
- type:
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
[Use Case 1]: 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.
Our approach consist of extending generated item providers without modifying the generated code. A composable adapter factory is generated by the EMF Edit framework and it is used to provide the interfaces needed to support item provider creation in viewers. The following steps should be realized for customizing tree views:
- Step 1 : Creating transient nodes if needed for instance for adding virtual elements in tree views.
- Step 2 : Extending generated item providers for instance to display transient nodes as children of an object.
- Step 3 : Extending generated adapter factories in order to use the extended item providers.
- Step 4 : Creating a new composed adapter factory that adds extended factories in the available adapters list.
- Step 5 : Extending the content and label providers for using the adapter factory created in Step 4.
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 customizations. For instance, we may want to 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:
Figure 1: An extract of the Hummingbird meta-model 2.0.
[Use Case 1.1]: 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:
Figure 2: An example displaying references as children.
We must initially override the getChildren (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) { if (childrenFeatures == null) { 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()
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)); return; 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()
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)); return; case InstanceModel20Package.CONNECTION__TARGET_COMPONENT: fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), true, false)); return; } super.notifyChanged(notification); }
[Use Case 1.2]: 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. For example, we will 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.
Figure 3: An example adding transient nodes.
The following are the main steps for adding non-model intermediary objects into views:
Step 1: Transient Nodes Creation
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 like this:
public ParameterValuesItemProvider(AdapterFactory adapterFactory) { super(adapterFactory); }
- getText(Object object) - for specifying the transient node name:
@Override public String getText(Object object) { return "Parameter Values"; //$NON-NLS-1$ }
- getStyledText(Object object) - for specifying custom style of the text:
@Override public Object getStyledText(Object object) { return new StyledString(getText(object), Style.NO_STYLE); }
- 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; }
Step 2: Item Providers Extension
Create (or open if it already exists) an extended item provider (e.g., ExtendedComponentItemProvider) that extends an existing item provider (e.g., ComponentItemProvider) and change it as follows:
Override the following methods:
- 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) { if (childrenFeatures == null) { 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) { List<Object> children = new ArrayList<Object>(super.getChildren(object)); children.add(adapterFactory.adapt(object, ParameterValuesItemProvider.class)); children.add(adapterFactory.adapt(object, OutgoingConnectionsItemProvider.class)); 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); }
- Add 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 ? adapterFactory.adapt(owner, ParameterValuesItemProvider.class) : adapterFactory.adapt(owner, OutgoingConnectionsItemProvider.class)); } return affected; }}; } return command; }
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 a constructor that calls its super:
public ExtendedParameterValueItemProvider(AdapterFactory adapterFactory) { super(adapterFactory); }
- Override the getParent(Object object) method to return the appropriate transient node:
@Override public Object getParent(Object object) { Object component = super.getParent(object); return adapterFactory.adapt(parent, ParameterValuesItemProvider.class); }
Step 3: Item Provider Adapter Factory Extension
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() { if (componentItemProvider == null) { componentItemProvider = new ExtendedComponentItemProvider(this); } return componentItemProvider; } @Override public Adapter createParameterValueAdapter() { if (parameterValueItemProvider == null) { parameterValueItemProvider = new ExtendedParameterValueItemProvider(this); } return parameterValueItemProvider; } @Override public Adapter createConnectionAdapter() { if (connectionItemProvider == null) { connectionItemProvider = new ExtendedConnectionItemProvider(this); } return connectionItemProvider; }
Adding field for the disposable.
protected Disposable disposable = new Disposable();
Dispose() - for disposing all item providers in the disposable.
@Override public void dispose() { disposable.dispose(); super.dispose(); }
Override the adapt() method to add the (item provider) adapter to disposable.
@Override public Object adapt(Object target, Object type) { Adapter adapter = TransientItemProvider.AdapterFactoryHelper.adapt(target, type, this); if (adapter != null) { disposable.add(adapter); return adapter; } return super.adapt(target, type); }
Override the createAdapter() method to return the corresponding item provider of the given type.
@Override public Adapter createAdapter(Notifier target, Object type) { if (type == ComponentsItemProvider.class) { return new ComponentsItemProvider(this); } if (type == OutgoingConnectionsItemProvider.class) { return new OutgoingConnectionsItemProvider(this); } if (type == ParameterValuesItemProvider.class) { return new ParameterValuesItemProvider(this); } return super.createAdapter(target, type); }
Step 4: Composed Adapter Factory Creation
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() { /** * Singleton instance. */ public static final Hummingbird20ItemProviderAdapterFactory INSTANCE = new Hummingbird20ItemProviderAdapterFactory(); super(ComposedAdapterFactory.Descriptor.Registry.INSTANCE); addAdapterFactory(new ExtendedInstanceModel20ItemProviderAdapterFactory()); } }
In order to avoid having multiple instances of same custom adapter factory, we turn the Hummingbird20ItemProviderAdapterFactory classe into singleton and return this singleton instance as custom adapter factory in ExtendedExplorerContentProvider and ExtendedExplorerLabelProvider to be used in model explorer.
Step 5: Content & Label Providers Extension
public class ExtendedExplorerContentProvider extends BasicExplorerContentProvider { @Override protected AdapterFactory getCustomAdapterFactory() { return Hummingbird20ItemProviderAdapterFactory.INSTANCE; } }
public class ExtendedExplorerLabelProvider extends BasicExplorerLabelProvider { @Override protected AdapterFactory getCustomAdapterFactory() { return Hummingbird20ItemProviderAdapterFactory.INSTANCE; } }
[Use Case 1.3]: 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).
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)
method of the corresponding item provider class (i.e., ExtendedConnectionItemProvider
) like this:
@Override public Collection<? extends EStructuralFeature> getChildrenFeatures(Object object) { if (childrenFeatures == null) { 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.
[UC 2] 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)
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; } }
Figure 5 illustrates the property sheet customization result: