Jump to: navigation, search

Difference between revisions of "GMF Newsgroup Q and A"

m
m
Line 1,196: Line 1,196:
 
</pre>
 
</pre>
 
I believe there is a tutorial on how to create custom styles, try to look it up.
 
I believe there is a tutorial on how to create custom styles, try to look it up.
 +
 +
====[http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/msg00283.html How can I synchronize my custom figures with the model?]====
 +
 +
*'''Q:''' I have been using GMF and creating custom figures, the custom figures are made up of images and several label which might or might not be shown based on some logic that needs to be applied to the model.
 +
 +
I am now trying to work out the cleanest way to add the synchronization of the model with the figure, I suppose the EditPart should contain the logic but what is the preferred way to override the default EditPart?
 +
 +
*'''A:''' You could override refreshVisuals() in generated edit parts to update figure on model changes.
 +
 +
Add the following code in ShipEditPart of TaiPan sample. When you rename a ship to "Avrora" it becomes red.
 +
<pre>
 +
    protected void refreshVisuals() {
 +
        super.refreshVisuals();
 +
        Ship ship = (Ship) resolveSemanticElement();
 +
        if ("Avrora".equals(ship.getName())) { //$NON-NLS-1$
 +
            getPrimaryShape().setBackgroundColor(ColorConstants.red);
 +
        } else {
 +
            getPrimaryShape().setBackgroundColor(null);
 +
        }
 +
    }
 +
 +
    protected void handleNotificationEvent(Notification notification) {
 +
        super.handleNotificationEvent(notification);
 +
        if
 +
(TaiPanPackage.eINSTANCE.getShip_Name().equals(notification.getFeature())) {
 +
            refreshVisuals();
 +
        }
 +
    }
 +
</pre>
 +
 +
====[http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/msg00204.html How can I add strikethrough and underline features to the Appearance tab?]====
 +
 +
*'''Q:''' I have to add "underline" and "strikethrough" features in Appearance page in Properties view. Can someone give me any hints?
 +
 +
*'''A:''' This is going to take some effort so I hope you're up for it:-)
 +
 +
The Appearance tab is contributed by the org.eclipse.gmf.runtime.diagram.ui.properties plug-in; the required three extension point declarations, and the corresponding implementation classes are found in this plug-in.
 +
 +
This plug-in contributes three tabs; the Appearance and Advanced tabs are always shown when anything in the editor is selected, and additionally the Grid tab is shown when the canvas itself is selected. These contributions are fixed with no built-in capability to 'swap out' the appearance tab with your own or for adding additional items to the existing tab.
 +
 +
The quick and dirty solution is to import org.eclipse.gmf.runtime.diagram.ui.properties into your workspace (as source) then clone ....appearance.ConnectionAppearancePropertySection
 +
and any other required classes (put the clones in your own plug-in) then add your own "underline" and "strikethrough" properties to your clone(s).
 +
Then in the plugin.xml of org.eclipse.gmf.runtime.diagram.ui.properties modify the extension point declaration(s) to point to your 'cloned' version(s) instead. This is not your final solution because you really don't want to hack Eclipse code and distribute it with your plug-in or application (bad Karma :-P).
 +
 +
What the quick and dirty solution can do is get you up and running pretty quickly with prototyping/developing your enhancements.
 +
 +
Once you're satisfied that the enhancements are working then it's time to make them official.
 +
 +
Making it official means stopping the hijacking of org.eclipse.gmf.runtime.diagram.ui.properties and properly declaring your own custom propertyContributor.
 +
 +
There are just 3 basic steps to this process:
 +
 +
1. Implement and override .getContributorId() in the generated <your>DiagramEditor by returning your own ID for the custom contribution. This ID is a string that you choose so it can be just about anything; you can simply follow any convention you have now for other extension point ID's in your application. As an example let's make the ID = "com.my.own.contributor.id"
 +
 +
2. Copy/paste the following three extension point declarations from the 'hacked' org.eclipse.gmf.runtime.diagram.ui.properties#plugin.xml into your own plugin.xml:
 +
 +
org.eclipse.ui.views.properties.tabbed.propertyContributor org.eclipse.ui.views.properties.tabbed.propertyTabs org.eclipse.ui.views.properties.tabbed.propertySections
 +
 +
3. Now in your own plugin.xml replace the three:
 +
contributorId="org.eclipse.gmf.runtime.diagram.ui.properties"
 +
with
 +
contributorId="com.my.own.contributor.id"
 +
 +
That's about it.
 +
 +
You can delete the hacked version of org.eclipse.gmf.runtime.diagram.ui.properties at this point since you don't need it any more.
 +
 +
I hope this is enough of a hint on how you can get started; the bulk of your work (and maybe headaches:-P) is to get to know how the existing code utilizes the editing domain, commands, etc... and then adding your own stuff to it.
 +
 +
Hints +1 -- If your editor has some non-standard or tricky hierarchy you may have to extend the default ModelElementTypeMapper or provide your own custom implementation of ITypeManager.
 +
 +
Hint +2 -- Likewise with the LabelProvider
 +
 +
Hint +3 -- If you want finer control of when these new properties show up (maybe they're only applicable for certain nodes???) then you would want to extend the default filters or provide your own implementation of IFilter.

Revision as of 07:55, 4 November 2006

This page contains a number of useful/interesting Q&As that are found on the newsgroup. Please add/edit/organize as needed.

Contents

How do I get ports to stick to the side of a component?

  • Q: My first problem was that I couldn't find a good way to get the ports stick to the component since apparently GMF doesn't support nodes
  • A: Did you try setting affixedParentSide attribute for port Node in .gmfgraph model? This attribute was recently added and is available in 2.0 builds.

How do I change the color of a line using an action?

  • Q: I'm able to call a created Action by popup menu, but i want to know how to change EditPart's attributes such as colors of connections, for example.

Any hint?

  • A: Visual attributes (like color, line width , ... ) are attributes of the figure, and they usually reflect styles on the Notation view

To change the line color on a view you can use the LineStyle (from the notation meta model). LineStyle had setLineColor method that allows you to change the line color.

For examples on how to change styles check SetPropertyCommand and ColorPropertyContributionItem

Here is one of the ways to do it:

First you create a change property request like this

ChangePropertyValueRequest req = new ChangePropertyValueRequest( 
        StringStatics.BLANK,Properties.ID_LINECOLOR,
    FigureUtilities.colorToInteger(DiagramColorConstants.red));

you will notice that I'm passing the line color as the property ID, and Red as the value. Now, we can call get command on the edit part, passing it the request we just created.

final Command cmd = editPart.getCommand(req);

Then execute the returned command (should check for null before trying to execute) like this:

AbstractEMFOperation operation = new AbstractEMFOperation(((IGraphicalEditPart) editPart).getEditingDomain(),
	StringStatics.BLANK, null) {
	protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
		cmd.execute();
		return Status.OK_STATUS;
	}
};

try {
	operation.execute(new NullProgressMonitor(), null);
} catch (ExecutionException e) {
	// nothing to do here
}

This should change the line color to red.

How do I create a scalable note figure with folded corner?

  • Q: What's an elegant way to create a figure like the ones used for notes (the sheet with a dog-ear, i.e. a triangle bent down in the upper right)? Is there a gallery or resource that one can import for that? With "elegant" I also mean, that the figure should nicely resize, provide a reflowing label, etc. etc,
  • A: The figure used by notes is called NoteFigure it is public in the plugin org.eclipse.gmf.runtime.diagram.ui. You can use it or subclass it to do any customizations you need.

The way to use change the figure created by the edit part is to change the code in the your edit part's createFigure() method to create a NoteFigure or a subclass of it.

I've tried a very simple case with the generated code where i use the note figure instead of the generated figure , and noticed that width and height works as i expect. It respect the value i pass (as long as I just drop the shape on the diagram surface, otherwise it will use the exact rectangle i draw on the diagram surface).

This is the way I create my figure :

    /**
     * @generated Not
     */
    protected IFigure createNodeShape() {
        Insets insets = new Insets(getMapMode().DPtoLP(30), 
getMapMode().DPtoLP(30), getMapMode().DPtoLP(30), getMapMode().DPtoLP(45));
        primaryShape = new MyFigure(getMapMode().DPtoLP(300), 
getMapMode().DPtoLP(400), insets);
        return primaryShape;
    }

I have not tried to add labels though.

How to scroll a background image?

  • Q: I have set a background image in gmf editor however i need to set the bounds to enable scrolling (to move through the image) (and not only when a figure is on it). How can i achieve this?
  • A: That depends on how you've set the diagram background; if you've overridden paintFigure() in diagram FreeformLayer you should override method that calculates freeform extent to return the image size. Another way is to add mouse-transparent ImageFigure to diagram layer; in this case freeform extent should be large enough to fit background and so there should be scrollers.

How do I prevent figure overlap?

  • Q: How can I prevent my figures in the editor to overlap?

i.e. when the user moves/drags them around, I want to prohibit positions when one is displayed on top of another (think of a graph editor where the nodes are small circles - I don't want them to overlap).

  • A: This topic was already discussed but there are two possibilities: constrain node location on move (adjust location in SetConstraintsCommand or add vetoing command from another edit policy when location is bad) or do special layout after each diagram modification that will relocate overlapping figures. You could do the both to ensure that your nodes never overlap - even when location is altered from another editor.

How to have children of an entity removed automatically?

  • Q: I'm having trouble in getting the children of an entity be removed automatically: my purpose is to add and remove _transient_ children of an entity when changing an unrelated attribute, such as the name of the entity.

The solution I adopted is to modify the setName() method in the EMF-generated impl class, adding the proper eSet calls.

The result is, when editing a diagram with the generated editor, changing the name of such an entity triggers an update in the children list adding figures for newly-added children, but *not removing* figures for the just-removed children, which have been semantically removed, but not graphically.

Closing and re-opening the diagram results in the removal of the orphan figures.

  • A: Generated ???CanonicalEditPolicy is responsible for adding/removing visual elements on any changes in underlying domain model. Looks like it works incorrectly in this situation. Can you please debug it to find the reason (put a breakpoint into getSemanticChildrenList() method and see what's happening on renaming an entity)?

As a workaround you can call ???CanonicalEditPolicy.refresh() the the corresponding changes will be applied.

The Fact that should Delete View is overridden in some cases is actually done on purpose and it is not arbitrary. To explain, consider the case where you have a canonical container that can contains both canonical and non canonical views for example the diagram surface can display both canonical views, and Notes (keep in mind notes had no semantic elements, so note views will be considered orphaned). If should delete view returns true always, then when your container is refreshed it will delete all notes on it (actually it will delete any view that had no semantic element).

You can always override this method and make it return true in your specific case, I would not recommend return true always

for an example of a container that can contain canonical and non canonical views, check the circuit compartment in the GMF Logic example, where this compartment is canonical when is comes to LED's, but it can contains Notes as well.

How to change an attribute of an object when clicked?

  • Q: I am working in the creation of a gmf editor, and I would like to be able to change an attribute of an object when it is clicked, for example the color.

I have read the topics related: http://dev.eclipse.org/newslists/news.eclipse.technology.gmf/msg03725.html http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/msg01089.html

and added a new class extending OpenEditPolicy, and also installed that EditPolicy in the appropiate EditPart file, but it does not seem to work.

I am not sure OpenEditPolicy is the class I should extend for my case. I would really glad if someone could give me a hint.

  • A: To handle double-click you should install custom subclass of OpenEditPolicy for the desired editpart:
protected void createDefaultEditPolicies() {
…
    installEditPolicy(EditPolicyRoles.OPEN_ROLE, new SubclassOfOpenEditPolicy());
}

As a result, SubclassOfOpenEditPolicy.getOpenCommand(Request request) will be called and corresponding command will be executed on double-clicking to the diagram node. Be careful – you should select whole node first (selection frame around the node should be visible) and only then double-click to the node. If you double-click on node without selection there is a big chance to hit inner compartment or label and then corresponding child element will be selected instead of Double-click command execution.

How to access attributes of an object related to a node?

  • Q: have already installed my custom subclass of OpenEditPolicy in my ObjectEditPart and I have added code to the function SubclassOfOpenEditPolicy.getOpenCommand(Request request) in this way:
protected Command getOpenCommand(Request request) { 
    EditPart targetEditPart = getTargetEditPart(request); 
if (targetEditPart instanceof IGraphicalEditPart) { 
IGraphicalEditPart editPart = 
(IGraphicalEditParttargetEditPart; 

editPart.getContentPane().setBackgroundColor(ColorConstants.red); ....

So, as expected, when the node is double-clicked it turns red. My problem now is how to access the attributes of the object related with that node.

  • A:
    ((View) EditPart.getModel()).getElement()
    is a correct way to access underlying domain model element.

How to notify the diagram when domain model changes?

  • Q: From a property tab sheet I'm creating/deleting/editing some EMF elements that do not have a graphical representation. Once the changes are made I want to save the diagram but as the diagram has not been changed I am not allowed to save. You must make a change in the diagram to be able to save it.

Does anyone know how to make a notification to the diagram warning it that something has been changed?

  • A: Take a look on generated ???DocumentProvider.CustomModificationListener - this code is responsible for making editor dirty. Looks like some of the necessary notifications are not handled there.

I found the solution in reply of one of you answers: http://dev.eclipse.org/newslists/news.eclipse.modeling.gmf/msg00329.html

NotificationFilter setFilter = NotificationFilter.createEventTypeFilter(Notification.SET);
NotificationFilter addFilter = NotificationFilter.createEventTypeFilter(Notification.ADD);
NotificationFilter addManyFilter = NotificationFilter.createEventTypeFilter(Notification.ADD_MANY);
NotificationFilter removeFilter = NotificationFilter.createEventTypeFilter(Notification.REMOVE);
NotificationFilter removeManyFilter = NotificationFilter.createEventTypeFilter(Notification.REMOVE_MANY);
NotificationFilter diagramResourceModifiedFilter = setFilter.or(addFilter.or(addManyFilter.or(removeFilter.or(removeManyFilter))));

So problem solved!!

Why does removing a link from the diagram not remove the underlying element?

  • Q: I can hit the breakpoint set in NotationViewDependentsAdvice. However, I was unfortunately not be able to hit my breakpoint set in the Advices methods in the domain model, specifically, I overwrite getDestroyDependentsCommand(...) method in my XXXEditHelper class, but I found the execution flow never reach that method when I delete a figure with link to other figures.

Consequently, the Node and Edge are removed from the view, the Object represented by the node is also removed from the domain model, but the object representend by the edge doesn't.

Do you know where I am wrong?

Another finding, the Edge is NOT actually removed from the view, it is still there, just not visible to user (since no target Node). I reach to this conclusion because every time after I have mannually removed the link object from the domain model xml file, and then I do some operation like arrange figures and save the diagram file, I found the removed link object come out like a ghost in the domain model xml file.

  • A: The NotationViewDependentsAdvice, will delete the edges connected to the view but it will not delete the semantic element for the edges it is destroying; since this semantic element might be used but other edges. If you need to delete the semantic element when the edge is deleted you need to handle that in your own advice, but be careful since the semantic element might be used by other views.

Why does MultiClientContext.includes() return true only if all the children contexts return true?

  • Q: I just noticed that MultiClientContext.includes() returns true if ALL of the child contexts' includes() return true. Why is that? I'm using a single editor to edit objects from multiple plugins, so each plugin must have the same editing domain, which results in a MultiClientContext. Only one of the children will return true (as only one plugin is aware of the element type); there is no way that multiple contexts will return true, so therefore the MultiClientContext will never return true.

I was wondering about the design decision to make MultiClientContext return true only if all contexts return true; it seems the opposite of what I'm looking for ;) but it could be my interpretation of contexts is incomplete or incorrect.

I ran into this issue from lines 135 and 136 of SemanticEditPolicy:

IElementType elementType = ElementTypeRegistry.getInstance()
.getElementType(completedRequest.getEditHelperContext());

DefaultMetamodelType.getInstance() is being returned because only one client context can service the request, though the response from that client context is exactly what I was hoping would be returned.

  • A: The behaviour of the MultiClientContext is based on the idea that it's easier to control an application's behaviour if you have to deliberately include element types and advice in your context rather than exclude them. The idea is that if an EObject is recognized by more than one client context, only the intersection of the advice and edit helpers in those contexts will be applied to the object.

Suppose we have applications A and B that operate on the same metamodel and share the same context criteria (e.g., editing domain), but each defines its own set of editing behaviour. If the MultiClientContext included advice and element types from both applications, it's possible (probable?) that the behaviour in one application will contradict the other.

When two such applications are co-deployed, there likely needs to be a third party that makes sense of the integration. In your case this might be the plugin that defines the single editor. It could 'merge' the contexts together by binding each to the types and advice from the others. Or maybe your application would be best represented by a single client context described by the shared editing domain?

Or do your different client contexts work with distinct metamodels in the same editing domain? If so you could restrict the criteria for each context to reflect this.

Another option is to specify the client context on your requests (IEditCommandRequest#setClientContext), so that there is no question which element types and advice should be used to perform the semantic editing. But that requires customizing tools, etc, to set the appropriate client context.

Maybe it would be nice to have an easy way for an 'integrator' (like your plugin that defines the single editor) to merge contexts? Any suggestions you have to make the API easier to work with would be most welcome.

How do I draw an ellipse inside another ellipse?

  • Q: I'd like to have an Final Activity Figure in my Figure Gallery where a filled ellipse is surrounded by another one that is not filled. I tried to add one ellipse as Child to the other one, but it doesn't work
  • A: here is an example on how to achieve what you want without creating extra figure:
package root.diagram.edit.parts;

import org.eclipse.draw2d.Ellipse;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.graphics.Color;

public class MyFigure extends Ellipse {

    /**
     * Fills the ellipse.
     * @see org.eclipse.draw2d.Shape#fillShape(org.eclipse.draw2d.Graphics)
     */
    protected void fillShape(Graphics graphics) {
        graphics.pushState();
        graphics.setBackgroundColor(new Color(null,255,255,255));
        graphics.fillOval(getBounds());
        graphics.popState();
    }

    public void paintFigure(Graphics graphics) {
        super.paintFigure(graphics);
        graphics.pushState();
        graphics.setBackgroundColor(new Color(null,0,0,0));
        double scaleFactor = 0.8;
        Rectangle rect1 = getBounds().getCopy();
        Rectangle rect = getBounds().getCopy().scale(scaleFactor);
        rect.x = rect1.x + (int)Math.floor(rect1.width*(1-scaleFactor)/2);
        rect.y = rect1.y + (int)Math.floor(rect1.height*(1-scaleFactor)/2);
        graphics.fillOval(rect);
        graphics.popState();
    }
}

If you use this figure instead of the Ellipse figure in your edit part, it should work. Without wasting an object (the extra figure)that basically does nothing but draw the inner ellipse

How can I hide an edge on a diagram?

  • Q: I've added an action to the diagram content navigator, wich allows me to select model elements and to show/hide them in the diagram (corresponding edges should be hidden too).

This works well for nodes. But the behavior of edges seems strange to me:

1. Hiding a node results in hiding all target egdes. But only one source egde gets hidden (while all edges have visible="false").

2. Setting the visibility of a hidden node back to true results in edges appearing in the upper left corner, not connected to any nodes (visually).

Everything is fine, when I reopen the diagram. Any ideas where the mistake is?

Following code is executed:

protected CommandResult doExecuteWithResult(
    IProgressMonitor progressMonitor, IAdaptable info)
        throws ExecutionException {

    boolean visible = !this.selectedView.isVisible();
    List sources = this.selectedView.getSourceEdges();
    List targets = this.selectedView.getTargetEdges();
    for (Object o : sources)
    {
        ((Edge)o).setVisible(visible);
    }
    for (Object o : targets)
    {
        ((Edge)o).setVisible(visible);
    }
    this.selectedView.setVisible(visible);
    return CommandResult.newOKCommandResult();
}
  • A: Setting the view visibility to false will result in the removal of the view's edit part from the diagram.

As a result all connected edges to this view should disappear from the diagram surface regardless of their visibility status, otherwise these edges will be pointing to/from nowhere and might show up in the upper left corner.

To achieve this, refresh had to be called on any edit part connected to the edit part being removed.

Shape compartments do this by using a ConnectionRefreshMgr take a look at ShapeCompartmentEditPart#ConnectionRefreshMgr

I'm guessing that in your case the views are direct children of the diagram, not inside a shape compartment.

What i suggest is, just set your nodes visibility to false no need to change the visibility in the edges for now. Place a break point in refresh method in AbstractGraphicalEditPart, make sure it get called on any edit parts that is connected to the edit part being removed.

for example : if your diagram looks like this

    A --> B
    |---> C
    |<--- D

Setting the visibility on A to false ; should result in refreshing B,C and D

If this is not the case; then this is a bug in GMF runtime

Is it possible to render diagram images running headless?

  • Q: Assume we are given a model instance file and a corressponding notation file. Is there a change to produce an image of the given instance using the GMF API without launching the Eclipse UI?
  • A: You can produce an image without bringing up an editor within Eclipse if this is any help.

See OffscreenEditPartFactory and CopyToImageUtil for details.

When the Diagram UI plugin starts up it initializes the preference store with font values. It is calling JFaceResources.getDefaultFont() and when a new font registry is created in SWT it requires a Display.

We have not supported this use case in the past, but I don't see why we shouldn't be able to support it assuming SWT supports this somehow. Maybe there is another way we can get the default font. I would suggest you create a bugzilla and someone can look into it.

How do I prevent the destruction of an element?

  • Q: I have a problem with the DestroyElementRequest. I want to check some condition just before deleting an element from diagram so that DestroyElementCommand may be not executed. I use approveRequest() in FlowEditHelperAdvice (Flow is the diagram name):
@Override
     public boolean approveRequest(IEditCommandRequest request) {
           if (request instanceof DestroyElementRequest) {
                if.....return true;
                else return false;
}
return true;
}

Unfortunately this method will be called with DestroyElementRequest even if no elements were deleted. How can I solve this problem?

  • A: I'm not sure that I understand what you are trying to do.

The #approveRequest() method can be used to indicate that your system does not provide a command to delete the semantic element, as it has been requested. No elements will be deleted unless an executable command is returned by the system. By implementing #approveRequest() to return false, you make it so that no elements will be deleted as a result of the request.

If you want to wait to do this check until the command to delete the element (and its dependents) is actually being executed, then you can implement #getBeforeDestroyElementCommand() instead and return a command whose #doExecuteWithResult() method will cancel the progress monitor. This will cause the destroy command to stop executing and to rollback any changes it has made up to that point.

How can I tell were in my generator model I have a validation error?

  • Q: When the validation fails (as part of the .gmfgen generation), ones currently has to to do a lengthy manual tree search like procedure to figure out, where and which element one has got wrong. It would be cute, if the validation would automatically directly anotate or "decorate" any offending line in the treeview so that one would be aware that something's fishy right away.
  • A: If validation fails (as part of the .gmfgen generation) you can execute GMFGen Editor/Validate or GMFMap Editor/Validate action. Both produce validation markers in the 'Problems View' which allow to navigate to the affected elements in the model tree view.

How to create required elements on diagram when created?

  • Q: For my application I would like to have the graphical editor come up with two predefined containers (I fancy two large labeled rectangles) inside which the user then starts creating sub-elements and connecting them, etc.

This corresponds to two top-level elements that *always* have to be present in the XML files that I am dealing with. I don't want to have to create these outermost elements, they simply should be there right from the begin (i.e. even if creating an new "empty" file or model).

Can one create such fixed and predefined figures? How?

  • A: You may remove tool references for this "fixed" mappings in the Map model,

effectively removing creation tools for them. Then write custom code that creates this 2 fixed elements in the generated <Model>DiagramEditorUtil#createInitialModel(), something like

/**
* Create a new instance of domain element associated with canvas.
* @generated NOT
*/
private static org.eclipse.uml2.uml.Package createInitialModel() {
org.eclipse.uml2.uml.Package root = UMLFactory.eINSTANCE.createModel();
root.setName("Model");
createDefaultPrimitiveTypeImports(root);
return root;
}

How do I set a ConnectionRouter?

  • Q: I would like to use ManhattanConnectionRouter in my application. I try to set the ConnectionRouter in my Top Editpart but failed. It seems that the way in traditional GEF application do not work. I wonder in which way I could customize the router?
  • A: I do it in the view factory corresponding to the connection:
public class ConnectionViewFactory extends
        org.eclipse.gmf.runtime.diagram.ui.view.factories.ConnectionViewFactory {

    protected List createStyles(View view) {
        List styles = new ArrayList();
        styles.add(NotationFactory.eINSTANCE.createRoutingStyle());
        styles.add(NotationFactory.eINSTANCE.createLineStyle());
        styles.add(NotationFactory.eINSTANCE.createFillStyle());
        return styles;
    }

    protected void decorateView(View containerView, View view,
            IAdaptable semanticAdapter, String semanticHint, int index,
            boolean persisted) {
        if (semanticHint == null) {
            semanticHint = Bluenose2VisualIDRegistry
                    .CONNECTION_VISUAL_ID;
            view.setType(semanticHint);
        }

        super.decorateView(containerView, view, semanticAdapter, semanticHint,
                index, persisted);

        RoutingStyle rstyle = (RoutingStyle) view.getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
        rstyle.setAvoidObstructions(true);
rstyle.setRouting(Routing.MANUAL_LITERAL);

}

}

Is Affixed Parent Side only respected on creation?

  • Q: The constraint seems to be checked only at the element creation. For example, I have configured my graphical defintion with the property set as "WEST" to only attach objects on the left of the container node. Then, in my generated editor, when I create a child element, this work well, the element is attached to the left border of its container. But when I try to move it, I can also attach it to the right border. I would have expected to "only" enable attachment to the left border as this was done at the creation.
  • A: The runtime actually uses the affixed side as a hint only, and does not

prevents manual relocation. You need to install custom implementation of org.eclipse.gmf.runtime.diagram.ui.figures.IBorderItemLocator that prevents this.

How can I show/hide compartment contents programmatically?

  • Q: I need to show and hide compartment view dynamically. I'm developing a Use Case Diagram Editor. When I create a extend relationship between 2 usecases, I would to create show the compartment

view containing the extension points.

How can I show or hide the compartment view at the creation of a extension point?

  • A: Looking for this in ResizableCompartmentEditPart:
protected void handleNotificationEvent(Notification event ) {
        Object feature = event.getFeature();
        if (NotationPackage.eINSTANCE.getRatio_Value().equals(feature) 
            || event.getOldValue()instanceof Ratio
            || event.getNewValue() instanceof Ratio)
            refreshRatio();
        else if (NotationPackage.eINSTANCE.getDrawerStyle_Collapsed().equals(feature)){        
            setCollapsed(event.getNewBooleanValue(), true);
            this.getFigure().revalidate();
        } else if (NotationPackage.eINSTANCE.getTitleStyle_ShowTitle().equals(feature))
            setShowCompartmentTitle(event.getNewBooleanValue());
        else if (NotationPackage.eINSTANCE.getFontStyle_FontColor().equals(feature)){
            Integer c = (Integer) event.getNewValue();
            setFontColor(DiagramColorRegistry.getInstance().getColor(c));
        }

tells you can use an AbstractTransactionalCommand that calls GraphicalEditPart#setStructuralFeatureValue with the correct feature.

How to change the view of an existing element?

  • Q: Basically I want to switch between two visual styles of one EditPart. So, I think i will add a property to the semantic model, wich indicates what style the EditPart should have and add a logic to the EditPart's class accordingly. I don't know, if this is the right approach. But it seems to work.
  • A: For interested parties:

I'm creating a petrinet editor to become familiar with GMF. Transition nodes (simple rectange figures) should be able to be switched between vertical orientation and horizontal oriantation.

I added the following code to 'TransitionEditPart.java':

protected void handleNotificationEvent(Notification notification) {
    Object feature = notification.getFeature();
    if (PetrinetPackage.eINSTANCE.getTransition_Vertical().equals(feature))
    {
        refreshBounds();
    }
    else
        super.handleNotificationEvent(notification);
}

protected void refreshBounds() {

    Dimension size = getPrimaryShapeDimension();
    int x = ((Integer)
getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_X())).intValue();
    int y = ((Integer) 
getStructuralFeatureValue(NotationPackage.eINSTANCE.getLocation_Y())).intValue();
    Point loc = new Point(x, y);
    ((GraphicalEditPart) getParent()).setLayoutConstraint(
        this,
        getFigure(),
        new Rectangle(loc, size));
    }

protected Dimension getPrimaryShapeDimension() {
    Transition t = (Transition) this.resolveSemanticElement();
    if (t.isVertical())
        return new Dimension(40, 10);
    else
        return new Dimension(10, 40);
    }

Another possibility could be to register two different mappings and differentiate between them using MappingEntry.domainSpecialization constraint. An example of this approach can be found in the MindMap project used in tutorial (three different link mappings are used for the domain element Relationship).

The advantages of having two distinct elements are the following: 1. You may associate completely unrelated figures with these two elements (this may not bee needed in your scenario, although you might use figures with fixed sizes 10x40 and 40x10, respectively); 2. You might associate different creation tools with these elements (but still have one creation tool if you don't need two); 3. You might associate element initializers with these elements, so as to initialize your orientation based on the element you are creating. 4. This approach can be easily adapted to the situation when the visual aspects of an element depend on multiple features, all you need is to modify the OCL expression in the *.gmfmap.

Disadvantages are: 1. You have more code generated. This may be a problem as the number of @generated NOT's increases; 2. If the visual aspects depend solely on a single attribute of the semantic element, OCL may seem an overkill; 3. There is a known problem in the generated diagram editor that a XXXCanonicalEditPpolicy might fail to always update the ElementType on a change in the domain model that affects the element type. (this problem is not present in the lite runtime, where ANY such change is guaranteed to be processed correctly).

Having two different mappings was my very first approach. It seems to be the most logic way, having two independent visual elements, which can be associated to an element. But I just can't see how to change the visual component of an existing element (in a way different to how I mentioned before).

In fact, this should be automatic (provided that the node is canonical). The fact that it does not update is due to 150257.

How can I add a tooltip to a diagram element?

  • Q: Anyone konw how to add tooltip for element on the diagram?
  • A: There are no tooltip support in the gnfgraph model.

You may try to to add something like the code below to the generated <DiagramElement>EditPart.

/**
* @generated NOT
*/
protected IFigure createFigure() {
IFigure result = super.createFigure();
result.setToolTip(new Label("My diagram tooltip"));
return result;
}

How to enable drag-n-drop from the palette?

  • Q: It seems that the only way to create nodes using the palette is by first clicking on the tool from the palette, releasing the button, then moving the mouse to the creation point on the canvas (a "+" sign is displayed with the mouse cursor) then clicking again to actually create a new node.

I have a user request for "traditional" drag&drop where you would left-click on a palette tool, move the mouse to the drop point (keeping the mouse button pressed) and release the mouse button in order to create the node.

I've found two bug reports that claim that drag&drop is available (resolved/fixed):

Can not add elements to diagram doing drag and drop from palette

Support drag-n-drop

Is this possible in GMF 1.0.1? Is this a behavior inherited from GEF that can't be changed?

  • A: This works in the GMF Geoshapes Example, but not in the generated Taipan Example so it looks like the GMF generation capabilities does not support this yet. Take a look at PaletteToolTransferDropTargetListener to see how this is implemented in the GMF Runtime.

How can I remove the connection handles from my diagram?

  • Q: I just don't know what the little tool shown in http://www.volker-wegert.de/files/attic/connector-tool.png is called... Anyway - is there a way to disable this tool for a single object or for the entire editor? I'm trying to create a VE-like dialog editor that doesn't work with connections, so I don't really need this tool...
  • A: It's ConnectionHandleEditPolicy that adds these handles. You'll need to remove edit policy registered for EditPolicyRoles.CONNECTION_HANDLES_ROLE (which is added in ShapeNodeEditPart, default edit part for all generated nodes).

How can I modify what is provided in the model assistance popups?

  • Q: Using the help guide, I've been able to figure out how to add tools to the palette. I haven't been able to figure out, however, how to change the behavior for when you hover over the document. Right now, one of my model objects shows up twice in the menu- I see "Add Node", "Add Link", and then "Add Node" again. I don't want to see "Add Link" at all (it's a connection), and I only want to see "Add Node" once. I started with the gmfgen file, but I need to work with and make changes directly to the generated code, so I'm trying to figure out how to modify the code/plugin.xml directly.
  • A: Check subclasses of ModelingAssistantProvider.

The default behavior of the PopupBarEditPolicy installed on the diagram will get the popupbar items based on the items on the last active drawer in the palette. Put a breakpoint in DiagramPopupBarEditPolicy.fillPopupBarDescriptors() to understand what is going on.

The default behavior of the PopupBarEditPolicy installed on other editparts, is to get the list of types for the popupbar from the Modeling Assistant Service. Check out the method getTypesForPopupBar().

How can I remove model assistant popups entirely?

  • Q: GMF automatically creates a palette of icons when you hover the mouse in an editor window--the palette of things that can be inserted into the current object. My boss does not like the look of it; is there any simple way to turn it off?
  • A: Remove edit policy with key EditPolicyRoles.POPUPBAR_ROLE from all node and compartment edit parts. Or PopupBarEditPolicy if it's registered by other key.

You could also easily control this with a preference option if you wanted. Support for this is already in GMF. The GMF Logic Diagram Example has this in its preference pages.

How can I allow for the rearrangement of items in a compartment?

  • Q: How do I manage to rearrange items in a Compartment? For instance, in the Mindmap tutorial example, it is easy to create a Thread with a bunch of Thread Items, but suppose after I create the Thread Items I want to rearrange them. Is there any way to make a (user interface) control to do that? I can't seem to figure it out.
  • A: This has to do with the layout edit policy installed on your compartment edit part. Here's a configuration that works for me. The ShapeCompartmentEditPart installs an XYLayoutEditPolicy that allows you to rearrange things in your compartment.

You can ignore the last two other edit policy installed on this edit part:

public class BlockChildrenCompartmentEditPart extends ShapeCompartmentEditPart {

    public BlockChildrenCompartmentEditPart(View view) {
        super(view);
    }

    public String getCompartmentName() {
        return "BlockChildrenCompartment";
    }

    public IFigure createFigure() {
        ResizableCompartmentFigure result = (ResizableCompartmentFigure) super
                .createFigure();
        result.setTitleVisibility(false);
        return result;
    }

    protected void createDefaultEditPolicies() {
        super.createDefaultEditPolicies();
        installEditPolicy(EditPolicyRoles.CREATION_ROLE,
                new CreationEditPolicy());
        installEditPolicy(EditPolicyRoles.DRAG_DROP_ROLE,
                new DragDropEditPolicy());
        installEditPolicy(EditPolicyRoles.CANONICAL_ROLE,
                new BlockCanonicalEditPolicy());
        installEditPolicy(EditPolicyRoles.SEMANTIC_ROLE,
                new BlockChildrenCompartmentCreationEditPolicy());
}
...

}

The edit parts contained in this compartment extend ShapeNodeEditPart.

How can I make my domain element aware of a view element's coordinates?

  • Q: I have a figure (Field) in a compartment, when the user set its position, it gets x and y values in the view. So i want that the corresponding object in the model (also Field :) ) get its values for x and y from the view coordinates. Must I implement a move-listener for the figure?
  • A: Do you have your own editpart for this model element? Why don't you just listen to changes to the location in the view and then update your element? Check out ShapeEditPart.handleNotificationEvent().

Here you have a snippet of my code...

This is the method from my <DomainModel-Name>.diagram.edit.parts.FieldEditPart

/**
* @generated not
*/
protected void handleNotificationEvent(Notification arg0) {
  // SET was the type i need
  if (arg0.getEventType() == Notification.SET) {
    // the notifier sends his new Bounds ...
    if (arg0.getNotifier() instanceof BoundsImpl) {
      BoundsImpl notifier = (BoundsImpl) arg0.getNotifier();
      // for my special coordinate mapping i also need the node,
      // so i save it in this variable ...
      NodeImpl node = (NodeImpl) this.getModel();
      // get the corresponding FieldLabel Object from the model
      FieldLabel model = (FieldLabel) node.getElement();

      if (arg0.getFeature() instanceof EAttributeImpl) {
        // Get the attribute that has changed
        EAttributeImpl attribute = (EAttributeImpl) arg0.getFeature();
        // set the values for x and y in the model
        if (attribute.getName().equals("x")) {
          model.setX(notifier.getX());
        } else if (attribute.getName().equals("y")) {
          model.setY(notifier.getY());
        }
      }
    }
  }
}

So everytime the bounds change the information is stored in the model. If the user moves the FieldFigure or if the values are changed in the editor doesn't matter.

How to make copy/paste work on compartments?

  • Q: I've managed to get pasting into compartments to work. The main issue I had was that copy & paste worked just with the top level diagram.
  • A: In summary, the gmf copy & paste implementation can be easily modified to work with compartments but for some reason it doesn't allow it.

Hope this helps other folks.

The following in the NotationClipboardOperationHelper class have to be overridden (fork the class because some methods are private):

static EObject getSemanticPasteTarget(View view) {
        Diagram diagram = getContainingDiagram(view);
        if (diagram != null) {
            return diagram.getElement();
        }
        return null;
    }

should become smth like

static EObject getSemanticPasteTarget(View view) {

View parent = (View) view.eContainer();

return parent.getElement();

}

and

private boolean shouldAllowPaste(
            PasteChildOperation overriddenChildPasteOperation) {
        EObject eObject = overriddenChildPasteOperation.getEObject();
        EObject parentEObject = overriddenChildPasteOperation
            .getParentEObject();
        if ((parentEObject instanceof Diagram) && (eObject instanceof View)) {

....
}

should be modified to allow pasting into Nodes, too.

How to create two unsynchronized diagrams for one domain model instance?

  • Q: I have created a model and a diagram editors in GMF, let's say MyEditor. MyEditor works well with one diagram per model. But when I initialize a second diagram from the same model and delete or add something there, it gets reflected in the first diagram and also in the model itself. Is it possible to create two diagrams of the same type for one model and have instances in the model and only references in the diagrams, so that when I delete a node in one diagram, it stays both in the model and the other diagram? I want the model to be union of all diagrams.

Said in simple words I want something like the repository-based UML tools - have one repository and many class diagrams to it. The repository is the union of all diagrams.

Is there a native support in GMF for this, or I should create my own implementation? If so, can you advise me where to start from?

  • A: Try making your diagram non-synchronized (see: Synchronized).

How can I position a label at the end of a link?

  • Q: I want to add a Label at the end of a (decorated) connection which should represent the target (source) cardinality of the connection. What could i add to my PolyLine Connection in my .gmfgraph file?

One thing i tried was a BorderLayout as child from the Connection and a FigureRef also as child. Then the FigureRef gets the BorderLayoutData (END). But this didn't work out. Is there a build in possibility to solve this? Or must i implement an own Layout?

  • A: In gmfgraph model add AlignmentFacet to the DiagramLabel. In this facet you may select appropriate label alignment relative to the link.

Use Label Offset Facet to adjust the position.

How can I constrain node movement/resize?

  • Q: What is the GMF way of constraining how/where can the user move(drag) / resize Figures (editParts) ?

For example, I want to allow moving/resizing them, but I want to prevent figures to overlap. (e.g. in GEF, what I did was to create a SetConstraintCommand, and check my constraints in canExecute())

How do I achieve something similar in GMF ?

  • A: You could specify resize constraint in gmfgraph model for the node but this particular case is different; I'd suggest you to try 'veto approach': add edit policy that contributes command in cases when SetConstraintCommand is returned. In this command check that nodes overlap with the new bounds; if it's so return 'false' from canExecute().

If you are that pretty strict about layout constraint maybe it would be better to hide it from the properties view? And there is one more way to change it - modify xml with notation model externally and reopen the diagram.

How can I create two different containers for a single type of node?

  • Q: I am trying to be able to drag and drop various SubNodes (represented using 1 class in my meta-model and 1 rectangle in my gmfgraph) into two different containers layed out (using a BorderLayout) into one single SuperNode (1 class in my meta-model and 1 rectangle with 2 internal rectangles associated to 2 containers in my gmfgraph).

The idea is to be able to have a SuperNode with various SubNodes placed on the left and right sides of the SuperNode.

The problem is in the mapping!! I can't define two different compartment mappings using the same SubNode child; if I do so, whenever I drag & drop a SubNode into one of the compartments, another one appears also in the other compartment.

I have tried to solve this problem creating different SubNode Rectangles (LeftSubNode and RightSubNode) in the gmfgraph and then associate them to the LeftCompartment and RightCompartment, respectively in the gmfmap. But it doesn't work either.

The only solution seems to be changing the meta-model to add two different kinds of SubNodes (LeftSubNode and RightSubNode). But I don't want to do that since the SubNode domain concept should be unique in the meta-model (there is only one kind of SubNodes, independently of the fact that they appear graphically on the right or on the left side of the SuperNode).

  • A: Guess, there's no need to modify your domain model and to keep there information which compartment SubNode belongs to.

It's possible to define two (or more) compartments for same SubNode, the .gmfmap should look like:

NodeMapping SuperNode
ChildReference compartment=Left
ownedChild NodeMapping SubNode
ChildReference compartment=Right
referencedChild NodeMapping SubNode

Note use of referencedChild instead of ownedChild in the second (and subsequent) child references.

With this, you get exactly one SubNode concept, and we get to another part of the problem, subnodes being automatically added to all compartments. You can approach this problem either with keeping your diagram not automatically synchronized (GMFGen.GenDiagram#synchronized attribute), which means generated code won't try to add elements automatically; or you can keed whole diagram synchronized and fix canonical edit policy of the compartments only not to process domain notifications (ADD/SET) and not to add children. I'd recommend the former approach because it rarely makes sense to have synchronized diagrams anyway.

How to change the color of the editor canvas?

  • Q: I want to change the colour of the editor canvas. Is there anyway by which I can do this?
  • A: Override createFigure() in your DiagramEditPart. By calling super.createFigure() you get a reference to the IFigure. You can then set the background colour directly for this figure. You also need to set it to be opaque.
protected IFigure createFigure() {
  IFigure fig = super.createFigure();
  fig.setBackgroundColor(ColorConstants.green);
  fig.setOpaque(true);
  return fig;
}

How to create a gmfgraph CustomLayout?

  • Q: How can I create a CustomLayout? Are thery any tutorial, guides? Which class should I sub-class, what methods should I overwrite, etc.
  • A: gmfgraph.CustomLayout is just a gate to the custom implementation of the org.eclipse.draw2d.LayoutManager class. Thus there is in fact 2 questions -- how to write draw2d Layout manager and how to plug it into the gmfgraph.

I can try to answer the second one.

Imagine you have com.xyz.SuperLayout class in the com.xyz.misc plugin. The SuperLayout class has method setBoolParam(boolean) and public instance field int myIntParam; It also expects the instanceof SuperLayoutData that has setter setStringParam(String s).

To plug this into gmfgraph you need:

1. Create separate ResourceGallery, set implementation bundle to "com.xyz.misc" 2. Create figures structure. 3. In the container node create CustomLayout, set fqn = "com.xyz.SuperLayout". Note that bundleName property of CustomLayout is deprecated and not used, it does not make sense to change it. 4. In the just created Custom Layout create custom attribute, set name = boolParam (or BoolParam -- it doesnot make sense) -- the name is derived from setter name, value = (say) "false" or "42 / 2 >= 21". 5. Create one more custom attribute, name = "myIntParam" (derived from field name), value = "42", isDirectAccess = true. 6. In the child figure create CustomLayoutData, set fqn = "com.xyz.SuperLayutData", repeat step 4 for custom attribute "StringParam" if needed.

Note that values set at the steps 4, 5 are considered opaque and just generated into the setter call or assignment statement as is. Thus, to set the string value "MG" for custom attribute StringParam you need to set value = "MG" (with quotes).

How to open a dialog for editing elements?

  • Q: I am trying to display a dialog for editing elements.

Following this post and another one that I cannot find now, it suggested that a dialog could be placed in the getOpenCommand() method and return null for the command. That works to display the dialog, but it does not work for edits.

Can anybody give me an idea of what to do differently?

I think I need to look at the command that is returned, but I have been unable to find any documentation on commands.

I would like to be able to double click on a graphical element and display a dialog that the user can edit information about that element or the model in general. Like the properties window except in a dialog.

The following code displays the dialog, but I cannot seem to figure out how to update the model from here.

public class OpenEditorEditPolicy extends OpenEditPolicy {

protected Command getOpenCommand(Request request) {
EditPart targetEditPart = getTargetEditPart(request);
if (targetEditPart instanceof IGraphicalEditPart) {
IGraphicalEditPart editPart = (IGraphicalEditPart) targetEditPart;
View view = editPart.getNotationView();
if (view != null) {
EObject element = ViewUtil.resolveSemanticElement(view);
if (element instanceof Operation) {
System.out.println("found operation");
Shell shell = new Shell(SWT.DIALOG_TRIM | 
SWT.PRIMARY_MODAL);
OperationComposite editor = new OperationComposite(shell, 
SWT.NONE);
shell.open();

// This makes the system unstable.
// while (!shell.isDisposed ()) {
// Display.getCurrent().sleep();
// }

return new ICommandProxy(new EditOperationCommand(element));
}
}
}
return null;
}
}
  • A: To learn more about commands, explore the IUndoableOperation type hierachy to see what type of commands GMF defines. Take a look at AbstractTransactionalCommand.

NOTE: if you need to return these commands from an EditPolicy they must be wrapped by an ICommandProxy (this makes a GMF command look like a GEF command).

hope this helps, vlad

Here are some steps you should take, substitute your concrete example accordingly.

Add an editor action in your plugin.xml:

<extension point="org.eclipse.ui.popupMenus">
  <objectContribution
     adaptable="false"
     id="ca.uwaterloo.watform.bluenose2.diagram.ui.actions.Bluenose2GenerateVHDLAction"
     objectClass="org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart">
  <action 
    label="Generate VHDL"
    class="ca.uwaterloo.watform.bluenose2.diagram.ui.actions.Bluenose2GenerateVHDLAction"
    menubarPath="additions"
    enablesFor="1"
    id="Bluenose2OpenGenerateVHDLAction">
  </action>
  </objectContribution> 
</extension>

Define a command to edit the particular model element as follows, add more parameters etc.

public class GenerateVHDLCommand extends AbstractTransactionalCommand {

private EObject modelElement;

    public GenerateVHDLCommand(EObject modelElement, TransactionalEditingDomain domain,
         String label, List affectedFiles) {
        super(domain, label, affectedFiles);
        this.modelElement = modelElement;
    }

    protected CommandResult doExecuteWithResult(
            IProgressMonitor progressMonitor, IAdaptable info)
            throws ExecutionException {
        //example here        
        return CommandResult.newOKCommandResult(/*VHDLGenerator.generateVHDL( (Pipeline) modelElement)*/);
    }

}

in doExecuteWithResult you have read/write access to the model element so you can do whatever you want.

Create and execute this command from your action:

public void run(IAction action) {
        TransactionalEditingDomain domain = mySelectedEditPart
                .getEditingDomain();
        EObject modelElement = mySelectedEditPart.resolveSemanticElement();

        AbstractTransactionalCommand semanticCommand = new GenerateVHDLCommand(
                modelElement, domain, "Generate VHDL Command",
                Collections.EMPTY_LIST);

        try {
            OperationHistoryFactory.getOperationHistory().execute(
                    semanticCommand, null, null);
        } catch (ExecutionException e) {
            // smth Happend here
        }

        CommandResult commandResult = semanticCommand.getCommandResult();

        if (commandResult.getStatus().isOK()) {
            String result = (String) commandResult.getReturnValue();
            System.out.println(result);
        }

}

How to remove zoom palette tool?

  • Q: I am wondering how to remove Zoom palette entry. I wondered, if there might be a way to remove/add some other standard-tools like the way the removal of Zoom worked? I tried the same for the Note-dropdown-Tool, but I didn't manage to remove it. Does anyone know the correct id for this one?
  • A: you could try the following:
<extension point="org.eclipse.gmf.runtime.diagram.ui.paletteProviders"> 
  <paletteProvider class="org.eclipse.gmf.runtime.diagram.ui.providers.DefaultPaletteProvider">
    <Priority name="High"/>
    <contribution>
      <predefinedEntry
         id="standardGroup/zoomTool"
         remove="true"/>
    </contribution>
  </paletteProvider>
</extension>

There's no other way than to place remove="true" xml right now, though we are going to have complete description of the palette tools in the .gmftool model some day.

As for note tools, next should remove all note-related tools from the palette (put these next to zoom removal):
<pre>
<predefinedEntry id="standardGroup/noteStack/noteTool" remove="true"/> 
<predefinedEntry id="standardGroup/noteStack/textTool" remove="true"/> 
<predefinedEntry id="standardGroup/noteStack/noteattachmentTool" remove="true"/>

Specifying remove=true in plugin.xml works but it is not perfect. The problem is it will interfere other GMF-based editor your product has. I would like to remove Zoom tool in my editor ONLY, but Zoom is also removed from other GMF-based editor.

You need to provide criteria in the palette provider extension point to indicate that it applies to your editor only. e.g.:

<editor id="LogicEditor">
</editor>

How to extend the generated properties view?

  • Q: I am working on a project for modelling processes. The nodes have the following important attributes:

-associatedClass (EString) -customProperties (EMap)

I have two questions:

-How can I extend/edit/overwrite/whatever the default GMF/EMF Property view? I want to select the value for associatedClass from a dropdown list (similar to EEnum). -How can I add an additional tab in the Property view, which should be able to edit the customProperties attribute?

  • A: Check out the tabbed properties view article

It tells you how to add tabs and sections (fields) to the tabbed properties view.

I've put some details about how to deal with property sheet in 2.0M2 here.

How can I create a multi-line link?

  • Q: How can I draw a link in the diagram as a double line?

It shuold look like this:

--- --- | A |==============| B | --- ---

  • A: Write custom PolylineConnection that paints itself twice shifting internal PointList up and down by desired offset.

How can I right-justify items in a compartment?

  • Q: I want to layout the objects in the compartment as a row right-justified. I keep getting a stack of objects on the right. What gives? Is this a bug?
public IFigure createFigure() {
  ResizableCompartmentFigure result = (ResizableCompartmentFigure) super.createFigure();
  FlowLayout layout = new FlowLayout(true);
  layout.setMajorAlignment(FlowLayout.ALIGN_RIGHTBOTTOM);
  result.setLayoutManager(layout);
  result.setTitleVisibility(false);
  return result;
}
  • A: I found the answer by diving into the source code (as you all more learned people probably expected me to do in the first place).

A ResizableCompartmentFigure contains two children figures, a Figure for the text pane (optional) and the ScrollPane. The ScrollPane child object has a child figure itself called content. Setting the ResizableCompartmentFigure layout does nothing. Setting the ScrollPane layout does bad things (because it expects the ScrollLayout). You must instead set the layout of the ScrollPane child figure, as such:

public class FooBarCompartmentEditPart extends ListCompartmentEditPart {
...
/**
* @generated NOT
*/
public IFigure createFigure() {
    ResizableCompartmentFigure result = (ResizableCompartmentFigure) 
super.createFigure();
    IFigure fig = result.getContentPane();
    FlowLayout layout = new FlowLayout(true);
    layout.setMajorAlignment(FlowLayout.ALIGN_RIGHTBOTTOM);
    fig.setLayoutManager(layout);
    result.setTitleVisibility(false);
    return result;
}

How do I install an EditPolicyProvider?

  • Q: Is there any editpolicyprovider snippet except the one in GMF Developer Guide, in which I couldn't find the source of TraceDiagramEditPolicyProvider. In fact, I found no implementation of

IEditPolicyProvider except EditPolicyService, so I wonder how to implement the TraceDiagramEditPolicyProvider above.

  • A: All you need to do, is write the provides() method as you would in any other service, describing the type of editpart you provide for (or element of the editpart). Make sure you are specific here so as not to have your editpolicy installed on non-applicable editparts.

Then you just need to install your editpolicy on the editpart in the createEditPolicies() method.

e.g. editPart.installEditPolicy(THE_ROLE, new TheEditPolicy());

I'll add some detail, here's code for a PropertyHandlerEditPolicyProvider class, that installs a PropertyHandlerEditPolicy for the EditPolicyRoles.PROPERTY_HANDLER_ROLE role on edit parts of the types GateEditPart and AbstractVariableEditPart.

public class PropertyHandlerEditPolicyProvider implements
        IEditPolicyProvider {

public void createEditPolicies(EditPart editPart) {

editPart.installEditPolicy(EditPolicyRoles.PROPERTY_HANDLER_ROLE,
                new PropertyHandlerEditPolicy());
    }

    public boolean provides(IOperation operation) {
        if (operation instanceof CreateEditPoliciesOperation)
{
            EditPart editPart =((CreateEditPoliciesOperation)operation).getEditPart();
            if (editPart instanceof GateEditPart ||
                    editPart instanceof AbstractVariableEditPart
                    )
                return true;
        }
        return false;
    }
    public void addProviderChangeListener(IProviderChangeListener listener) {
    }
    public void removeProviderChangeListener(IProviderChangeListener listener) {
    }
}

Remember also to declare the PropertyHandlerEditPolicyProvider class in plugin.xml, as follows:

    <editPolicyProvider
       class="no.hal.diamodl.diagram.custom.providers.PropertyHandlerEditPolicyProvider">
       <Priority name="Lowest"/>
       <object id="GateEditPart"
          class="no.hal.diamodl.diagram.edit.parts.GateEditPart(no.hal.diamodl.gmf.diagram)"/>
       <object id="VariableEditPart"
          class="no.hal.diamodl.diagram.edit.abstractparts.AbstractVariableEditPart(no.hal.diamodl.gmf.diagram)"/>
       <context editparts="GateEditPart,VariableEditPart"/>
    </editPolicyProvider>

Note how the object elements declares IDs for the EditPart classes (the project/plugin name is within the parenthesis), and how the context element refers to these IDs.

How can I make multi-line and vertical labels?

  • Q: How can I create a multiline/wrapped label, like the ones for the standard Note feature? Do I have to manipulate the code for this or is there a way to do this in GMF?

Is there a way to create vertical labels, rotated 90° to the left, with the text going upwards?

  • A: I'll try to answer your questions from the runtime point of view.

To make the text wrap you should use a figure that inherits WrapLable and make sure you call setTextWrap(true) this will give you the wrapping functionality; or you can just use the DiagramNameCompartmentEditPart which will do that for you.

You can always implement the paintFigure method on your figure to do what ever you like.

There is an option to get rotated string using ImageUtilities.createRotatedImageOfString(...) but it looks not very good if text antialiasing is enabled.

How can I programmatically add a note to created elements?

  • Q: I need to create programmatically a note attachment when I create an

element in my diagram. How can I do?

  • A: The answer depends on where the code is called to create the new element in your diagram. There is an AddNoteAction in GMF that creates a new note and draws a note attachment to the element from which the action was executed. If you are doing something similar to this, you could probably reuse this code.

One idea is to override the method protected Command getCreateCommand(CreateViewRequest request) in CreationEditPolicy

This method is responsible for creating the view for the new element. You should compose this command with another that creates the views for the Note and the connection.

To see how to create a note take a look at NoteViewFactory.

You can figure a lot about how this is done by setting breakpoints in GraphicalNodeEditPolicy (gmf) while attaching notes using the Note Attachment tool.

Here's an example of how to create the note when you create an element. Modify the CreationEditPolicy for the editPart corresponding to that element type.

Maybe someone else can suggest how to add the edge.

protected Command getCreateCommand(CreateViewRequest request) {

    IElementType NOTE = ElementTypeRegistry
            .getInstance()
            .getType(
                    "org.eclipse.gmf.runtime.diagram.ui.presentation.note");

    ICommand createElementViewCommand = ((ICommandProxy) super
            .getCreateCommand(request)).getICommand();

    TransactionalEditingDomain editingDomain = ((IGraphicalEditPart) getHost())
            .getEditingDomain();

    CompositeTransactionalCommand cc = new CompositeTransactionalCommand(
            editingDomain,
            DiagramUIMessages.AddCommand_Label);

cc.compose(createElementViewCommand);

    CreateViewRequest createNoteRequest = CreateViewRequestFactory
            .getCreateShapeRequest(
                    NOTE,
                    PreferencesHint.USE_DEFAULTS);

    Iterator descriptors = createNoteRequest
            .getViewDescriptors().iterator();

    while (descriptors.hasNext()) {
        CreateViewRequest.ViewDescriptor descriptor = (CreateViewRequest.ViewDescriptor) descriptors
                .next();

        CreateCommand createCommand = new CreateCommand(
                editingDomain, descriptor,
                ((View) (getHost().getModel()))
                        .getDiagram());

        cc.compose(createCommand);
    }

return new ICommandProxy(cc.reduce());

}

The edit part corresponding to the element you need to create, must install your modified EditPolicy as follows:

protected void createDefaultEditPolicies() {
        installEditPolicy(EditPolicyRoles.CREATION_ROLE,
                new CreationEditPolicy() {
...
}

The anonymous class overrides protected Command getCreateCommand(CreateViewRequest request)

This method is called in the super class when it creates the view for a newly create element.

How can I persist my custom border?

  • Q: I created custom border following the thread "How can I use custom border?". My border's width, style, color can be changed dynamically from the appearance page. But it's not persisted. When I save, close and re-open the diagram - the borders are with their initial values. How can I persisted the values of my custom border?
  • A: Let me explain something about persisted/transient views.

Any time you create a view you have the choice of creating this view as a transient or persisted view, transient views will not be saved when you close your model, then they will be recreated the next time you open your diagram. As a result transient views always use default values for all the attributes.

The Diagram event broker will persist any transient view as soon as some one change any attribute on that view. For, example if you move the transient view on the diagram surface, which results in setting the bounds on this view, the diagram event broker will persist this view for you.

I think you should add a break point to the DiagramEventBroker#transactionAboutToCommit near the end of this method you will find it creating a PersistViewsCommand, line 312 if you have the latest GMF 1.0.1 code, then change any attribute on your border using the properties view, you should hit this break point and the view should get persisted, otherwise this might be a bug.

One more point to keep in mind, changing the attributes of the view in the View factory decorate method will not persist the view since it is done in a silent operation.

You will need to introduce a new notation style, this can be done by adding creating your own meta model that define a new notation style that extends the default notation style. Then in your view factory you override the createStyles to do something like this:

    protected List createStyles(View view) {
        List styles = super.createStyles(view);              
        styles.add(MyFactory.eINSTANCE.createCustomStyle());
        return styles;
    }

I believe there is a tutorial on how to create custom styles, try to look it up.

How can I synchronize my custom figures with the model?

  • Q: I have been using GMF and creating custom figures, the custom figures are made up of images and several label which might or might not be shown based on some logic that needs to be applied to the model.

I am now trying to work out the cleanest way to add the synchronization of the model with the figure, I suppose the EditPart should contain the logic but what is the preferred way to override the default EditPart?

  • A: You could override refreshVisuals() in generated edit parts to update figure on model changes.

Add the following code in ShipEditPart of TaiPan sample. When you rename a ship to "Avrora" it becomes red.

    protected void refreshVisuals() {
        super.refreshVisuals();
        Ship ship = (Ship) resolveSemanticElement();
        if ("Avrora".equals(ship.getName())) { //$NON-NLS-1$
            getPrimaryShape().setBackgroundColor(ColorConstants.red);
        } else {
            getPrimaryShape().setBackgroundColor(null);
        }
    }

    protected void handleNotificationEvent(Notification notification) {
        super.handleNotificationEvent(notification);
        if 
(TaiPanPackage.eINSTANCE.getShip_Name().equals(notification.getFeature())) {
            refreshVisuals();
        }
    }

How can I add strikethrough and underline features to the Appearance tab?

  • Q: I have to add "underline" and "strikethrough" features in Appearance page in Properties view. Can someone give me any hints?
  • A: This is going to take some effort so I hope you're up for it:-)

The Appearance tab is contributed by the org.eclipse.gmf.runtime.diagram.ui.properties plug-in; the required three extension point declarations, and the corresponding implementation classes are found in this plug-in.

This plug-in contributes three tabs; the Appearance and Advanced tabs are always shown when anything in the editor is selected, and additionally the Grid tab is shown when the canvas itself is selected. These contributions are fixed with no built-in capability to 'swap out' the appearance tab with your own or for adding additional items to the existing tab.

The quick and dirty solution is to import org.eclipse.gmf.runtime.diagram.ui.properties into your workspace (as source) then clone ....appearance.ConnectionAppearancePropertySection and any other required classes (put the clones in your own plug-in) then add your own "underline" and "strikethrough" properties to your clone(s). Then in the plugin.xml of org.eclipse.gmf.runtime.diagram.ui.properties modify the extension point declaration(s) to point to your 'cloned' version(s) instead. This is not your final solution because you really don't want to hack Eclipse code and distribute it with your plug-in or application (bad Karma :-P).

What the quick and dirty solution can do is get you up and running pretty quickly with prototyping/developing your enhancements.

Once you're satisfied that the enhancements are working then it's time to make them official.

Making it official means stopping the hijacking of org.eclipse.gmf.runtime.diagram.ui.properties and properly declaring your own custom propertyContributor.

There are just 3 basic steps to this process:

1. Implement and override .getContributorId() in the generated <your>DiagramEditor by returning your own ID for the custom contribution. This ID is a string that you choose so it can be just about anything; you can simply follow any convention you have now for other extension point ID's in your application. As an example let's make the ID = "com.my.own.contributor.id"

2. Copy/paste the following three extension point declarations from the 'hacked' org.eclipse.gmf.runtime.diagram.ui.properties#plugin.xml into your own plugin.xml:

org.eclipse.ui.views.properties.tabbed.propertyContributor org.eclipse.ui.views.properties.tabbed.propertyTabs org.eclipse.ui.views.properties.tabbed.propertySections

3. Now in your own plugin.xml replace the three: contributorId="org.eclipse.gmf.runtime.diagram.ui.properties" with contributorId="com.my.own.contributor.id"

That's about it.

You can delete the hacked version of org.eclipse.gmf.runtime.diagram.ui.properties at this point since you don't need it any more.

I hope this is enough of a hint on how you can get started; the bulk of your work (and maybe headaches:-P) is to get to know how the existing code utilizes the editing domain, commands, etc... and then adding your own stuff to it.

Hints +1 -- If your editor has some non-standard or tricky hierarchy you may have to extend the default ModelElementTypeMapper or provide your own custom implementation of ITypeManager.

Hint +2 -- Likewise with the LabelProvider

Hint +3 -- If you want finer control of when these new properties show up (maybe they're only applicable for certain nodes???) then you would want to extend the default filters or provide your own implementation of IFilter.