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:

The method canLayout has to check whether the pictogram element of the given context can be layouted.

The method layout has to recalculate and modify everything needed to layout the pictogram element given with the context.

 

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.


Copyright (c) SAP AG 2005, 2010.