Providing Layout Functionality

Create a Layout Feature

If you already enlarged a EClass in the diagram, you may have observed that the shapes inside the rectangle kept their size (EClass name is not longer in the centre and the line separator is too short). Graphiti provides the concept of layout features, which mainly supports the recalculation of positions and sizes inside the pictogram model.

Theoretical such functionality could also be implemented by providing resize functionality, but using a layout feature for this is the recommended solution.

A layout feature has to implement the interface ILayoutFeature. Instead of implementing it directly you should extend one of the available base classes. In this example we extend the base class AbstractLayoutFeature.

In this case we have to implement/overwrite two methods:

You can see the complete implementation of the move feature here:

 

package org.eclipse.graphiti.examples.tutorial.features;
 
public class TutorialLayoutEClassFeature extends AbstractLayoutFeature {
 
    private static final int MIN_HEIGHT = 30;
 
    private static final int MIN_WIDTH = 50;
 
    public TutorialLayoutEClassFeature(IFeatureProvider fp) {
        super(fp);
    }
 
    public boolean canLayout(ILayoutContext context) {
       // return true, if pictogram element is linked to an EClass
       PictogramElement pe = context.getPictogramElement();
       if (!(pe instanceof ContainerShape))
           return false;
       EList<EObject> businessObjects = pe.getLink().getBusinessObjects();
       return businessObjects.size() == 1
              && businessObjects.get(0) instanceof EClass;
    }
 
    public boolean layout(ILayoutContext context) {
        boolean anythingChanged = false;
        ContainerShape containerShape =
            (ContainerShape) context.getPictogramElement();
        GraphicsAlgorithm containerGa = containerShape.getGraphicsAlgorithm();
 
        // height
        if (containerGa.getHeight() < MIN_HEIGHT) {
            containerGa.setHeight(MIN_HEIGHT);
            anythingChanged = true;
        }
 
        // width
        if (containerGa.getWidth() < MIN_WIDTH) {
            containerGa.setWidth(MIN_WIDTH);
            anythingChanged = true;
        }
 
        int containerWidth = containerGa.getWidth();
       
        for (Shape shape : containerShape.getChildren()){
            GraphicsAlgorithm graphicsAlgorithm = shape.getGraphicsAlgorithm();
            IGaService gaService = Graphiti.getGaService();
            IDimension size =
                 gaService.calculateSize(graphicsAlgorithm);
            if (containerWidth != size.getWidth()) {
                if (graphicsAlgorithm instanceof Polyline) {
                    Polyline polyline = (Polyline) graphicsAlgorithm;
                    Point secondPoint = polyline.getPoints().get(1);
                    Point newSecondPoint =
                        gaService.createPoint(containerWidth, secondPoint.getY());
                    polyline.getPoints().set(1, newSecondPoint);
                    anythingChanged = true;
                } else {
                    gaService.setWidth(graphicsAlgorithm,
                        containerWidth);
                    anythingChanged = true;
                }
            }
        }
        return anythingChanged;
    }
}

 

Additionally the feature provider has to deliver our newly created feature (overwrite the method getLayoutFeature).

This implementation can be seen here:

 

@Override
public ILayoutFeature getLayoutFeature(ILayoutContext context) {
    PictogramElement pictogramElement = context.getPictogramElement();
    Object bo = getBusinessObjectForPictogramElement(pictogramElement);
    if (bo instanceof EClass) {
        return new TutorialLayoutEClassFeature(this);
    }
    return super.getLayoutFeature(context);
}

 

Finally we have to call the layout feature at the end of the add method of the TutorialAddEClassFeature, as shown in the following code snippet.

This causes that the layout (especially the layout restrictions like minimum size) are applied after adding a EClass.

 

 public PictogramElement add(IAddContext context) {
 
       
        // ... EXISTING CODING ...
       
       
        // call the layout feature
        layoutPictogramElement(containerShape);
 
        return containerShape;
    } 

 

Test: Layout EClass after Resize

Now start the editor again and test it: Try to resize a EClass. You see that the class name stays in the centre and the line separator will be automatically extended.