Tools are used in conjunction with the active diagram editor. They allow the user to quickly create new elements on the diagram or within compartments. Connection tools make creating relationships easy by providing visual cues and tool feedback.
This example will demonstrate how to add a tool to the palette that will create a UML Class.
The first step is to extend the
org.eclipse.gmf.runtime.diagram.ui.paletteProviders
extension-point.
The following example shows an extension that will add a new palette drawer and a palette tool within the drawer.
<extension point="org.eclipse.gmf.runtime.diagram.ui.paletteProviders"> <paletteProvider class="org.eclipse.gmf.runtime.diagram.ui.providers.DefaultPaletteProvider"> <Priority name="Lowest"/> <!-- Used to constrain the palette to a specific context --> <content> <method name="getDiagram().getType()" value="Freeform, Class"/> </content> <contribution factoryClass="com.ibm.examples.providers.MyPaletteFactory"> <entry id="MyDrawer" kind="drawer" label="My Drawer" path="/"/> <entry description="My description" id="myToolId" kind="tool" label="My Label" small_icon="icons/myIconSmall.gif" large_icon="icons/myIconLarge.gif" path="/MyDrawer/"/> </contribution> </paletteProvider> </extension>
The MyPaletteFactory
class should extend
org.eclipse.gmf.runtime.diagram.ui.services.palette.PaletteFactory.Adapter
. It simply provides a
CreationTool
for the given toolId
.
The toolId
comes from the tool entry id
specified in the paletteProviders
extension.
An element type is passed in the CreationTool
constructor. For this example, because the
palette tools will create a UML Class, the Class element type is obtained through UMLElementTypes.CLASS
.
public class MyPaletteFactory extends Adapter { private final Map tools = new HashMap(); { tools.put("myToolId", new CreationTool(UMLElementTypes.CLASS); } public Tool createTool(String toolId) { return (Tool)tools.get(toolId); } }Note the editor content object is of type
IPaletteContent
.
You can use its getDiagram()
method to specify the diagram types where the palette tool is to be added. In the example above, the tool is added
to both Class diagram and Freeform diagram.
This example will demonstrate how to add a tool to the palette that will create a stereotyped element. This example assumes that a profile named MyProfile with a stereotype named MyStereotype is deployed. Substitute the profile and stereotype names with those from your own deployed profile where applicable.
The process for defining the palette is done similarly to Adding Palette Tools to Create UML Elements.
The first step is to extend the
org.eclipse.gmf.runtime.diagram.ui.paletteProviders
extension-point.
The following example shows an extension that will add a new palette drawer and a palette tool within the drawer.
<extension point="org.eclipse.gmf.runtime.diagram.ui.paletteProviders"> <paletteProvider class="org.eclipse.gmf.runtime.diagram.ui.providers.DefaultPaletteProvider"> <Priority name="Lowest"/> <!-- Used to constrain the palette to a specific context --> <content> <method name="getDiagram().getType()" value="Freeform, Class"/> </content> <contribution factoryClass="com.ibm.examples.providers.MyPaletteFactory"> <entry id="MyDrawer" kind="drawer" label="My Drawer" path="/"/> <entry description="My description" id="myToolId" kind="tool" label="My Label" small_icon="icons/myIconSmall.gif" large_icon="icons/myIconLarge.gif" path="/MyDrawer/"/> </contribution> </paletteProvider> </extension>
The MyPaletteFactory
class should extend
org.eclipse.gmf.runtime.diagram.ui.services.palette.PaletteFactory.Adapter
. It simply provides a
CreationTool
for the given toolId
.
Since the palette tool will create a stereotyped element, a corresponding element type is retrieved from the
ElementTypeRegistry
by type id, com.ibm.examples.myStereotypeTypeId
public class MyPaletteFactory extends Adapter { private final Map tools = new HashMap(); { tools.put("myToolId", new CreationTool( ElementTypeRegistry.getInstance().getType("com.ibm.examples.myStereotypeTypeId")); } public Tool createTool(String toolId) { return (Tool)tools.get(toolId); } }
If the stereotype element type does not already exist for the type id, then one must be created by using the
org.eclipse.gmf.runtime.emf.type.core.elementTypes
extension point, otherwise this step may be omitted.
specializationType
element.id
to a unique id. This is the id in previous parts of this example used to reference the element type.kind
to be com.ibm.xtools.uml.type.IStereotypedElementType
because this element type represents a stereotyped element.specializes id
to be com.ibm.xtools.uml.class
because the stereotype will be applied to a UML Class.
By specifying the kind to be
com.ibm.xtools.uml.type.IStereotypedElementType
, a param
with name="stereotype"
must be specified to identify the stereotype this element type represents.
The value
of this parameter should equal the fully qualified name of the stereotype.
<extension point="org.eclipse.gmf.runtime.emf.type.core.elementTypes"> <specializationType id="com.ibm.examples.myStereotypeTypeId" kind="com.ibm.xtools.uml.type.IStereotypedElementType" name="My Stereotype Type" icon="icons/myTypeIcon.gif"> <specializes id="com.ibm.xtools.uml.class"/> <param name="stereotype" value="MyProfile::MyStereotype"/> </specializationType> </extension>
Element types and advice are organized by client context. In order for the new stereotype element type
to participate in the UML Modeler application it must be bound to the UML Modeler client context through the
org.eclipse.gmf.runtime.emf.type.core.elementTypeBindings
extention point.
binding
with the context set to com.ibm.xtools.uml.type.context
.elementType
with the ref
set to the ID of the element type to bind.<extension point="org.eclipse.gmf.runtime.emf.type.core.elementTypeBindings"> <binding context="com.ibm.xtools.uml.type.context"> <elementType ref="com.ibm.examples.myStereotypeTypeId"/> </binding> </extension>
This example will assume that the stereotype above is to extend the UML Association instead of the UML Class.
The palette factory will remain the same as above.
The element type will differ by specializing com.ibm.xtools.uml.association
and
implementing an edithelperadvice
which will define what elements this connector can connect between.
<extension point="org.eclipse.gmf.runtime.emf.type.core.elementTypes"> <specializationType id="com.ibm.examples.myStereotypeTypeId" edithelperadvice="com.ibm.examples.MyConnectionEditHelperAdvice" kind="com.ibm.xtools.uml.type.IStereotypedElementType" name="My Stereotype Type" icon="icons/myTypeIcon.gif"> <specializes id="com.ibm.xtools.uml.association"/> <param name="stereotype" value="MyProfile::MyStereotype"/> </specializationType> </extension>
Override getBeforeEditContextCommand(GetEditContextRequest request)
to define what elements
this connector can connect between. If the source and target are correct, create and return a new
GetEditContextCommand
. If the source is correct, but the target has yet to be chosen, return
IdentityCommand.INSTANCE
. If all checks fail, return
UnexecutableCommand.INSTANCE
.
In this example, the connection tool will only be able to connect between two UML Classes.
public class MyConnectionEditHelper extends AbstractEditHelper { protected ICommand getEditContextCommand(GetEditContextRequest req) { IEditCommandRequest editRequest = req.getEditCommandRequest(); if (editRequest instanceof CreateRelationshipRequest) { CreateRelationshipRequest crr = (CreateRelationshipRequest) editRequest; EObject source = crr.getSource(); if (source != null && !(source instanceof Class)) { return UnexecutableCommand.INSTANCE; } EObject target = crr.getTarget(); if (target == null) { return IdentityCommand.INSTANCE; } if (!(target instanceof Class)) { return UnexecutableCommand.INSTANCE; } GetEditContextCommand result = new GetEditContextCommand(req); result.setEditContext(crr.getContainer()); return result; } return null; } }
Popup bars appear when hovering over shapes (including inner shapes) on a diagram. The popup bar can be filled with actions to create
new elements within the context of the shape that is hovered over. These actions are contributed by extending the
org.eclipse.gmf.runtime.emf.ui.modelingAssistantProviders
extension-point.
For this example, popup bar actions will be contributed for a shape on the diagram which represents a UML
Class
using the
FORWARD
execution strategy (the popup bar action contribution will be added to the existing popup bar actions).
A UML
Class
can contain
Operation
s. Therefore the popup action that will be contributed, will be an action to create
Operation
s within the
Class
.
Begin by extending the
org.eclipse.gmf.runtime.emf.ui.modelingAssistantProviders
extension-point and
set the modelingAssistantProvider class
to be a class which extends
org.eclipse.gmf.runtime.emf.ui.services.modelingassistant.ModelingAssistantProvider
The enablement criteria for the modeling assistant is usually done by comparing the context object either to a specific edit part or by comparing the semantic element of the edit part to a specific model element. This example will illustrate both of these ways.
object
- Describes the context object that this provider is interested in providing for.
The class value is the fully qualified name of the class followed by the plug-in id in brackets.
An object definition can include method
calls to further narrow the match criteria.context
- Lists the object
definitions by their id to indicate that this provider wishes to provide for these elements.<extension point="org.eclipse.gmf.runtime.emf.ui.modelingAssistantProviders"> <modelingAssistantProvider class="com.ibm.examples.providers.MyModelingAssistantProvider"> <Priority name="Medium"/> <object class="com.ibm.examples.editparts.MyEditPart(com.ibm.examples)" id="editPart"> </object> <object class="org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart(org.eclipse.gmf.runtime.diagram.ui)" id="modelObject"> <method name="resolveSemanticElement().eClass().getEPackage().getNsURI()" value="http://www.eclipse.org/uml2/3.0.0/UML"/> <method name="resolveSemanticElement().eClass().getName()" value="Class"/> </object> <context elements="editPart, modelObject"/> </modelingAssistantProvider> </extension>
Override the
getTypesForPopupBar(IAdaptable host)
method in the
MyModelingAssistantProvider
class. The return
result of this method should be a list of element types. For each element type in the list, a new popup bar action
will be contributed.
public class MyModelingAssistantProvider extends ModelingAssistantProvider { public List getTypesForPopupBar(IAdaptable host) { // can check by edit part IGraphicalEditPart hostEP = (IGraphicalEditPart)host.getAdapter(IGraphicalEditPart.class); if (hostEP != null) { if (hostEP instanceof ClassEditPart) { return Collections.singletonList(UMLElementTypes.OPERATION); } } // or can check by semantic element EObject eObject = (EObject)host.getAdapter(EObject.class); if (eObject != null) { if (eObject instanceof Class) { return Collections.singletonList(UMLElementTypes.OPERATION); } } return Collections.EMPTY_LIST; } }
Connection handles appear when hovering over shapes on a diagram. The connection handles provide
various functions through easy to access popup menus. These actions are contributed by extending the
org.eclipse.gmf.runtime.emf.ui.modelingAssistantProviders
extension-point.
The following connection handles examples will simply add functionality to the
MyModelingAssistantProvider
class from above.
Clicking and dragging either the inbound or outbound connection handle to the diagram surface, results in a popup menu which displays a list of available relationship types to be created between the source or target element (depending on if the inbound or outbound connection handle was used).
To contribute to this list, implement the getRelTypesOnSource()
and getRelTypesOnTarget()
methods.
Each method should return a list of available relationship element types.
public List getRelTypesOnSource(IAdaptable source) { EObject eObject = (EObject)source.getAdapter(EObject.class); if (eObject instanceof Class) { return Collections.singletonList(UMLElementTypes.INTERFACE_REALIZATION); } return Collections.EMPTY_LIST; } public List getRelTypesOnTarget(IAdaptable target) { EObject eObject = (EObject)target.getAdapter(EObject.class); if (eObject instanceof Interface) { return Collections.singletonList(UMLElementTypes.INTERFACE_REALIZATION); } return Collections.EMPTY_LIST; }
Clicking and dragging either the inbound or outbound connection handle to another shape on the diagram (as oppose to the diagram surface), results in a popup menu which displays a list of available relationship types to be created between the source and target.
To contribute to this list, implement the getRelTypesOnSourceAndTarget()
method.
This method should return a list of available relationship element types for the given source and target elements.
public List getRelTypesOnSourceAndTarget(IAdaptable source, IAdaptable target) { EObject sourceEObject = (EObject)source.getAdapter(EObject.class); EObject targetEObject = (EObject)target.getAdapter(EObject.class); if (sourceEObject instanceof Class && targetEObject instanceof Interface) { return Collections.singletonList(UMLElementTypes.INTERFACE_REALIZATION); } return Collections.EMPTY_LIST; }
Utilizing a connection palette tool from a shape to the diagram surface, results in a popup menu which displays a list of available source and target elements for the relationship represented by the palette tool.
To contribute to this list, implement the getTypesForSource()
and getTypesForTarget()
methods.
These methods should return a list of available element types which can be used as either the source or target type respectively.
public List getTypesForSource(IAdaptable target, IElementType relationshipType) { EObject eObject = (EObject)target.getAdapter(EObject.class); if (eObject instanceof Interface) { if (relationshipType == UMLElementTypes.INTERFACE_REALIZATION) { return Collections.singletonList(UMLElementTypes.CLASS); } } return Collections.EMPTY_LIST; } public List getTypesForTarget(IAdaptable source, IElementType relationshipType) { EObject eObject = (EObject)source.getAdapter(EObject.class); if (eObject instanceof Class) { if (relationshipType == UMLElementTypes.INTERFACE_REALIZATION) { return Collections.singletonList(UMLElementTypes.INTERFACE); } } return Collections.EMPTY_LIST; }
By implementing the selectExistingElementForSource()
and selectExistingElementForTarget()
methods,
the create to existing element action will be available. When the user selects this entry, the
selectExistingElementForSource()
and selectExistingElementForTarget()
methods will be called (depending on whether
the inbound or outbound connection handle was used) in the provider that provided for this operation with the highest priority.
It is up to the client to implement a mechanism to allow the user to select an existing element.
public EObject selectExistingElementForSource(IAdaptable target, IElementType relationshipType) { // Show a dialog from which the user can select an existing element. // Return the element. } public EObject selectExistingElementForTarget(IAdaptable source, IElementType relationshipType) { // Show a dialog from which the user can select an existing element. // Return the element. }
Double-clicking either the inbound or outbound connection handle, results in a popup menu which displays a list of relationship element types for the source or target. After the user selects a type, the related elements will appear on the diagram with connections to the source or target.
To contribute to this list, implement the getRelTypesForSREOnSource()
and getRelTypesForSREOnTarget()
methods.
These methods should return a list of relationship element types which can connect to either the source or target type respectively.
public List getRelTypesForSREOnSource(IAdaptable source) { EObject eObject = (EObject)source.getAdapter(EObject.class); if (eObject instanceof Class) { return Collections.singletonList(UMLElementTypes.INTERFACE_REALIZATION); } return Collections.EMPTY_LIST; } public List getRelTypesForSREOnTarget(IAdaptable target) { EObject eObject = (EObject)target.getAdapter(EObject.class); if (eObject instanceof Interface) { return Collections.singletonList(UMLElementTypes.INTERFACE_REALIZATION); } return Collections.EMPTY_LIST; }
For more information on element types see Creating Element Types.