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.
Graphical Modeling Framework/Tips
A collection of snippets and tips...
Contents
- 1 Creating New Elements And Corresponding Views
- 2 Change Names Of Newly Created Elements
- 3 Create New Elements Using RecordingCommand and CanonicalEditPolicies
- 4 Remove Property Sheet altogether
- 5 Sharing single EditingDomain instance across several diagrams
- 6 Making figures sensitive to attributes of semantic elements
Creating New Elements And Corresponding Views
DeviceEditPart selectedElement = ...; String compartemntsSemanticHint = NetworkVisualIDRegistry.getType(tests.mindmap.network.diagram.edit.parts.Device_ModulesCompartmentEditPart.VISUAL_ID); Device_ModulesCompartmentEditPart modulesCompartment = (Device_ModulesCompartmentEditPart)selectedElement.getChildBySemanticHint(compartemntsSemanticHint); IElementType type = NetworkElementTypes.Module_3001; ViewAndElementDescriptor viewDescriptor = new ViewAndElementDescriptor( new CreateElementRequestAdapter(new CreateElementRequest(type)), Node.class, ((IHintedType) type).getSemanticHint(), selectedElement.getDiagramPreferencesHint()); CreateViewAndElementRequest req = new CreateViewAndElementRequest(viewDescriptor); CompoundCommand cmd = new CompoundCommand("Create 10 modules"); for (int i=0; i<10; i++) { cmd.add(modulesCompartment.getCommand(req)); } selectedElement.getDiagramEditDomain().getDiagramCommandStack().execute(cmd);
Change Names Of Newly Created Elements
Collection results = DiagramCommandStack.getReturnValues(cmd); for (Object res: results) { if (res instanceof IAdaptable) { IAdaptable adapter = (IAdaptable) res; View view = (View) adapter.getAdapter(View.class); if (view != null) { Module newMod = (Module)view.getElement(); SetRequest reqSet = new SetRequest(selectedElement.getEditingDomain(), newMod, NetworkPackage.eINSTANCE.getNamedElement_Name(), "ModX"); SetValueCommand operation = new SetValueCommand(reqSet); selectedElement.getDiagramEditDomain().getDiagramCommandStack().execute(new ICommandProxy(operation)); } } }
Create New Elements Using RecordingCommand and CanonicalEditPolicies
final Device dev = (Device)((View)selectedElement.getModel()).getElement(); TransactionalEditingDomain editingDomain = selectedElement.getEditingDomain(); editingDomain.getCommandStack().execute(new RecordingCommand(editingDomain) { @SuppressWarnings("unchecked") protected void doExecute() { dev.setName("Morda13"); for (int i = 0; i < 5; i++) { Module newMod = NetworkFactory.eINSTANCE.createModule(); newMod.setName("X26 - " + i); dev.getModules().add(newMod); } } });
Remove Property Sheet altogether
Add next method to the generated diagram editor class (usually <ModelName>DiagramEditor)
public Object getAdapter(Class type) { if (type == IPropertySheetPage.class) { return null; } return super.getAdapter(type); }
Sharing single EditingDomain instance across several diagrams
Generated code always creates new (own) instance of EditingDomain for each opened diagram editor. Since EditingDomain owns ResourceSet, different instances of domain model elements will be loaded for each opened diagram editor. Sometimes it is important to share the same domain model instances across several diagram editors (for example to get rid of synchronization problems). This leads us to the question of sharing same instance of EditingDomain across several generated diagram editors. Below you can find step by step description of necessary modifications you have to apply to the generated code to share the same EditingDomain instance between two diagrams of different types.
1. Make sure you have org.eclipse.gmf.bridge.trace plugin installed as a part of GMF SDK
2. Create diagram1.gmfmap, diagram2.gmfmap files and generate diagram1.gmfgen, diagram2.gmfgen. Ensure diagram1.trace and diagram2.trace files created.
3. Modify generated diagram1.gmfgen and diagram2.gmfgen files to use different Model IDs, Plugin IDs, Editor IDs. Optionally two different diagrams could has different diagram file extensions as well:
4. Modify diagram2.trace file to use different visualID values then specified in diagram1.trace file - the easiest way is to replace “"200”-> “"210”, .., “"800” -> “"810” – and regenerate diagram2.gmfgen from diagram2.gmfmap
5. Open diagram2.gmfgen and modify visualID property for GenDiagram to make it different then visualID of GenDiagram in diagram1.gmfgen:
6. Ensure both diagram1.gmfgen and diagram2.gmfgen are using the same EditingDomain ID:
7. Generate code for both diagram plugins.
8. In both generated ???DiagramEditor classes modify createEditingDomain() method to simply call to the super. implementation:
/** * @generated NOT */ protected TransactionalEditingDomain createEditingDomain() { return super.createEditingDomain(); }
NOTE: Due to the latest changes in GMF 2.0 M5 code generator you should modify generated ???DocumentProvider. createEditingDomain() instead. The following code should be placed there:
/** * @generated NOT */ private TransactionalEditingDomain createEditingDomain() { // Modification started TransactionalEditingDomain editingDomain; editingDomain = TransactionalEditingDomain.Registry.INSTANCE.getEditingDomain("org.eclipse.gmf.ecore.editor.EditingDomain"); if (editingDomain == null) { editingDomain = DiagramEditingDomainFactory.getInstance().createEditingDomain(); editingDomain.setID("org.eclipse.gmf.ecore.editor.EditingDomain"); } // Continue with the original code. final NotificationFilter diagramResourceModifiedFilter = NotificationFilter.createNotifierFilter(editingDomain.getResourceSet()). and(NotificationFilter.createEventTypeFilter(Notification.ADD)).and(NotificationFilter.createFeatureFilter( ResourceSet.class, ResourceSet.RESOURCE_SET__RESOURCES)); editingDomain.getResourceSet().eAdapters().add(new Adapter() { // ..... }); return editingDomain; }
9. Declare EditingDomain with the shared EditingDomain ID (see step 5.) inside plugin.xml for generated for diagram1:
<!-- gmf generator persistent region begin --> <extension point="org.eclipse.emf.transaction.editingDomains"> <editingDomain factory="org.eclipse.emf.workspace.WorkspaceEditingDomainFactory" id="SharedEditingDomain"/> </extension> <!-- gmf generator persistent region end -->
10. Only one metamodelType could be registered for each EClass in scope of one EditingDomain. During this step you have to replace by specializationType declaration all the metamodelType declarations inside plugin.xml for diagram2 duplicating metamodelType declarations inside plugin.xml for diagram1 (having the same eclass attribute). Following part of plugin.xml:
<metamodelType id="shape.diagram2.Diagram_1001" name="Undefined" kind="org.eclipse.gmf.runtime.emf.type.core.IHintedType" eclass="Diagram" edithelper="shape.diagram.edit.helpers.DiagramEditHelper"> <param name="semanticHint" value="1001"/> </metamodelType>
Should be replaced with:
<specializationType id="shape.diagram2.Diagram_1001" name="Undefined" kind="org.eclipse.gmf.runtime.emf.type.core.IHintedType" edithelperadvice="org.eclipse.gmf.runtime.emf.type.core.edithelper.AbstractEditHelperAdvice"> <specializes id="shape.diagram1.Diagram_1000"/> <param name="semanticHint" value="1001"/> </specializationType>
<specializes> attribute for newly creates specializationTypes should point to the corresponding metamodeType id from plugin.xml generated for diagram1.
11. Patch plugin.xml generated for diagram2 and specify the same clientContext for elementTypeBindings extension point as it is specified for diagram1. Instead of:
<extension point="org.eclipse.gmf.runtime.emf.type.core.elementTypeBindings"> <clientContext id="Diagram2_IDClientContext"> … </clientContext> <binding context="Diagram2_IDClientContext"> … </binding> </extension>
type:
<extension point="org.eclipse.gmf.runtime.emf.type.core.elementTypeBindings"> <clientContext id="Diagram1_IDClientContext"> … </clientContext> <binding context="Diagram1_IDClientContext"> … </binding> </extension>
12. To correctly unload (model) resources associated with diagram you can add method to generated ???DocumentProvider:
protected void disposeElementInfo(Object element, ElementInfo info) { super.disposeElementInfo(element, info); // Unload all the resources associated with diagram here if necessary. }
Making figures sensitive to attributes of semantic elements
This is about how to change diagram editor generated by GMF to make figures sensitive to semantic element's attributes' values. Changes to attributes' values should be automatically detected and reflected in figure's look. All you have to do is to make a little change in *EditPart class. I'm going to change edit part for semantic model's Port element, so I will edit MY.PACKAGE.diagram.edit.parts.PortEditPart class.
We will add to the figure a new method which changes figure's parameters according to attributes of semantic element. Add following method to PortFigure class which is PortEditPart 's inner class:
public void updateFace() { Port port = (Port) ((Node) PortEditPart.this.getModel()).getElement(); // set line width according to number of some children int lineWidth = 1; if (port.getLogicalUnits().size() > 1) { lineWidth = 2; } this.setLineWidth(lineWidth); // update tooltip String tooltipText; if (port.getDescription() != null && port.getDescription().length() > 0) { tooltipText = port.getDescription(); } else { tooltipText = port.getName(); } if (getToolTip() == null) { setToolTip(new Label(tooltipText)); } else if (getToolTip() instanceof Label) { ((Label) getToolTip()).setText(tooltipText); } }
Change PortFigure 's constructor to make it use new method.
/** * @generated NOT */ public PortFigure() { this.setFill(true); this.setFillXOR(false); this.setOutline(true); this.setOutlineXOR(false); this.setLineStyle(Graphics.LINE_SOLID); //this.setLineWidth(1); //this.setForegroundColor(PORTFIGURE_FORE); //this.setBackgroundColor(PORTFIGURE_BACK); updateFace(); createContents(); }
The last thing is to hook new method to changes in semantic element. To do that you have to override in PortEditPart handleNotificationEvent(Notification notification) method. Add to the class something like this:
@Override protected void handleNotificationEvent(Notification notification) { if (notification.getNotifier() instanceof Port) { getPrimaryShape().updateFace(); } super.handleNotificationEvent(notification); }
Without this method you would need to restart editor to reflect element's changes in figure parameters.
→ Original version of this section, with colorized source code, can be found here