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.
Difference between revisions of "Manage Decorators On Papyrus"
(→Using Decoration Service) |
(→Implemented Edit Policy) |
||
Line 347: | Line 347: | ||
So in the refresh methode for NodeB: | So in the refresh methode for NodeB: | ||
− | <source lang="java> | + | <source lang="java"> |
... | ... | ||
// If the marker for nodeB already set have to be changed | // If the marker for nodeB already set have to be changed |
Revision as of 11:32, 21 October 2015
Contents
- 1 Introduction
- 2 Decoration Service Framework
- 3 Shape Service Framework
- 4 Application Example
- 4.1 Context
- 4.1.1 Example
- 4.1.2 Using Decoration Service
- 4.1.3 Using Shape Service
- 4.2 Sources
- 4.1 Context
Introduction
The purpose of this documentation is to give the minimum information to deploy your own decorator for Papyrus elements as EditPart. To manage decorator on Edit Part two solutions are provided by Papyrus:
- Decoration Service Framework
- Shape Service Framework
Decoration Service is compliant with gif, ico, bmp, jpg and png files. Contextual message can be set for each decoration, and propagation to parents can be allowed. Unlike Decoration Service, Shape Service is only compliant to svg files, but the position of the shape can be selected within in the properties view. Others differences are that the shape can be displayed in the symbol compartment and it can be used as the shape of the figure.
Decoration Service Framework
Architecture
The decoration service architecture has already been described on a document (here). You will find a description of main interfaces or classes to be implemented or to be called in order to use the framework and add specific decoration.
DecorationService
Decoration service permits to manage decoration on EObject. Decorations are added through this service. It provides listener to observe changes. This service can be retrieved with:
DecorationService decorationService = ServiceUtilsForEditPart.getInstance().getService(DecorationService.class, editPart);
Main methods
- addDecorations(IPapyrusMarker marker, EObject element)
- Add a new Decoration to a decorations Map with an IPapyrusMarker associated to an element.
- addDecoration(String id, String type, EObject element, ImageDescriptor decorationImageForGE, ImageDescriptor decorationImageForME, PreferedPosition position, String message, int priority)
- Add a new decoration without passing by a marker.
- removeDecoration(String id)
- Remove a decoration from the decorations Map,
- getDecorations(EObject element):List<IPapyrusDecoration>
- Return an Interface of decoration (IDecoration) for the element
IPapyrusMarker
IPapyrusMarker provides a protocol for markers that annotates elements with information, often used for problems. It is an analogy of the Eclipse IMarker API for resources in the workspace, to be implemented in order to create its own marker used for custom decoration.
Main methods
- getType():String
- Return the type of the concret Papyrus marker. Is also used to link a decorator to the marker(see Decoration Image Extension Point).
- exist():Boolean
- Return true if the marker exists on the view.
IDecorationSpecificFunctions
This interface allows to access a set of functions that depends on the decorator type. The objective is that plug-ins for a specific decoration type can implement this interface (via an extension point) to provide the information that depends on the decoration type, notably the used icons, their position, the way how messages are calculated and how decoration might propagate from children to parents. To be implemented in order to create its own decoration.It Is related to a marker through decorationImage extension point.
Main methods
- getImageDescriptorForGE(IPapyrusMarker marker):ImageDescriptor
- Get the image descriptor for a graphical editor.
- getImageDescriptorForME(IPapyrusMarker marker):ImageDescriptor
- Get the image descriptor for model explorer. May be identical to the image for a graphical editor.
- getPreferedPosition(IPapyrusMarker marker):PreferedPosition
- Return the preferred position for markers within the model explorer.
- getMessage(IPapyrusMarker marker):String
- Return a textual information for the marker (used for fixing messages that do not need to be stored in each marker).
- getPriority(IPapyrusMarker marker):int
- Return the priority of a decoration. This enables selecting a marker with a high priority, if multiple markers for the same model element and the same position exist.
- supportsMarkerPropagation():MarkChildren
- Does the decoration type support a propagation from child to parent, e.g. in case of a problem on a parents' marker (package) might be marked as containing warnings or errors.
- markerPropagation(EList<IPapyrusDecoration> childDecorations):IPapyrusDecoration
- Calculate a propagated marker for the parent, given the set of child decorations. Return the calculated decoration for the parent depending on a set of decorations on children.
Decoration Image Extension Point
Provide an ImageDescription for a decoration marker. It allows to link a IDecorationSpecificFunction class to a Papyrus marker through his type.
Identifier: org.eclipse.papyrus.infra.services.decoration.decorationImage
Shape Service Framework
The shape service framework allows to display svg document in the symbol compartment or at a chosen position on the edit part.
Architecture
AbstractShapeProvider
The framework provides a simple abstract provider class in order to add svg shape to edit parts. Only few methods have to be implemented.
Main methods
- getShapes(EObject view):List<RenderedImage>
- Returns the list of shapes proposed by this provider or null if no shapes have to be displayed by this provider.
- getSVGDocument(EObject view):List<SVGDocument>
- Return the list of SVG DOCUMENT or null if no shape has to be displayed by this provider.
- providesShapes(EObject view):Boolean
- Returns true if the provider can display shapes. This methods allows to compute if shapes can be displayed instead of computing the whole list of shapes to be displayed.
ShapeProvider Extension Point
To be loaded, implemented shape providers have to be linked through a specific extension point.
Appearence tab
To display the shape on the edit parts and to choose the visibility and the position, attributes have to be set on the appearance tab of the properties view.
Application Example
This part will provide a simple example using decorator service. This example illustrates how to display decoration on edit part according to the conditions described above.
Context
SysML profile will be used as allocation profile. An "allocation table" affects the call behavior to nodes. Nodes can be stereotyped with NodeA and NodeB stereotypes. Depending on the node on which the callBehavior is allocated, the decorator of the callBehavior should change.
Example
With this profile:
Applied on these two nodes:
And with this allocation Table:
The expected result is:
Using Decoration Service
Implemented architecture
On this example, we have used 2 markers and one decoration specific function for each marker. The association between markers and decoration are done thanks to a specific extension point. An Edit policy is used to add markers to the decoration Service according to the model context. The edit policy is installed to the right edit parts through an edit policy provider, which is loaded by extension point.
Implemented markers
For each type of stereotype NodeA and NodeB, a marker have been implemented with a specific markerType:
public class NodeAMarker implements IPapyrusMarker { public static final String MARKER_TYPE = "org.eclipse.papyrus.infra.services.decoration.example.NodeA"; //$NON-NLS-1$ public static final String NODE_A_STEREOTYPE = "DecorationExampleProfile::NodeA";//$NON-NLS-1$ protected View notationElement; public NodeAMarker(final View notationElement) { this.notationElement = notationElement; } @Override public boolean exists() { return ExampleUtils.isAllocatedTo((CallBehaviorAction) notationElement, NODE_A_STEREOTYPE); } @Override public String getType() throws CoreException { return MARKER_TYPE; } @Override public String getTypeLabel() throws CoreException { return "Node A marker example"; } ...
Implemented NodeDecoration EditPolicy
These markers are added to the DecorationService thanks to an editPolicy applied to the CallBehavoir edit part.
The DecorationService is called in the Activate() method:
@Override public void activate() { super.activate(); // TODO install listener try { decorationService = ServiceUtilsForEditPart.getInstance().getService(DecorationService.class, getHost()); refresh(); } catch (final ServiceException ex) { // Ignored; do nothing } }
The refresh method adds or removes markers according to the allocated element on the UML element of the edit part:
@Override public void refresh() { ... // If the marker already set for nodeA have to be changed. if (ExampleUtils.isAllocatedTo((CallBehaviorAction) view.getElement(), NodeAMarker.NODE_A_STEREOTYPE) != isNodeAMarked) { isNodeAMarked = !isNodeAMarked; if (isNodeAMarked) { decorationService.addDecoration(getMarkerA(), getView()); } else { decorationService.removeDecoration(getMarkerA().toString()); } getHost().refresh(); } // If the marker for nodeB already set have to be changed if (ExampleUtils.isAllocatedTo((CallBehaviorAction) view.getElement(), NodeBMarker.NODE_B_STEREOTYPE) != isNodeBMarked) { isNodeBMarked = !isNodeBMarked; if (isNodeBMarked) { decorationService.addDecoration(getMarkerB(), getView()); } else { decorationService.removeDecoration(getMarkerB().toString()); } getHost().refresh(); } }
Implemented CustomEditPolicy Provider
An edit policy provider is used to install the NodeDecorationEditPolicy to the right edit parts.
public class CustomEditPolicyProvider implements IEditPolicyProvider { protected String diagramType = org.eclipse.papyrus.uml.diagram.activity.edit.parts.ActivityDiagramEditPart.MODEL_ID; @Override public void addProviderChangeListener(final IProviderChangeListener listener) { } @Override public boolean provides(final IOperation operation) { boolean provide = false; String currentDiagramType; // get the element final EObject referenceElement = ((View) ((CreateEditPoliciesOperation) operation).getEditPart().getModel()).getElement(); // Test if it's a creation operation and the element is a CallBehavoirActino if ((operation instanceof CreateEditPoliciesOperation) && (referenceElement instanceof CallBehaviorAction)) { // Get The current diagram type currentDiagramType = ((View) ((CreateEditPoliciesOperation) operation).getEditPart().getModel()).getDiagram().getType(); // Test if we are on an Activity Diagram if ((diagramType != null) && (diagramType.equals(currentDiagramType))) { provide = true; } else { provide = false; } } return provide; } @Override public void removeProviderChangeListener(final IProviderChangeListener listener) { } @Override public void createEditPolicies(final EditPart editPart) { editPart.installEditPolicy(NodeDecoratorEditPolicy.EDIT_POLICY_ROLE, new NodeDecoratorEditPolicy()); } }
This edit policy provider is installed with the editpolicyProviders extension point:
<extension point="org.eclipse.gmf.runtime.diagram.ui.editpolicyProviders"> <editpolicyProvider class="org.eclipse.papyrus.infra.services.decoration.example.provider.CustomEditPolicyProvider"> <Priority name="Medium"> </Priority> </editpolicyProvider> </extension>
Implemented Decoration Specific Function
The decoration specific function specifies the decoration to be applied on a marked element. It defines the image, the position, the context message of the decoration etc...
public class NodeADecoration implements IDecorationSpecificFunctions { @Override public MarkChildren supportsMarkerPropagation() { // This marker should not be propagated return null; } @Override public ImageDescriptor getImageDescriptorForGE(final IPapyrusMarker marker) { return org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImageDescriptor(Activator.ID, "icons/NodeA.gif"); //$NON-NLS-1$ } @Override public PreferedPosition getPreferedPosition(final IPapyrusMarker marker) { return PreferedPosition.NORTH_EAST; } @Override public String getMessage(final IPapyrusMarker marker) { return "Node A decoration example"; } @Override public int getPriority(final IPapyrusMarker marker) { return 0; } }
To associate decoration specific function to a marker, an extension point can be used. In the image below the decoration NodeAdecoration is linked to the marker type defined in the marker NodeAMarker.MARKER_TYPE
<extension point="org.eclipse.papyrus.infra.services.decoration.decorationSpecificFunctions"> <client class="org.eclipse.papyrus.infra.services.decoration.example.NodeADecoration" decorationType="org.eclipse.papyrus.infra.services.decoration.example.NodeA"> </client> <client class="org.eclipse.papyrus.infra.services.decoration.example.NodeBDecoration" decorationType="org.eclipse.papyrus.infra.services.decoration.example.NodeB"> </client> </extension>
Implementation without markers
NOTE:this implementation does't work for now due to a NPE. A Patch is in progress to fix that.
Architecture
Without marker the architecture of class to implement is less complexe. You only needs the edit policy which will add decoration to the decorationService with the provider which is the same than with marker.
Implemented Edit Policy
The edit policy is prtty much the same except that we use addDecoration(String id, String type, EObject element, ImageDescriptor decorationImageForGE, ImageDescriptor decorationImageForME, PreferedPosition position, String message, int priority)
So in the refresh methode for NodeB:
... // If the marker for nodeB already set have to be changed if (ExampleUtils.isAllocatedTo((CallBehaviorAction) view.getElement(), ExampleUtils.NODE_B_STEREOTYPE) != nodeBMarked) { nodeBMarked = !nodeBMarked; if (nodeBMarked) { // Decoration Without marker decorationService.addDecoration( view.getElement().toString(), // $NON-NLS-1$ "NodeBDecoration", //$NON-NLS-1$ view.getElement(), org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImageDescriptor(Activator.ID, "icons/NodeB.gif"), //$NON-NLS-1$ org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImageDescriptor(Activator.ID, "icons/NodeB.gif"), //$NON-NLS-1$ , PreferedPosition.SOUTH_WEST, "NodeB decoration Without marker", 0); } else { decorationService.removeDecoration(view.getElement().toString()); } getHost().refresh(); } ...
Result
Using Shape Service
Implemented architecture
The use of Shape service is done by the implementation of a shape provider which extends AbstractShapeProvider: "NodeShapeProvider". Then "NodeShapeProvider" is activated thanks to the shape provider extension point.
Implemented Shape Provider
The implementated Shape provder will provide shape according to the same conditions than before.
public class NodeShapeProvider extends AbstractShapeProvider { // The used SVG files private static final String ICONS_SYMBOLS_NODE_A_SVG = "/icons/NodeA.svg";//$NON-NLS-1$ private static final String ICONS_SYMBOLS_NODE_B_SVG = "/icons/NodeB.svg";//$NON-NLS-1$ ... @Override public boolean providesShapes(final EObject view) { boolean provide = false; if (view instanceof View) { final EObject element = ((View) view).getElement(); // Test if the element is a CallBehavoirAction and if a stereotyped node is allocated to it. if (element instanceof CallBehaviorAction && (ExampleUtils.isAllocatedTo((CallBehaviorAction) element, ExampleUtils.NODE_A_STEREOTYPE) || ExampleUtils.isAllocatedTo((CallBehaviorAction) element, ExampleUtils.NODE_B_STEREOTYPE))) { provide = true; } else { provide = false; } } return provide; } @Override public List<RenderedImage> getShapes(final EObject view) { if (providesShapes(view)) { // Gets the SVG document: here NodeA.svg or/and NodeB.svg final List<SVGDocument> documents = getSVGDocument(view); if (documents != null) { final List<RenderedImage> result = new LinkedList<RenderedImage>(); for (final SVGDocument document : documents) { try { // Adds the shape to result result.add(renderSVGDocument(view, document)); } catch (final IOException ex) { // Do nothing } } return result; } } return null; } @Override public List<SVGDocument> getSVGDocument(final EObject view) { final List<SVGDocument> svgDocuments = new ArrayList<SVGDocument>(); if (providesShapes(view)) { final CallBehaviorAction callBehaviorAction = (CallBehaviorAction) ((View) view).getElement(); // If allocation corresponding adds SVG document for Node A if (ExampleUtils.isAllocatedTo(callBehaviorAction, ExampleUtils.NODE_A_STEREOTYPE)) { // Get the SVG document final SVGDocument document = getSVGDocument(URI.createPlatformPluginURI(Activator.ID + ICONS_SYMBOLS_NODE_A_SVG, true).toString()); if (document != null) { svgDocuments.add(document); } } // If allocation corresponding adds SVG document for Node B if (ExampleUtils.isAllocatedTo(callBehaviorAction, ExampleUtils.NODE_B_STEREOTYPE)) { // Get the SVG document final SVGDocument document = getSVGDocument(URI.createPlatformPluginURI(Activator.ID + ICONS_SYMBOLS_NODE_B_SVG, true).toString()); if (document != null) { svgDocuments.add(document); } } } return svgDocuments; } ... }
Implemented Shape Provider Extension Point
To activate the shape provider we use the Shape Provider Extension Point:
<extension point="org.eclipse.papyrus.infra.gmfdiag.common.shapeProvider"> <shapeProvider class="org.eclipse.papyrus.infra.services.decoration.example.provider.NodeShapeProvider" id="org.eclipse.papyrus.infra.services.decoration.example.nodeShapeProvider" name="NodeShapeProvider"> <Priority name="Medium"> </Priority> </shapeProvider> </extension>
Result
Sources
The plugin of this example can be retrieved in the Papyrus git code repository here.