Viewpoint – Provide custom style

  1. Viewpoint - Provide custom style
    1. Goals
    2. StyleConfiguration
      1. The StyleConfiguration interface
        1. adaptNodeLabel
        2. getBorderItemLocatorProvider
        3. getNameBorderItemLocator
        4. adaptViewNodeSizeWithLabel
        5. getAnchorProvider
        6. getLabelIcon
        7. fitToText
      2. Providing custom StyleConfiguration
        1. Providers of StyleConfiguration
      3. Example of a StyleConfiguration implementation
    3. GMF extension points, CustomStyle and EditPartProvider
    4. GMF extension points
      1. Edit Part Provider
      2. Edit Policy Provider

Goals

Viewpoint provides tools to design and display diagrams. These diagrams are essentially composed of figures of distinct styles
and shapes and, even though the tooling initially allows for the usage of a wide array of styles, many diagrams will still require
customized styles to conform to the company’s theme.

Viewpoint offers three distinct ways of customizing its graphical styles :

  1. the StyleConfiguration extension point.
  2. the CustomStyle in addition to the EditPartProvider GMF extension point.
  3. the GMF-provided extension points.

StyleConfiguration

StyleConfiguration is a mechanism that enables the customization of a specific style. It aims at providing support for different
ways of displaying labels, anchors, ...

The StyleConfiguration interface

This interface defines a set of methods that need be implemented in order for the syle to be customizable:

adaptNodeLabel

This method can be used to alter the size and location of a given label according to a given node.

getBorderItemLocatorProvider

This method returns the instance currently providing border item locators for the node. A border item is a node located on the border
of another node.

getNameBorderItemLocator

This method returns the item locator for the label of the node. This method is meaningless if the position of the label isn’t BORDER.

adaptViewNodeSizeWithLabel

This method returns the minimum width a node needs to be correctly displayed with its label.

getAnchorProvider

This method returns the instance providing connections anchors.

getLabelIcon

This method returns the icon that will displayed for this element’s representations.

fitToText

This method returns the optimal dimension of the node.

Providing custom StyleConfiguration

The StyleConfiguration mechanism is only available for ViewNode\ s at the moment. Default configurations are initially
installed on nodes.

SimpleStyleConfiguration

This configuration is the simplest implementation.

SquareStyleConfiguration

This is the minimal configuration for nodes using the BundledImage style with a square shape.

SimpleSquareStyleConfiguration

This is the minimal configuration for nodes with a Square style.

Providers of StyleConfiguration

Installing your own configurations can be done through the fr.obeo.dsl.viewpoint.diagram.styleConfigurationProvider extension
point. This extension point requires only one attribute : the qualified name of the provider class.

   <extension point="fr.obeo.dsl.viewpoint.diagram.styleConfigurationProvider">
      <styleConfigurationProvider
            providerClass="com.thalesgroup.melody.diagseq.style.DiagSeqStyleConfigurationProvider">
      </styleConfigurationProvider>
   </extension>


Here is a sample of the extension tab of the PDE editor when filling in this extension point :

This example records the DiagSeqStyleConfigurationProvider as a configuration provider. This class must implement the
IStyleConfigrationProvider interface.

The latter interface defines two methods :

provides(mapping : DiagramElementMapping, style : Style) : boolean

This method returns true if the provider provides a configuration for the given mapping and style.

createStyleConfiguration(mapping : DiagramElementMapping, style : Style) : StyleConfiguration

This method creates a StyleConfiguration for the specified mapping and style.


Here is an example of a provider :

	/**
	 * The Sequence Diagram style configuration provider.
	 * 
	 * @author ymortier
	 */
	public class DiagSeqStyleConfigurationProvider implements IStyleConfigurationProvider {
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.IStyleConfigurationProvider#createStyleConfiguration(
	     *		viewpoint.description.ViewPointElementMapping,
	     *      viewpoint.Style)
	     */
	    public StyleConfiguration createStyleConfiguration(DiagramElementMapping mapping, Style style) {
	        if (mapping instanceof NodeMapping) {
	            NodeMapping nodeMapping = (NodeMapping) mapping;
	            if (nodeMapping.getName() != null && nodeMapping.getName().equals(DiagSeqConstants.INSTANCE_ROLE_MAPPING_NAME)) {
	                return new InstanceRoleStyleConfiguration();
	            }
	            if (nodeMapping.getName() != null && nodeMapping.getName().equals(DiagSeqConstants.EXECUTION_MAPPING_NAME)) {
	                return new ExecutionSpecificationStyleConfiguration();
	            }
	        }
	        return null;
	    }
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.IStyleConfigurationProvider#provides(viewpoint.description.ViewPointElementMapping,
	     *      viewpoint.Style)
	     */
	    public boolean provides(DiagramElementMapping mapping, Style style) {
	        return mapping instanceof NodeMapping && ((NodeMapping) mapping).getName() != null
	                && (((NodeMapping) mapping).getName().equals(DiagSeqConstants.INSTANCE_ROLE_MAPPING_NAME) 
	                	|| DiagSeqConstants.EXECUTION_MAPPING_NAME.equals(((NodeMapping) mapping).getName()));
	    }
	}


Example of a StyleConfiguration implementation

	/**
	 * A simple configuration. Do nothing.
	 * 
	 * @author ymortier
	 */
	public class SimpleStyleConfiguration implements StyleConfiguration {
	
	    /**
	     * {@inheritDoc}
	     *
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#adaptNodeLabel(
	     * 		viewpoint.ViewNode, org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel)
	     */
	    public void adaptNodeLabel(DNode node, WrapLabel nodeLabel) {
	        if (nodeLabel.getParent() != null) {
	            Rectangle constraint = nodeLabel.getParent().getBounds().getCopy();
	
	            Insets borderDimension = this.getBorderDimension(node);
	            constraint.height -= (borderDimension.top + borderDimension.bottom);
	            constraint.width -= (borderDimension.left + borderDimension.right);
	            constraint.x += borderDimension.left;
	            constraint.y += borderDimension.top;
	
	            nodeLabel.setBounds(constraint);
	            nodeLabel.getParent().setConstraint(nodeLabel, constraint);
	        }
	    }
	
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#adaptViewNodeSizeWithLabel(viewpoint.ViewNode,
	     *      org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel)
	     */
	    public int adaptViewNodeSizeWithLabel(DNode viewNode, WrapLabel nodeLabel, int nodeWidth) {
	        if (viewNode.getResizeKind() != ResizeKind.NONE_LITERAL) {
	
	        }
	        return nodeWidth;
	    }
		
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#getAnchorProvider()
	     */
	    public AnchorProvider getAnchorProvider() {
	        return null;
	    }
	
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#getBorderItemLocatorProvider()
	     */
	    public BorderItemLocatorProvider getBorderItemLocatorProvider() {
	        return DefaultBorderItemLocatorProvider.getInstance();
	    }
	
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#getNameBorderItemLocator(viewpoint.ViewNode)
	     */
	    public IBorderItemLocator getNameBorderItemLocator(DNode node, IFigure mainFigure) {
	        BorderItemLocator locator = new AirBorderItemLocator(mainFigure, PositionConstants.NSEW);
	        locator.setBorderItemOffset(new Dimension(1, 1));
	        return locator;
	    }
	
	    /**
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#getLabelIcon(viewpoint.ViewPointElement)
	     */
	    public Image getLabelIcon(DDiagramElement vpElement) {
	        EObject target = vpElement;
	        if (vpElement instanceof DSemanticDecorator) {
	            target = ((DSemanticDecorator) vpElement).getTarget();
	        }
	        if (isShowIcon(vpElement)) {
	            if (target != null) {
	                IItemLabelProvider labelProvider = (IItemLabelProvider) ViewpointDiagramEditorPlugin.getInstance()
	                		.getItemProvidersAdapterFactory().adapt(target, IItemLabelProvider.class);
	                if (labelProvider != null) {
	                    ImageDescriptor descriptor = ExtendedImageRegistry.getInstance().getImageDescriptor(labelProvider.getImage(target));
	                    if (descriptor == null) {
	                        descriptor = ImageDescriptor.getMissingImageDescriptor();
	                    }
	                    return ViewpointDiagramEditorPlugin.getInstance().getImage(descriptor);
	                }
	            }
	        }
	        return null;
	    }
	
	    /**
	     * Return <code>true</code> if the icon of the specified
	     * {@link ViewPointElement} is shown.
	     * 
	     * @param vpElement
	     *            the {@link ViewPointElement}.
	     * @return <code>true</code> if the icon of the specified
	     *         {@link ViewPointElement} is shown.
	     */
	    protected boolean isShowIcon(DDiagramElement vpElement) {
	        if (vpElement instanceof MappingBased) {
	            DiagramElementMapping vpElementMapping = ((MappingBased) vpElement).getMapping();
	            if (vpElementMapping instanceof NodeMapping) {
	                return ((NodeMapping) vpElementMapping).isShowIcon();
	            }
	            if (vpElementMapping instanceof EdgeMapping) {
	                return ((EdgeMapping) vpElementMapping).isShowIcon();
	            }
	            if (vpElementMapping instanceof ContainerMapping) {
	                return true;
	            }
	        }
	        return false;
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see viewpoint.diagram.graphical.edit.styles.api.StyleConfiguration#fitToText(viewpoint.ViewNode,
	     *      org.eclipse.gmf.runtime.draw2d.ui.figures.WrapLabel,
	     *      org.eclipse.gmf.runtime.gef.ui.figures.DefaultSizeNodeFigure)
	     */
	    public Dimension fitToText(DNode node, WrapLabel nodeLabel, DefaultSizeNodeFigure defaultSizeNodeFigure) {
	        if (nodeLabel.getFont() != null) {
	            String text = node.getName();
	
	            int charHeight = FigureUtilities.getStringExtents("ABCDEF", nodeLabel.getFont()).height + 5;
	            int charWidth = FigureUtilities.getTextWidth("ABCDEFGHIJKLMNOPQRSTUVWXYZ", nodeLabel.getFont()) / 26;
	
	            double ratio = charHeight / charWidth;
	
	            int nbLines = (int) (Math.sqrt(text.length()) / ratio) + 1;
	            int nbCols = (int) (Math.sqrt(text.length()) * ratio) + 1;
	
	            int longestWord = this.getTheLongestWord(text.split("\\s"));
	            nbCols = Math.max(nbCols, longestWord);
	
	            int hHeight = nbLines * charHeight;
	            int hWidth = nbCols * charWidth;
	
	            Dimension size = nodeLabel.getPreferredSize(hWidth + nodeLabel.getIconBounds().width + 
	            		nodeLabel.getIconTextGap(), hHeight).getCopy();
	
	            size.width += 20;
	            size.height += 30;
	
	            Insets borderDimension = this.getBorderDimension(node);
	            size.width += (borderDimension.left + borderDimension.right);
	            size.height += (borderDimension.top + borderDimension.bottom);
	
	            //
	            // Square ?
	            if (node.getHeight().intValue() == node.getWidth().intValue()) {
	                // size.width = Math.max(size.height, size.width);
	                // size.height = Math.max(size.height, size.width);
	            }
	
	            return size;
	        }
	        return defaultSizeNodeFigure.getBounds().getSize().getCopy();
	    }
	
	    private int getTheLongestWord(String[] strings) {
	        int max = -1;
	        for (int i = 0; i < strings.length; i++) {
	            if (strings[i].length() > max) {
	                max = strings[i].length();
	            }
	        }
	        return max;
	    }
	
	    /**
	     * Return the dimension of the border.
	     * 
	     * @param nodeth
	     *            view node.
	     * @return the dimension of the border.
	     */
	    public Insets getBorderDimension(DNode node) {
	        return new Insets(0, 0, 0, 0);
	    }
	
	}


The easiest way to implement your own configuration is to make it a sub class of SimpleStyleConfiguration.

GMF extension points, CustomStyle and EditPartProvider

CustomStyle is a style that can be applied to a node. Its only property is id that is a string value. By default,
applying a CustomStyle will have a Green Square be displayed. A custom EditPart describing the appearance of the node
must be implemented.

Here is how to apply a CustomStyle :

Next step is to create and record an EditPart to define the way this style will be managed.

An EditPart is a GEF class. It references both a model element and the shape that represents it. GMF adds a layer to GEF
and exposes its own EditPart API. The base type of this API is IGraphicalEditPart (in package
org.eclipse.gmf.runtime.diagram.ui.editparts). Here are the main methods this interface defines :

resolveSemanticElement() : EObject
This method returns the semantic element of the edit part. The type of this semantic element is a type contained by the
Viewpoint package (see ViewpointPackage). For instance, if we were to write an EditPart for our CustomStyle,
the semantic element would be the said CustomStyle. It is possible to get the ViewNode with it and, then, the target
element (namely, a Melody object).

getNotationView() : View
This method returns the GMF View of the edit part. This is the view that will be saved into the GMF Diagram.

All Custom Style Edit Part must implement the IStyleEditPart interface.
Semanticly, a Style Edit Part should not be selectable : it is selected when the Shape or Connector that contains it is selected.
Therefore, all Custom Style Edit Part should override the isSelectable() method and return false . If you can, inherit from the abstrac class AbstractNotSelectableShapeNodeEditPart that already overrides correctly this method.

Here is a sample of a Custom Style Edit Part :

	/**
	 * A custom StyleEditPart that will display different pictures according to its
	 * related semantic element's name.
	 */
	public class InstanceRoleStyleEditPart extends AbstractNotSelectableShapeNodeEditPart implements IStyleEditPart {
	
	    /**
	     * the content pane.
	     */
	    protected IFigure contentPane;
	
	    /**
	     * the primary shape.
	     */
	    protected ImageFigure primaryShape;
	
	    /**
	     * Create a new {@link ChangingImageEditPart}.
	     * 
	     * @param view
	     *            the view.
	     */
	    public InstanceRoleStyleEditPart(View view) {
	        super(view);
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart#getDragTracker(org.eclipse.gef.Request)
	     */
	    public DragTracker getDragTracker(Request request) {
	        return getParent().getDragTracker(request);
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart#createNodeFigure()
	     */
	    protected NodeFigure createNodeFigure() {
	        NodeFigure figure = createNodePlate();
	        figure.setLayoutManager(new XYLayout());
	        IFigure shape = createNodeShape();
	        figure.add(shape);
	        contentPane = setupContentPane(shape);
	        return figure;
	    }
	
	    /**
	     * @not-generated
	     */
	    private NodeFigure createNodePlate() {
	        DefaultSizeNodeFigure result = new AirStyleDefaultSizeNodeFigure(getMapMode().DPtoLP(40), getMapMode().DPtoLP(40));
	        return result;
	    }
	
	    /**
	     * Create the instance role figure.
	     * 
	     * @return the created figure.
	     */
	    protected ImageFigure createNodeShape() {
	        if (primaryShape == null) {
	            primaryShape = new ImageFigure();
	        }
	        return primaryShape;
	    }
	
	    /**
	     * Return the instance role figure.
	     * 
	     * @return the instance role figure.
	     */
	    public ImageFigure getPrimaryShape() {
	        return primaryShape;
	    }
	
	    /**
	     * Default implementation treats passed figure as content pane. Respects
	     * layout one may have set for generated figure.
	     * 
	     * @param nodeShape
	     *            instance of generated figure class
	     * @return the figure
	     */
	    protected IFigure setupContentPane(IFigure nodeShape) {
	        return nodeShape; // use nodeShape itself as contentPane
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#getContentPane()
	     */
	    public IFigure getContentPane() {
	        if (contentPane != null) {
	            return contentPane;
	        }
	        return super.getContentPane();
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeEditPart#refreshVisuals()
	     */
	    protected void refreshVisuals() {
	        CustomStyle customStyle = (CustomStyle) this.resolveSemanticElement();
	        if (customStyle.eContainer() instanceof DNode) {
	            this.getPrimaryShape().setImage(ViewpointPlugin.getDefault().getBundledImage(((DNode) customStyle.eContainer()).getName()));
	        }
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart#createDefaultEditPolicies()
	     */
	    protected void createDefaultEditPolicies() {
	        // empty.
	    }
	}
	


We now have to notify Viewpoint that we are providing a new EditPart for nodes having a CustomStyle of that id.
The GMF extension mechanism can be used to achieve this.

plugin.xml :

	<extension point="org.eclipse.gmf.runtime.diagram.ui.editpartProviders">
		<editpartProvider class="com.thalesgroup.melody.diagseq.provider.DiagSeqEditPartProvider">
       		<Priority name="High"/>
	    </editpartProvider>
	</extension>


The provider class ( com.thalesgroup.melody.diagseq.provider.DiagSeqEditPartProvider) extends the GMF class
org.eclipse.gmf.runtime.diagram.ui.services.editpart.AbstractEditPartProvider. Our custom Edit part will be
provided by overriding getNodeEditPartClass. Here is how this class looks like :

	/**
	 * Provides edit part for the UML2 modeler.
	 * 
	 * @author ymortier
	 */
	public class DiagSeqEditPartProvider extends AbstractEditPartProvider {
	    /**
	     * Create the Lifeline Edit Part.
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.services.editpart.AbstractEditPartProvider#getNodeEditPartClass(
	     *		org.eclipse.gmf.runtime.notation.View)
	     */
	    @Override
	    protected Class getNodeEditPartClass(View view) {
	        if (view.getElement() instanceof CustomStyle) {
	            CustomStyle customStyle = (CustomStyle) view.getElement();
	            if (customStyle.getId().equals(DiagSeqConstants.INSTANCE_ROLE_STYLE_ID)) {
	                return InstanceRoleStyleEditPart.class;
	            }
	        }
	        return super.getNodeEditPartClass(view);
	    }
	}


Where DiagSeqConstants.INSTANCE_ROLE_STYLE_ID is the id of our custom style.

In the modeler, the result looks like this :

GMF extension points

GMF exposes all of the necessary API to extend the default behavior of a modeler.

Edit Part Provider

We saw earlier how to provide custom edit parts. Here is how the result looks like in Viewpoint.

Snapshot of the Viewpoint meta-model :

The types DNode, DNodeContainer, DNodeList, DNodeListElement, etc. have their own edit parts :

Edit Policy Provider

Edit Policies are objects responsible for the handling of user actions. There are Edit Policies for different behaviors :

As with edit parts, it is necessary to write an Edit Policy Provider as well as the Edit Policy that is to be provided. The
Edit Policy Provider must implement the IEditPolicyProvider interface :

public void addProviderChangeListener(IProviderChangeListener listener)
Registers a listener on the provider.

public boolean provides(IOperation operation)
Returns true if this instance provides edit policies for the specified operation.

public void removeProviderChangeListener(IProviderChangeListener listener)
Removes a listener from this provider.

public void createEditPolicies(EditPart editPart)
Adds edit policies on the specified edit part.

Here is an example of an Edit Policy Provider

	/**
	 * Provides Edit Policy for Note Attachment.
	 * 
	 * @author ymortier
	 */
	public class AirNoteAttachmentEditPolicyProvider implements IEditPolicyProvider {
	
	    /** the property change support. */
	    private List listeners;
	
	    /**
	     * Create a new {@link AirNoteAttachmentEditPolicyProvider}.
	     */
	    public AirNoteAttachmentEditPolicyProvider() {
	        this.listeners = new ArrayList(2);
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.diagram.ui.services.editpolicy.IEditPolicyProvider#createEditPolicies(org.eclipse.gef.EditPart)
	     */
	    public void createEditPolicies(EditPart editPart) {
	        if (editPart instanceof NoteAttachmentEditPart) {
	            editPart.installEditPolicy(EditPolicy.CONNECTION_ROLE, new AirNoteAttachmentEditPolicy());
	        }
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.common.core.service.IProvider#addProviderChangeListener(org.eclipse.gmf.runtime.common.core.service.IProviderChangeListener)
	     */
	    public void addProviderChangeListener(IProviderChangeListener listener) {
	        this.listeners.add(listener);
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.common.core.service.IProvider#provides(org.eclipse.gmf.runtime.common.core.service.IOperation)
	     */
	    public boolean provides(IOperation operation) {
	        if (operation instanceof CreateEditPoliciesOperation) {
	            CreateEditPoliciesOperation castedOperation = (CreateEditPoliciesOperation) operation;
	            EditPart editPart = castedOperation.getEditPart();
	            Object model = editPart.getModel();
	            if (model instanceof View) {
	                View view = (View) model;
	                if (view.getDiagram() != null && view.getDiagram().getElement() != null
	                        && view.getDiagram().getElement().eClass().getEPackage().getNsURI().equals(ViewpointPackage.eINSTANCE.getNsURI())) {
	                    if ("NoteAttachment".equals(view.getType())) {
	                        return true;
	                    }
	                }
	            }
	        }
	        return false;
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.common.core.service.IProvider#removeProviderChangeListener(org.eclipse.gmf.runtime.common.core.service.IProviderChangeListener)
	     */
	    public void removeProviderChangeListener(IProviderChangeListener listener) {
	        this.listeners.remove(listener);
	    }
	
	    /**
	     * Fire a {@link ProviderChangeEvent}.
	     */
	    protected void fireProviderChanged() {
	        ProviderChangeEvent event = new ProviderChangeEvent(this);
	        Iterator iterListener = this.listeners.iterator();
	        while (iterListener.hasNext()) {
	            IProviderChangeListener listener = (IProviderChangeListener) iterListener.next();
	            listener.providerChanged(event);
	        }
	    }
	
	}
	


More flexibility can be achieved by writing an abstract provider :

	/**
	 * An abstract provider.
	 * 
	 * @author ymortier
	 */
	public abstract class AbstractEditPolicyProvider implements IEditPolicyProvider {
	
	    /** All listeners. */
	    private List listeners = new ArrayList(1);
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.common.core.service.IProvider#addProviderChangeListener(org.eclipse.gmf.runtime.common.core.service.IProviderChangeListener)
	     */
	    public void addProviderChangeListener(IProviderChangeListener listener) {
	        this.listeners.add(listener);
	    }
	
	    /**
	     * {@inheritDoc}
	     * 
	     * @see org.eclipse.gmf.runtime.common.core.service.IProvider#removeProviderChangeListener(org.eclipse.gmf.runtime.common.core.service.IProviderChangeListener)
	     */
	    public void removeProviderChangeListener(IProviderChangeListener listener) {
	        this.listeners.remove(listener);
	    }
	
	    /**
	     * Fire a {@link ProviderChangeEvent}.
	     */
	    protected void fireProviderChanged() {
	        ProviderChangeEvent event = new ProviderChangeEvent(this);
	        Iterator iterListener = this.listeners.iterator();
	        while (iterListener.hasNext()) {
	            IProviderChangeListener listener = (IProviderChangeListener) iterListener.next();
	            listener.providerChanged(event);
	        }
	    }
	
	}


There only remains to override the methods provides() and createEditPolicies() in this provider’s implementations.