Jump to: navigation, search

GMF Newsgroup Q and A

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

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.