| <html> |
| |
| <head> |
| <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> |
| <title>Providing layout functionality</title> |
| <link href="../book.css" rel="Stylesheet" type="text/css"> |
| <link href="../code.css" rel="Stylesheet" type="text/css"> |
| </head> |
| |
| <body> |
| |
| <h1>Providing Layout Functionality</h1> |
| <h2>Create a Layout Feature</h2> |
| <p>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. </p> |
| <p>Theoretical such functionality could also be implemented by |
| <a href="resize-feature.htm">providing resize functionality</a>, but using a layout |
| feature for this is the recommended solution.</p> |
| <p>A layout feature has to implement the interface |
| <a href="../../../javadoc/org/eclipse/graphiti/features/ILayoutFeature.html">ILayoutFeature</a>. |
| Instead of implementing it directly you should extend one of the available base |
| classes. In this example we extend the base class |
| <a href="../../../javadoc/org/eclipse/graphiti/features/impl/AbstractLayoutFeature.html"> |
| AbstractLayoutFeature</a>.</p> |
| <p>In this case we have to implement/overwrite two methods:</p> |
| <ul> |
| <li>The method |
| <a href="../../../javadoc/org/eclipse/graphiti/func/ILayout.html#canLayout(org.eclipse.graphiti.features.context.ILayoutContext)"> |
| canLayout</a> has to check whether the pictogram element of the given context |
| can be layouted. </li> |
| <li>The method |
| <a href="../../../javadoc/org/eclipse/graphiti/func/ILayout.html#layout(org.eclipse.graphiti.features.context.ILayoutContext)"> |
| layout</a> has to recalculate and modify everything needed to layout the pictogram |
| element given with the context. </li> |
| </ul> |
| <p>You can see the complete implementation of the move feature here:</p> |
| <p> </p> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"><span class="keyword">package </span>org.eclipse.graphiti.examples.tutorial.features;<br> <br> |
| <span class="keyword">public class</span> TutorialLayoutEClassFeature |
| <span class="keyword">extends </span>AbstractLayoutFeature {<br> <br> |
| <span class="keyword">private static final int</span> |
| <span class="string"><em>MIN_HEIGHT</em> </span>= 30;<br> <br> |
| <span class="keyword">private static final int</span> |
| <span class="string"><em>MIN_WIDTH</em></span> = 50;<br> <br> |
| <span class="keyword">public </span>TutorialLayoutEClassFeature(IFeatureProvider |
| fp) {<br> |
| <span class="keyword">super</span>(fp);<br> }<br> <br> |
| <span class="keyword">public boolean</span> canLayout(ILayoutContext context) |
| {<br> <span class="comment">// return |
| true, if pictogram element is linked to an EClass</span><br> |
| PictogramElement pe = context.getPictogramElement();<br> |
| <span class="keyword">if </span>(!(pe <span class="keyword">instanceof |
| </span>ContainerShape))<br> |
| <span class="keyword">return false</span>;<br> |
| EList<EObject> businessObjects = pe.getLink().getBusinessObjects();<br> |
| <span class="keyword">return </span>businessObjects.size() == 1 <br> |
| && businessObjects.get(0) <span class="keyword">instanceof </span>EClass;<br> |
| }<br> <br> <span class="keyword">public boolean</span> |
| layout(ILayoutContext context) {<br> |
| <span class="keyword">boolean </span>anythingChanged = |
| <span class="keyword">false</span>;<br> |
| ContainerShape containerShape =<br> |
| (ContainerShape) context.getPictogramElement();<br> |
| GraphicsAlgorithm containerGa = containerShape.getGraphicsAlgorithm();<br> <br> |
| <span class="comment">// height</span><br> |
| <span class="keyword">if </span>(containerGa.getHeight() < |
| <span class="string"><em>MIN_HEIGHT</em></span>) {<br> |
| containerGa.setHeight(<span class="string"><em>MIN_HEIGHT</em></span>);<br> |
| anythingChanged = <span class="keyword">true</span>;<br> |
| }<br> <br> |
| <span class="comment">// width</span><br> |
| <span class="keyword">if </span>(containerGa.getWidth() < |
| <span class="string"><em>MIN_WIDTH</em></span>) {<br> |
| containerGa.setWidth(<span class="string"><em>MIN_WIDTH</em></span>);<br> |
| anythingChanged = <span class="keyword">true</span>;<br> |
| }<br> <br> |
| <span class="keyword">int </span>containerWidth = containerGa.getWidth();<br> |
| <br> <span class="keyword">for |
| </span>(Shape shape : containerShape.getChildren()){<br> |
| GraphicsAlgorithm graphicsAlgorithm = shape.getGraphicsAlgorithm();<br> |
| IGaService gaService = Graphiti.getGaService();<br> |
| IDimension size = <br> |
| gaService.calculateSize(graphicsAlgorithm);<br> |
| <span class="keyword">if </span>(containerWidth != size.getWidth()) {<br> |
| <span class="keyword">if</span> (graphicsAlgorithm <span class="keyword"> |
| instanceof </span>Polyline) {<br> |
| Polyline polyline = (Polyline) graphicsAlgorithm;<br> |
| Point secondPoint = polyline.getPoints().get(1);<br> |
| Point newSecondPoint =<br> |
| gaService.createPoint(containerWidth, secondPoint.getY()); <br> |
| polyline.getPoints().set(1, newSecondPoint);<br> |
| anythingChanged = <span class="keyword">true</span>;<br> |
| } <span class="keyword">else </span>{<br> |
| gaService.setWidth(graphicsAlgorithm,<br> |
| containerWidth);<br> |
| anythingChanged = <span class="keyword">true</span>;<br> |
| }<br> |
| }<br> }<br> |
| <span class="keyword">return </span>anythingChanged;<br> |
| }<br>}<br></p> |
| </div> |
| </div> |
| <p> </p> |
| <p>Additionally the feature provider has to deliver our newly created feature (overwrite |
| the method |
| <a href="../../../javadoc/org/eclipse/graphiti/features/IFeatureProvider.html#getLayoutFeature(org.eclipse.graphiti.features.context.ILayoutContext)"> |
| getLayoutFeature</a>).</p> |
| <p>This implementation can be seen here:</p> |
| <p> </p> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code">@Override<br><span class="keyword">public </span>ILayoutFeature |
| getLayoutFeature(ILayoutContext context) {<br> PictogramElement |
| pictogramElement = context.getPictogramElement();<br> |
| Object bo = getBusinessObjectForPictogramElement(pictogramElement);<br> |
| <span class="keyword">if</span> (bo <span class="keyword">instanceof</span> |
| EClass) {<br> |
| <span class="keyword">return new</span> TutorialLayoutEClassFeature(<span class="keyword">this</span>);<br> |
| }<br> <span class="keyword">return super</span>.getLayoutFeature(context);<br> |
| } </p> |
| </div> |
| </div> |
| <p> </p> |
| <p>Finally we have to call the layout feature at the end of the add method of the |
| <span class="incode"><em>TutorialAddEClassFeature</em></span>, as shown in the following |
| code snippet.</p> |
| <p>This causes that the layout (especially the layout restrictions like minimum |
| size) are applied after adding a EClass.</p> |
| <p> </p> |
| <div class="literallayout"> |
| <div class="incode"> |
| <p class="code"> <span class="keyword">public </span>PictogramElement |
| add(IAddContext context) {<br> <br> |
| <br> <span class="comment">// |
| ... EXISTING CODING ...</span><br> |
| <br> <br> |
| <span class="comment">// call the layout feature</span><br> |
| layoutPictogramElement(containerShape);<br> <br> |
| <span class="keyword">return </span>containerShape;<br> |
| } </p> |
| </div> |
| </div> |
| <p> </p> |
| <h2>Test: Layout EClass after Resize</h2> |
| <p>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.</p> |
| |
| </body> |
| |
| </html> |