Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpguilet2018-01-08 14:39:41 +0000
committerPierre-Charles David2018-05-02 13:25:39 +0000
commit9499239023d5853831343cf695447843c78638e6 (patch)
tree85b261ed4ce9a1778bf16e917aebd4f1e2a8e9fd
parent27b00a81ce506c870da28da643b1c52a5a3acbc7 (diff)
downloadorg.eclipse.sirius-9499239023d5853831343cf695447843c78638e6.tar.gz
org.eclipse.sirius-9499239023d5853831343cf695447843c78638e6.tar.xz
org.eclipse.sirius-9499239023d5853831343cf695447843c78638e6.zip
[529531] Update obsolete arrange all documentation
Update obsolete documentation to reflect current API. Bug: 529531 Change-Id: I628e3977026470a5dd6d25de626949c009d04398 Signed-off-by: pguilet <pierre.guilet@obeo.fr>
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.html794
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.textile736
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/airlayoutprovider.jpgbin8831 -> 0 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-CompoundLayoutProvider.pngbin0 -> 21303 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-abstractLayoutEditPart.pngbin0 -> 29033 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-air.jpgbin33025 -> 0 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border1.pngbin0 -> 8937 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border2.pngbin0 -> 7143 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ilayoutNodeproviderApi.pngbin0 -> 49140 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-iproviderApi.pngbin0 -> 39105 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutProvider.pngbin0 -> 18619 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutingAPI.pngbin0 -> 236996 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutprovider-extension.pngbin42972 -> 24029 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ls.jpgbin23256 -> 0 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-provider-extension.pngbin43803 -> 0 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-tlinterface.jpgbin26565 -> 0 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ui.pngbin0 -> 38420 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering.pngbin0 -> 5330 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering2.pngbin0 -> 5188 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingArchitecture.pngbin0 -> 55790 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingExtensionPoint.pngbin0 -> 68372 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingProvider.pngbin0 -> 13898 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-vsm.pngbin0 -> 37184 bytes
-rw-r--r--plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/viewordering.jpgbin53848 -> 0 bytes
24 files changed, 1049 insertions, 481 deletions
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.html b/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.html
index 8dfdcdea0b..ab21afd0ab 100644
--- a/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.html
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.html
@@ -7,25 +7,47 @@
<link type="text/css" rel="stylesheet" href="../resources/custom.css"/>
</head>
<body>
- <h1 id="Provideacustomarrangeall">Provide a custom arrange-all</h1>
- <h2 id="Goals">Goals</h2>
- <p>One of the main issues of visual modelers is the global arrangement of all elements. GMF provides a default implementation of an &quot;Arrange All&quot; algorithm to solve this issue but it happens that this default behavior is not adapted for some diagrams. Imagine a diagram representing the hierarchy between a program classes, the &quot;natural&quot; representation a human thinks about is that of a tree. When you add associations on such diagrams, GMF won&#8217;t keep the tree representation of the diagram. Sirius provides an API to arrange diagrams according to custom business rules.</p>
- <h2 id="ThearrangeallconceptasimplementedbyGMF">The arrange all concept as implemented by GMF</h2>
- <p>GMF provides basic API and implementations to ease the customization of the &quot;Arrange All&quot; mechanism. It also implements a complete algorithm that is based on the graphical elements.</p>
- <p>The top level type of this this API is
- <code>ILayoutNodeProvider</code>
- </p>
+ <h1 id="ProvidingacustomdiagramlayoutalgorithmArrangeAll">Providing a custom diagram layout algorithm (&#8220;Arrange All&#8221;)</h1>
+ <h2 id="TheArrangeAllfunctionalityinshort">The Arrange All functionality in short</h2>
+ <p>The arrange-all functionality is available in Sirius diagram editors in the form of a button and a context menu:</p>
<p>
- <img border="0" src="images/arrange-all/arrange-all-tlinterface.jpg"/>
+ <img border="0" src="images/arrange-all/arrange-all-ui.png"/>
</p>
- <p>As you can see, this interface is designed for genericity. Fortunately, GMF provides abstract classes that handle the low-level work while letting you define the business rules:</p>
- <p>
- <img border="0" src="images/arrange-all/arrange-all-ls.jpg"/>
+ <p>Its effect is to layout the selected diagram elements (or the whole diagram if no elements are selected) based on the layout algorithm defined for the diagram, or using a default, generic algorithm if nothin is specified. </p>
+ <p>By default, there are two different layout algorithm that can be configured in the VSM for a diagram:</p>
+ <ul>
+ <li>The
+ <code>Ordered Tree Layout</code> algorithm: useful to represent elements in a hierarchical way.
+ </li>
+ <li>The
+ <code>Composite Layout</code> algorithm: used to customize specific aspects of the default algorithm, i.e. the general layout orientation and the padding between elements.
+ </li>
+ </ul>
+ <img border="0" src="images/arrange-all/arrange-all-vsm.png"/>
+ <p>If none of these algorithms fit your needs, Sirius provides two extension points
+ <code>org.eclipse.sirius.diagram.ui.layoutProvider</code> and
+ <code>org.eclipse.sirius.diagram.ui.viewOrderingProvider</code> as well as an API to ease the writing of your own layout algorithms and their usage in Sirius diagram editors.
+ </p>
+ <p>This API reuse the GMF &#8220;Arrange All&#8221; API and augments it with features needed by Sirius layout algorithms like:</p>
+ <ul>
+ <li>The need to take in consideration pinned diagram elements</li>
+ <li>The need to take in consideration bordered nodes connected to edges</li>
+ </ul>
+ <h2 id="TheArrangeAllconceptasimplementedbyGMF">The Arrange All concept as implemented by GMF</h2>
+ <p>GMF provides basic API and implementations to ease the customization of the &#8220;Arrange All&#8221; mechanism. It also implements a complete algorithm that is based on the graphical elements.</p>
+ <p>The top level type of this this API is
+ <code>ILayoutNodeProvider</code> :
+ </p>
+ <img border="0" src="images/arrange-all/arrange-all-iproviderApi.png"/>
+ <p>This interface is very generic, but GMF provides abstract classes that handle the low-level work while letting you define only the layouting business rules:</p>
+ <img border="0" src="images/arrange-all/arrange-all-ilayoutNodeproviderApi.png"/>
+ <p>This can be done by creating a component inheriting the abstract class
+ <code>AbstractLayoutEditPartProvider</code> and implementing its methods:
</p>
- <p>This can be done by implementing three operations:</p>
<ul>
<li>
- <code>boolean provides(IOperation operation)</code>
+ <code>boolean provides(IOperation operation)</code> from
+ <code>IProvider</code> super interface
</li>
<li>
<code>Command layoutEditParts(GraphicalEditPart containerEditPart, IAdaptable layoutHint)</code>
@@ -35,318 +57,590 @@
</li>
</ul>
<p>The
- <code>provides</code> operation is meant to return true if the class can arrange the diagram for the specified operation.
+ <code>provides</code> operation is meant to return true if the class can arrange the diagram for the specified operation.
</p>
<p>The
- <code>layoutEditParts</code> operations will return the commands that will actually be in charge of arranging the diagrams' edit parts. The first one takes the main container that is to be arranged while the latter accepts a list of edit parts to arrange.
+ <code>layoutEditParts</code> operations will return the commands that will actually be in charge of arranging the diagrams' edit parts. The first one takes the main container that is to be arranged while the latter accepts a list of edit parts to arrange.
+ </p>
+ <p>The implementation of those three methods forms your layout algorithm.</p>
+ <p>With this API comes an extension point
+ <code>org.eclipse.gmf.runtime.diagram.ui.layoutProviders</code>. It allows your own
+ <code>AbstractLayoutEditPart</code> layout algorithm to be used.
</p>
- <h2 id="TheLayoutProvidersasprovidedbySirius">The LayoutProviders as provided by Sirius</h2>
- <p>The class
- <code>AbstractLayoutEditPartProvider</code> is the simplest one. Sirius provides utility classes to ease the implementation of &quot;Arrange All&quot; algorithms:
+ <h3 id="Theviewsandeditparts">The views and edit parts</h3>
+ <p>When doing layouting with GMF based tools like Sirius you will hear about views and edit parts. It is important to understand what they are.</p>
+ <p>The views are persisted model elements that when interpreted represent your diagram visually. You have the
+ <code>Node</code>,
+ <code>Edge</code>,
+ <code>Style</code>, etc...
</p>
+ <p>They contain all visual information like the position, the size of the element, its color, etc...
+ <br/>Edit parts ties the model (the views) to a visual representation with a one on one relationship. One edit part points at one view. They are responsible for making changes to the model and interpret and display graphically the view.
+ </p>
+ <h2 id="SiriusLayoutingAPI">Sirius Layouting API</h2>
+ <p>The Sirius Layouting API simplifies the writing of a custom layout algorithm by providing different layout providers specific to Sirius context that you can reuse easily in addition of your own layout algorithm if it does not conflict with these. </p>
+ <p>It also provides utility methods that you can find useful</p>
+ <p>The Sirius API for layouting Sirius diagrams is the following:</p>
<p>
- <img border="0" src="images/arrange-all/arrange-all-air.jpg"/>
+ <img border="0" src="images/arrange-all/arrange-all-layoutingAPI.png"/>
+ </p>
+ <h3 id="siriusLayoutProviders">Sirius Layout providers</h3>
+ <p>Sirius defines and already uses various different layout providers in different contexts.</p>
+ <p>Here is a list of all of those with a basic description of each:</p>
+ <h5 id="DefaultLayoutProvider">DefaultLayoutProvider</h5>
+ <p>It is used by Sirius as entry point to dispatch arrange requests on a Sirius diagram to registered layout providers. The dispatch takes in consideration layout algorithm specified in the VSM and layout providers provided from the Sirius extension point
+ <code>org.eclipse.sirius.diagram.ui.layoutProvider</code>.
</p>
- <p>Here is a list of all provided layout providers and a basic description of each:</p>
+ <h5 id="LineLayoutProvider">LineLayoutProvider</h5>
+ <p>Lays out all views on a single line (either vertical or horizontal). </p>
+ <h5 id="GridLayoutProvider">GridLayoutProvider</h5>
+ <p>Lays out all views as a grid.</p>
+ <h5 id="InlineEdgeLayoutProvider">InlineEdgeLayoutProvider</h5>
+ <p>Lays out connections alongside their source and target nodes (useful on the sequence diagram for example).</p>
+ <h5 id="ArrangeSelectionLayoutProvider">ArrangeSelectionLayoutProvider</h5>
+ <p>This provider only purpose is to delegate arrangement to attached layout provider after having added information about not selected parts in the layout hint. </p>
+ <p>It is used for example with our composite layout providers to keep fixed the not selected parts and to avoid putting other selected parts on it when layouting. </p>
+ <p>It is used primary by default provider whenever the arrange-all action is called because the arrangement can be done on a selection and not on all diagram elements.</p>
+ <h5 id="ArrangeAllOnlyLayoutProvider">ArrangeAllOnlyLayoutProvider</h5>
+ <p>This provider is used to delegate layouting to attached provider only when an arrange-all is done on a diagram and not an arrange selection. </p>
+ <p>When used as primary provider, the arrange selection action is not available in the menu of a Sirius editor using this provider. </p>
+ <p>It is used for example in the
+ <code>OrderedTreeLayoutProvider</code> where it does not make sense to make a tree of just some elements because the all concept is to have a complete tree representation.
+ </p>
+ <h5 id="PinnedElementLayoutProvider">PinnedElementLayoutProvider</h5>
+ <p>This provider is designed to work with another layout provider. When its attached layout provider has done its layouting part, this provider iterates on all diagram elements that are pinned (should not have its position changes by an automatic layout) to put it back at its original position. In case of visual overlap conflict with a non-pinned element, the non-pinned element is move near the pinned one where no overlap is visible.</p>
+ <h5 id="CompoundLayoutProvider">CompoundLayoutProvider</h5>
+ <p>This provider allows to compose different layout providers into a compound one. It is useful to reuse some layouting rules that does not conflict with others needed ones.</p>
+ <p>For example the providers
+ <code>CompositeDownTopLayoutProvider</code> and
+ <code>PinnedElementLayoutProvider</code> can be attached to a compound instance. Then those providers are called in their attach order one after another to do their layouting parts. It avoids the composite provider to duplicate code to handle pinned elements.
+ </p>
+ <h5 id="BorderedItemAwareLayoutProvider">BorderedItemAwareLayoutProvider</h5>
+ <p>This provider arranges all the bordered nodes which are connected to one edge. It reduces the path of the edge between each extremity. For example:</p>
+ <img border="0" src="images/arrange-all/arrange-all-border1.png"/>
+ <p>Becomes </p>
+ <img border="0" src="images/arrange-all/arrange-all-border2.png"/>
+ <h3 id="Theviewordering">The view ordering</h3>
+ <h4 id="API">API</h4>
+ <p>The view ordering is an API used by layout algorithms provided by Sirius. It allows to define a sub class of
+ <code>ViewOrdering</code> that will sort children views of a parent view. The layouting will be done on sorted views instead of the original order in the layout provider.
+ </p>
+ <p>For example, if I use the
+ <code>LineLayoutProvider</code> with default view ordering component in a diagram with two elements, views will be aligned in their natural iteration order:
+ </p>
+ <img border="0" src="images/arrange-all/arrange-all-viewOrdering.png"/>
+ <p>If I define a view ordering component that reorder view in the lexicographic order, views will be aligned accordingly:</p>
+ <img border="0" src="images/arrange-all/arrange-all-viewOrdering2.png"/>
+ <p>This mechanism avoid to rewrite a layout provider if the only thing that should be changed is the order the layout provider lays out its views.</p>
+ <p>Its architecture is the following:</p>
+ <img border="0" src="images/arrange-all/arrange-all-viewOrderingArchitecture.png"/>
+ <h4 id="Compatibleproviders">Compatible providers</h4>
+ <p>Layout providers need to sort view by using the view ordering framework so your view ordering component can be used. The Sirius providers using this framework are the following:</p>
<ul>
<li>
- <code>LineLayoutProvider</code>: lays out all views on a single line (either vertical or horizontal).
+ <code>GridLayoutProvider</code>
</li>
<li>
- <code>GrigLayoutProvider</code>: lays out all views as a grid.
+ <code>InlineEdgeLAyoutProvider</code>
</li>
<li>
- <code>InlineEdgeLayoutProvider</code>: lays out connections alongside their source and target nodes (useful on the sequence diagram for example).
+ <code>LineLAyoutProvider</code>
</li>
</ul>
- <h2 id="TheViewOrderings">The ViewOrderings</h2>
- <h3 id="TheAPI">The API</h3>
- <p>
- <img border="0" src="images/arrange-all/viewordering.jpg"/>
- </p>
- <p>All
- <code>LayoutProvider</code> provided by Sirius can be used with a
- <code>ViewOrdering</code> which has the responsibility of actually ordering the views.
- </p>
- <p>The aim of all these classes is to order the GMF views and to provide this result to an
- <code>AbstractLayoutProvider</code>.
- </p>
- <h3 id="Sample">Sample</h3>
- <p>Here is a sample ordering all views to get a tree from a list of UML2 packages :</p>
- <pre>/**
- * Orders packages.
- */
-public class PackageTreeOrdering extends SemanticTreeOrdering {
-
- public List getSemanticChildren(EObject semanticParent, List candidates) {
- List result = Collections.EMPTY_LIST;
- if (semanticParent instanceof Package) {
- result = new LinkedList&amp;lt;Package&amp;gt;(((Package) semanticParent).getNestedPackages());
- result.retainAll(candidates);
- }
- return result;
- }
+ <h4 id="WritingaViewOrdering">Writing a ViewOrdering</h4>
+ <p>To contribute a
+ <code>ViewOrdering</code> that should be used in a Sirius provider, you have to create a sub class of
+ <code>AbstractViewOrdering</code> or
+ <code>AbstractViewOrdering</code> or
+ <code>ViewOrdering</code> if you need to do an ordering different from what Sirius offers with its abstract classes.
+ <br/>Sirius abstract classes offers ordering only on Node views by default.
+ </p>
+ <p>For example the lexicographic view ordering component would be the following:</p>
+ <pre><code>public class LexicographicViewOrdering extends AbstractViewOrdering {
- public List getSemanticRoots(List objects) {
- List&amp;lt;Package&amp;gt; roots = new LinkedList&amp;lt;Package&amp;gt;();
- for (Object object : objects) {
- EObject semantic = (EObject) object;
- if (semantic instanceof Package) {
- Package package_ = (Package) semantic;
- if (package_.eContainer() == null || !objects.contains(package_.eContainer())) {
- roots.add(package_);
+ @Override
+ protected List&lt;View&gt; sortViews(List&lt;View&gt; views) {
+ Comparator&lt;View&gt; comparing = Comparator.comparing(new Function&lt;View, String&gt;() {
+ @Override
+ public String apply(View t) {
+ DDiagramElement element = (DDiagramElement) t.getElement();
+ return element.getName();
}
- }
+ });
+ Collections.sort(views, comparing);
+ return views;
}
- return roots;
}
-}
+</code></pre>
+ <h4 id="ContributingyourViewOrderingwithextensionpoint">Contributing your ViewOrdering with extension point</h4>
+ <p>Once your view ordering component has been written you have to make Sirius aware of it so it can be used.
+ <br/>To do that Sirius provides an extension point
+ <code>org.eclipse.sirius.diagram.viewOrderingProvider</code>.
+ <br/>It allows to register a
+ <code>ViewOrderingProvider</code> that will provide your view ordering component:
+ </p>
+ <img border="0" src="images/arrange-all/arrange-all-viewOrderingProvider.png"/>
+ <p>It contains the following methods:
+ <br/>-
+ <code>provides</code>: tell Sirius if your ordering component should be used when layouting views associated to the given mapping.
+ <br/>-
+ <code>getViewOrdering</code>: tell Sirius what view ordering component to use to order views when the provides method returns true.
+ </p>
+ <p>For example with the lexicographic you will have:</p>
+ <img border="0" src="images/arrange-all/arrange-all-viewOrderingExtensionPoint.png"/>
+ <pre><code>&lt;extension point="org.eclipse.sirius.diagram.viewOrderingProvider"&gt;
+ &lt;viewOrderingProvider providerClass="org.eclipse.sirius.diagram.ui.tools.internal.providers.LexicographicViewOrderingProvider" /&gt;
+&lt;/extension&gt;
-This tells us how to order the packages. We must notify Sirius that this @ViewOrdering@ has to be used for the Package Hierarchy diagram.
-</pre>
- <h3 id="TheViewOrderingProvider">The
- <code>ViewOrderingProvider</code>
- </h3>
- <p>Here is the implementation of a
- <code>ViewOrderingProvider</code> for an UML2 modeler :
+</code></pre>
+ <p>The
+ <code>LexicographicViewOrderingProvider</code> code would be:
</p>
- <pre>/**
- * The view ordering provider for UML2 modeler.
- */
-public class Uml2ViewOrderingProvider implements ViewOrderingProvider {
+ <pre><code>public class LexicographicViewOrderingProvider implements ViewOrderingProvider {
- /** The classifier ordering. */
- private ClassifierTreeOrdering classifierOrdering = new ClassifierTreeOrdering();
+ public LexicographicViewOrderingProvider() {
+ }
- public Uml2ViewOrderingProvider() {
- classifierOrdering.setUserAwareCapable(true);
+ @Override
+ public boolean provides(DiagramElementMapping mapping) {
+ return true;
}
+ @Override
public ViewOrdering getViewOrdering(DiagramElementMapping mapping) {
- return (ViewOrdering) getMappingToViewOrdering().get(getMappingName(mapping));
+ return new LexicographicViewOrdering();
}
+}
- public boolean provides(DiagramElementMapping mapping) {
- return getMappingToViewOrdering().containsKey(getMappingName(mapping));
+
+</code></pre>
+ <h3 id="Writeyourcustomlayoutalgorithm">Write your custom layout algorithm</h3>
+ <p>To create your own layout algorithm with Sirius API you have to subclass one Sirius abstract class depending on what you need to use:</p>
+ <h5 id="AbstractLayoutEditPartProvider">AbstractLayoutEditPartProvider</h5>
+ <p>This class should be extended if you do not need what AbstractLayoutProvider provides.
+ <br/>Its API is:
+ </p>
+ <p>
+ <img border="0" src="images/arrange-all/arrange-all-abstractLayoutEditPart.png"/>
+ </p>
+ <p>Only the abstract methods
+ <code>layoutEditParts</code> should be override. It is these methods that do the layouting by providing commands modifying underlying views information.
+ </p>
+ <h5 id="AbstractLayoutProvider">AbstractLayoutProvider</h5>
+ <p>This class should be extended if your layouting algorithm is meant to be used in addition to others during a same layouting pass and if you need to be aware of the bound changes produced by the other algorithms. It also should be used if you need all the utility methods regarding view bounds manipulation provided by this abstract class.</p>
+ <p>When sub classing this one, you only have to implement
+ <code>layoutEditParts(List, IAdaptable)</code> and to override
+ <code>provides(IOperation)</code> methods.
+ </p>
+ <p>For example the
+ <code>LineLayoutProvider</code> have the following code:
+ </p>
+ <pre><code>public class LineLayoutProvider extends AbstractLayoutProvider {
+
+ /** The default padding. */
+ private static final Insets DEFAULT_PADDING = new Insets(30, 30, 30, 30);
+
+ /**
+ * &lt;code&gt;true&lt;/code&gt; if the line is horizontal, &lt;code&gt;false&lt;/code&gt; if the line is vertical.
+ */
+ private boolean horizontal = true;
+
+ /**
+ * &lt;code&gt;true&lt;/code&gt; if the line is horizontal, &lt;code&gt;false&lt;/code&gt; if the line is vertical.
+ *
+ * @param horizontal
+ * &lt;code&gt;true&lt;/code&gt; if the line is horizontal, &lt;code&gt;false&lt;/code&gt; if the line is vertical.
+ */
+ public void setHorizontal(final boolean horizontal) {
+ this.horizontal = horizontal;
}
- private String getMappingName(DiagramElementMapping mapping) {
- String result = null;
- if (mapping instanceof NodeMapping) {
- result = ((NodeMapping) mapping).getName();
- } else if (mapping instanceof EdgeMapping) {
- result = ((EdgeMapping) mapping).getName();
- } else if (mapping instanceof ContainerMapping) {
- result = ((ContainerMapping) mapping).getName();
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ final Iterator&lt;?&gt; iterEditParts = selectedObjects.iterator();
+ final List&lt;View&gt; views = new ArrayList&lt;View&gt;(selectedObjects.size());
+ final Map&lt;View, ShapeEditPart&gt; viewsToEditPartMap = new HashMap&lt;View, ShapeEditPart&gt;();
+ while (iterEditParts.hasNext()) {
+ final Object next = iterEditParts.next();
+ if (next instanceof ShapeEditPart &amp;&amp; !(next instanceof IBorderItemEditPart)) {
+ final ShapeEditPart shapeEditPart = (ShapeEditPart) next;
+ final View view = shapeEditPart.getNotationView();
+ viewsToEditPartMap.put(view, shapeEditPart);
+ views.add(view);
+ } else {
+ iterEditParts.remove();
+ }
}
- return result;
+ ViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ // use a simple view ordering ... too bad.
+ viewOrdering = new SimpleViewOrdering();
+ }
+
+ viewOrdering.setViews(views);
+ final List&lt;View&gt; sortedViews = viewOrdering.getSortedViews();
+ final List&lt;ShapeEditPart&gt; sortedEditParts = new ArrayList&lt;ShapeEditPart&gt;(sortedViews.size());
+ final Iterator&lt;View&gt; iterSortedViews = sortedViews.listIterator();
+ while (iterSortedViews.hasNext()) {
+ final View currentView = iterSortedViews.next();
+ final ShapeEditPart currentEditPart = viewsToEditPartMap.get(currentView);
+ sortedEditParts.add(currentEditPart);
+ }
+ return createNodeChangeBoundCommands(sortedEditParts);
}
/**
- * Returns a map : MappingName(String) -&amp;gt; ViewOrdering.
- *
- * @return a map : MappingName(String) -&amp;gt; ViewOrdering.
+ * Create the change bounds commands.
+ *
+ * @param sortedNodes
+ * the nodes to move.
+ * @return the change bounds command.
*/
- private Map getMappingToViewOrdering() {
- Map result = new HashMap();
- result.put(Uml2Constants.LIFELINE_MAPPING_NAME, new LifelineOrdering());
- result.put(Uml2Constants.MESSAGE_MAPPING_NAME, new MessageOrdering());
- result.put(Uml2Constants.CLASS_MAPPING_NAME, this.classifierOrdering);
- result.put(Uml2Constants.INTERFACE_MAPPING_NAME, this.classifierOrdering);
- return result;
- }
+ protected Command createNodeChangeBoundCommands(final List&lt;ShapeEditPart&gt; sortedNodes) {
+ final CompoundCommand result = new CompoundCommand();
+ final Iterator&lt;ShapeEditPart&gt; iterEditParts = sortedNodes.iterator();
+ int currentX = 0;
+ while (iterEditParts.hasNext()) {
+ final ShapeEditPart shapeEditPart = iterEditParts.next();
+ if (!(shapeEditPart instanceof IBorderItemEditPart)) {
-}
+ final View view = shapeEditPart.getNotationView();
+ // the zoom.
+ double scale = 1.0;
+ if (shapeEditPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) shapeEditPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+ //
+ // Compute request data.
+ final Point ptOldLocation = shapeEditPart.getFigure().getBounds().getLocation();
+ // shapeEditPart.getFigure().translateToAbsolute(ptOldLocation);
+ final int locationX = horizontal ? currentX + this.getPadding().left : this.getPadding().left;
+ final int locationY = horizontal ? this.getPadding().top : currentX + this.getPadding().top;
+ final Point ptLocation = new Point(locationX, locationY);
+ final Dimension delta = ptLocation.getDifference(ptOldLocation);
+ final Object existingRequest = this.findRequest(view, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ int step = 0;
+ if (existingRequest == null) {
+ final ChangeBoundsRequest request = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ request.setEditParts(shapeEditPart);
+ request.setMoveDelta(new PrecisionPoint(delta.width * scale, delta.height * scale));
+ request.setLocation(new PrecisionPoint(ptLocation.x * scale, ptLocation.y * scale));
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+
+ final Command cmd = this.buildCommandWrapper(request, shapeEditPart);
+ if (cmd != null &amp;&amp; cmd.canExecute()) {
+ result.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(view,
+ // request);
+ }
+ } else if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingRequest;
+ changeBoundsRequest.setMoveDelta(new PrecisionPoint(delta.width * scale, delta.height * scale));
+ changeBoundsRequest.setLocation(new PrecisionPoint(ptLocation.x * scale, ptLocation.y * scale));
+
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+ }
+ currentX += horizontal ? step + getPadding().right + getPadding().left : step + this.getPadding().bottom + this.getPadding().top;
+
+ // check the size of the container.
+ EditPart container = shapeEditPart.getParent();
+ while (container instanceof CompartmentEditPart) {
+ container = container.getParent();
+ }
+ if (container instanceof ShapeEditPart) {
+ final ShapeEditPart containerEditPart = (ShapeEditPart) container;
+
+ // The minimum witdh
+ final int minWidth = this.horizontal ? ((getPadding().left + getPadding().right) * sortedNodes.size()) + (getNodeMaxWidth(sortedNodes) * sortedNodes.size())
+ : getPadding().left + getNodeMaxWidth(sortedNodes) + getPadding().right;
+ // The minimum height
+ final int minHeight = this.horizontal ? getPadding().top + this.getNodeMaxHeight(sortedNodes) + this.getPadding().bottom
+ : ((getPadding().top + getPadding().bottom) * sortedNodes.size()) + (this.getNodeMaxHeight(sortedNodes) * sortedNodes.size());
+
+ final Dimension minDimension = new Dimension(minWidth, minHeight);
+
+ final Dimension difference = minDimension.getShrinked(containerEditPart.getFigure().getBounds().getSize());
+ if (difference.width &gt; 0 || difference.height &gt; 0) {
+ final Object existingContainerRequest = this.findRequest(containerEditPart, org.eclipse.gef.RequestConstants.REQ_RESIZE); // ;this.getViewsToChangeBoundsRequest().get(containerEditPart.getNotationView());
+ createChangeBoundsCommand(result, existingContainerRequest, containerEditPart, difference, scale);
+ }
+
+ }
-</pre>
- <p>Once this has been implemented, we need to add the extension to the plugin.xml :</p>
- <p>
- <img border="0" src="images/arrange-all/arrange-all-provider-extension.png"/>
- </p>
- <pre><code>&lt;extension point="org.eclipse.sirius.diagram.viewOrderingProvider"&gt;
- &lt;viewOrderingProvider providerClass="com.example.uml2.specific.provider.Uml2ViewOrderingProvider" /&gt;
-&lt;/extension&gt;
-</code></pre>
- <h2 id="HowtomapaLayoutProviderwithaDiagram">How to map a Layout Provider with a Diagram</h2>
- <p>Now, we know how to both order and arrange views. We still need to let Sirius know that we want to use a custom Layout Provider for a specific Diagram.</p>
- <p>
- <img border="0" src="images/arrange-all/airlayoutprovider.jpg"/>
- </p>
- <p>Here is a provider designed for an UML2 modeler:</p>
- <pre>public class Uml2LayoutProvider implements LayoutProvider {
-
- /** The GMF layout provider. */
- private CompoundLayoutProvider layoutProvider;
-
- /** The class diagram layout provider. */
- private GridLayoutProvider classDiagramLayoutProvider;
-
- /** The package hierarchy layout provider. */
- private GridLayoutProvider packageHierarchyLayoutProvider;
-
-
- public AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container) {
- if (isSequenceDiagram(container)) {
- if (this.layoutProvider == null) {
- this.layoutProvider = new CompoundLayoutProvider();
- LineLayoutProvider lineLayoutProvider = new LineLayoutProvider();
- lineLayoutProvider.getPadding().right = 80;
- lineLayoutProvider.setHorizontal(true);
- this.layoutProvider.addProvider(lineLayoutProvider);
- inlineEdgeLayoutProvider inlineEdgeLayoutProvider = new InlineEdgeLayoutProvider();
- inlineEdgeLayoutProvider.setSide(PositionConstants.EAST_WEST);
- inlineEdgeLayoutProvider.setStart(PositionConstants.RIGHT);
- inlineEdgeLayoutProvider.setAlignment(PositionConstants.VERTICAL);
- inlineEdgeLayoutProvider.setChangeNodeHeight(true);
- inlineEdgeLayoutProvider.setChangeNodeWidth(true);
- inlineEdgeLayoutProvider.getPaddings().top = 50;
- this.layoutProvider.addProvider(inlineEdgeLayoutProvider);
}
- return this.layoutProvider;
- } else if (isClassDiagram(container)) {
- return this.getClassDiagramLayoutProvider();
- } else if (isPackageHierarchyDiagram(container)) {
- return this.getPackageHierarchyLayoutProvider();
}
- return null;
+ return result;
}
- public boolean provides(IGraphicalEditPart container) {
- return (isClassDiagram(container) &amp;amp;&amp;amp; isAbleToLayoutClassDiagram(container)) || isSequenceDiagram(container) || isPackageHierarchyDiagram(container);
- }
+ private void createChangeBoundsCommand(final CompoundCommand compoundCommand, final Object existingContainerRequest, final ShapeEditPart containerEditPart, final Dimension difference,
+ final double scale) {
- private boolean isSequenceDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof DDiagram) {
- DDiagram diagram = (DDiagram) editPart.resolveSemanticElement();
- if (viewPoint.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.SEQUENCE_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
- }
+ if (existingContainerRequest == null) {
+ final ChangeBoundsRequest changeBoundsRequest = new ChangeBoundsRequest();
+ changeBoundsRequest.setEditParts(containerEditPart);
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
+ changeBoundsRequest.setLocation(new Point(0, 0));
+ changeBoundsRequest.setType(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ final Command cmd = this.buildCommandWrapper(changeBoundsRequest, containerEditPart);
+ if (cmd.canExecute()) {
+ compoundCommand.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(containerEditPart.getNotationView(),
+ // changeBoundsRequest);
}
+ } else if (existingContainerRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingContainerRequest;
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
}
- return false;
}
- private boolean isClassDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof ViewPoint) {
- DDiagram diagram = (DDaiagram) editPart.resolveSemanticElement();
- if (diagram.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.CLASS_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
- }
+ /**
+ * Return the maximum width of all nodes (instances of {@link ShapeEditPart} ) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxWidth(final List&lt;ShapeEditPart&gt; nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final Object existingRequest = this.getViewsToChangeBoundsRequest().get(shapeEditPart.getNotationView());
+ int width = shapeEditPart.getFigure().getBounds().width;
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ width = width + ((ChangeBoundsRequest) existingRequest).getSizeDelta().width;
+ }
+ if (width &gt; max) {
+ max = width;
}
}
- return false;
+ return max;
}
- private boolean isPackageHierarchyDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof DDiagram) {
- DDiagram diagram = (DDiagram) editPart.resolveSemanticElement();
- if (viewPoint.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.PACKAGE_HIERARCHY_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
- }
+ /**
+ * Return the maximum height of all nodes (instances of {@link ShapeEditPart}) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxHeight(final List&lt;ShapeEditPart&gt; nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final int height = this.getBounds(shapeEditPart).height;
+ if (height &gt; max) {
+ max = height;
}
}
- return false;
+ return max;
}
- private boolean isAbleToLayoutClassDiagram(IGraphicalEditPart container) {
- if (container instanceof DiagramEditPart) {
- int nbNoInherance = 0;
- int nbInheritance = 0;
- Iterator iterConnections = ((DiagramEditPart) container).getConnections().iterator();
- while (iterConnections.hasNext()) {
- ConnectionEditPart connectionEditPart = (ConnectionEditPart) iterConnections.next();
- EObject semantic = connectionEditPart.resolveSemanticElement();
- if (semantic != null &amp;amp;&amp;amp; semantic instanceof DecorateSemanticElement) {
- EObject realSemantic = ((DecorateSemanticElement) semantic).getTarget();
- if (realSemantic instanceof Generalization) {
- nbInheritance++;
- } else {
- nbNoInherance++;
- }
- } else {
- nbNoInherance++;
- }
- }
- return nbInheritance &amp;gt; nbNoInherance;
+ @Override
+ public boolean provides(final IOperation operation) {
+ final View cview = getContainer(operation);
+ if (cview == null) {
+ return false;
}
- return false;
+ final IAdaptable layoutHint = ((ILayoutNodeOperation) operation).getLayoutHint();
+ final String layoutType = layoutHint.getAdapter(String.class);
+ return LayoutType.DEFAULT.equals(layoutType);
+ }
+
+ /**
+ * Return the padding to use.
+ *
+ * @return the padding to use.
+ */
+ public Insets getPadding() {
+ return DEFAULT_PADDING;
}
/**
- * Returns the class diagram layout provider.
- *
- * @return the class diagram layout provider.
+ * Get the container edit part of an object list. Currently the function takes only the first object of the list
+ *
+ * @param selectedObjects
+ * the selected object
+ * @return the container edit part
*/
- public GridLayoutProvider getClassDiagramLayoutProvider() {
- if (classDiagramLayoutProvider == null) {
- classDiagramLayoutProvider = new GridLayoutProvider();
- classDiagramLayoutProvider.setColumnSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- classDiagramLayoutProvider.setLineSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- classDiagramLayoutProvider.getPadding().top = 20;
- classDiagramLayoutProvider.getPadding().bottom = 20;
- classDiagramLayoutProvider.getPadding().left = 20;
- classDiagramLayoutProvider.getPadding().right = 20;
+ protected IGraphicalEditPart getContainerEditPart(final List&lt;EditPart&gt; selectedObjects) {
+ if (selectedObjects != null &amp;&amp; !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) (selectedObjects.iterator().next()).getParent();
}
- return classDiagramLayoutProvider;
+ return null;
}
- public GridLayoutProvider getPackageHierarchyLayoutProvider() {
- if (packageHierarchyLayoutProvider == null) {
- packageHierarchyLayoutProvider = new GridLayoutProvider();
- packageHierarchyLayoutProvider.setColumnSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- packageHierarchyLayoutProvider.setLineSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- packageHierarchyLayoutProvider.getPadding().top = 20;
- packageHierarchyLayoutProvider.getPadding().bottom = 20;
- packageHierarchyLayoutProvider.getPadding().left = 30;
- packageHierarchyLayoutProvider.getPadding().right = 30;
+}
+</code></pre>
+ <h4 id="Allowvieworderingcustomization">Allow view ordering customization</h4>
+ <p>If you want to add the capability for other developers to customize the order the views are laid out in your layout algorithm, you have to use the Sirius view ordering API. For example you will have in your
+ <code>org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LineLayoutProvider.layoutEditParts(List, IAdaptable)</code> method of your layout provider the following code:
+ </p>
+ <pre><code>ViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ //Use the default one that return the same order.
+ viewOrdering = new SimpleViewOrdering();
}
- return packageHierarchyLayoutProvider;
+
+ viewOrdering.setViews(views);
+ final List&lt;View&gt; sortedViews = viewOrdering.getSortedViews();
+</code></pre>
+ <p>with the method
+ <code>getContainerEditPart</code> that would be :
+ </p>
+ <pre><code>protected IGraphicalEditPart getContainerEditPart(final List&lt;EditPart&gt; selectedObjects) {
+ if (selectedObjects != null &amp;&amp; !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) (selectedObjects.iterator().next()).getParent();
+ }
+ return null;
+ }
+</code></pre>
+ <p>Then you will apply your layout algorithm on those ordered views.</p>
+ <h3 id="IntegrateyourcustomlayoutalgorithmtoSirius">Integrate your custom layout algorithm to Sirius </h3>
+ <p>To be used, your custom algorithm should be declared to Sirius with the provided extension point
+ <code>org.eclipse.sirius.diagram.ui.layoutProvider</code>. This extension point requires a sub class of
+ <code>LayoutProvider</code> that will provide your layout algorithm. Its API is the following:
+ </p>
+ <img border="0" src="images/arrange-all/arrange-all-layoutProvider.png"/>
+ <p>The
+ <code>LayoutProvider</code> interface contains the following methods:
+ </p>
+ <ul>
+ <li>
+ <code>isDiagramLayoutProvider</code>: This method should return true if the provided layout algorithm can handle layouting from root diagram part when this part is layout action&#8217;s target. It means your provider will be called with
+ <code>org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider.layoutEditParts(GraphicalEditPart, IAdaptable)</code> in this case. The call will only be done if your provider inherits from
+ <code>org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider</code>. If not or if
+ <code>isDiagramLayoutProvider</code> returns false, then the method
+ <code>org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider.layoutEditParts(List, IAdaptable)</code> is called and will delegate to the method
+ <code>layoutEditParts(List, IAdaptable)</code> of your provider.
+ </li>
+ <li>
+ <code>provides</code>: Should return true if your
+ <code>LayoutProvider</code> do provide a layout algorithm for the view associated to the given edit part and should be used. False otherwise.
+ </li>
+ <li>
+ <code>getLayoutNodeProvider</code>: Return the layout algorithm component to use to lay out the diagram elements target of the layout action.
+ </li>
+ </ul>
+ <p>For example the left right composite providers is declared as followed:</p>
+ <pre><code>public class CompositeLeftRightProvider implements LayoutProvider {
+ /** The delegated GMF provider. */
+ private AbstractLayoutEditPartProvider layoutNodeProvider;
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeLeftRightLayoutProvider cdtp = new CompositeLeftRightLayoutProvider();
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ // ArrangeSelectionLayoutProvider wrap all providers to manage
+ // the selected diagram element on diagram "Arrange all"
+ AbstractLayoutProvider abstractLayoutProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ } else {
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(clp);
+ }
+ }
+ return this.layoutNodeProvider;
}
- public boolean isDiagramLayoutProvider() {
+ public boolean provides(final IGraphicalEditPart container) {
+ return isInDDiagramWithConfiguredLeftRightLayout(container.getNotationView());
+ }
+
+ private boolean isInDDiagramWithConfiguredLeftRightLayout(final View view) {
+ final Layout foundLayout = DiagramLayoutCustomization.findLayoutSettings(view);
+ if (foundLayout instanceof CompositeLayout) {
+ return ((CompositeLayout) foundLayout).getDirection() == LayoutDirection.LEFT_TO_RIGHT;
+ }
return false;
}
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
}
-</pre>
- <p>Finally, we add the extension in the plug-in file :</p>
- <p>
+</code></pre>
+ <p>The layout algorithm provided by this
+ <code>LayoutProvider</code> will be used if the view to layout is associated to a Sirius mapping contained by a diagram mapping declaring the left right composite provider in the VSM.
+ </p>
+ <p>After this provider creation, you have to registered it with the extension point:
+ <br/>
<img border="0" src="images/arrange-all/arrange-all-layoutprovider-extension.png"/>
</p>
- <pre><code>&lt;extension point="org.eclipse.sirius.diagram.layoutProvider"&gt;
- &lt;layoutProvider priority="high" providerClass="com.example.uml2.specific.provider.Uml2LayoutProvider"&gt;
- &lt;/layoutProvider&gt;
-&lt;/extension&gt;
+ <p>A priority can be set. If two layout providers provide layouting for a same object, the one with the higher priority will be used.</p>
+ <h4 id="Composingyourlayoutproviders">Composing your layout providers</h4>
+ <p>You may want to reuse some of the Sirius layout providers in addition of your own layout provider to avoid code rewrite or duplication if the layouting you are doing does not conflict with the layouting other providers are doing.</p>
+ <p>To do that, Sirius offers a
+ <code>CompoundLayoutProvider</code> allowing to trigger layouting of many compatible providers in their insertion order. The compatible providers are:
+ </p>
+ <ul>
+ <li>The PinnedElementsLayoutProvider</li>
+ <li>The LineLayoutProvider</li>
+ <li>The GridLayoutProvider</li>
+ </ul>
+ <p>Also some providers are not compatible with the compound one but instead use a wrapping mechanism. They wrap another provider. Then their layouting code is called before or after the wrapped&#8217;s code:</p>
+ <ul>
+ <li>The ArrangeSelectionLayoutProvider is called before wrapped provider</li>
+ <li>The ArrangeAllOnlyLayoutProvider is called before wrapped provider</li>
+ <li>The BorderItemAwareLayoutProvider is called after wrapped provider. Its initialization is done with the code </li>
+ </ul>
+ <pre><code>BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
</code></pre>
- <h2 id="EnabletheborderednodeslayoutonacustomLayoutProvider">Enable the bordered nodes layout on a custom LayoutProvider</h2>
- <p>The bordered nodes layout arranges all the bordered nodes which are connected to one edge. This arrange reduces the path of the edge between each extremity.</p>
- <p>Currently, the layout of the bordered nodes is activated on the default Layout Provider (CompositeDownTopProvider, CompositeLeftRightProvider and OrderedTreeLayoutProvider. To enable the bordered nodes layout on a new LayoutProvider, in the method getLayoutNodeProvider(IGraphicalEditPart), you must create a new BorderItemAwareLayoutProvider with your own LayoutProvider in parameter. This new BorderItemAwareLayoutProvider must be return instead of your own.</p>
- <p>Example of the OrderedTreeLayoutProvider</p>
- <pre><code>public AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container) {
- if (isDDiagramWithConfiguredOrderedTreeLayout(container)) {
- //Get the expected layout provider
- AbstractLayoutProvider layoutNodeProvider = getGridLayoutProvider();
- //Create new BorderItemAwareLayoutProvider
- layoutNodeProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(layoutNodeProvider);
- //Return the BorderItemAwareLayoutProvider which wrap the previous one
- return layoutNodeProvider;
- } else {
- return null;
+ <p>
+ <code>PinnedElementsLayoutProvider</code> should always do its layouting before BorderItemAwareLayoutProvider but after any other layouting.
+ <br/>
+ <code>BorderItemAwareLayoutProvider</code> should always do its layouting at the end.
+ <br/>To know more about these providers you can read the section
+ <a href="#siriusLayoutProviders">Sirius Layout Providers</a>.
+ </p>
+ <p>The
+ <code>CompoundLayoutProvider</code> API is the following:
+ </p>
+ <img border="0" src="images/arrange-all/arrange-all-CompoundLayoutProvider.png"/>
+ <p>The
+ <code>provides</code> and
+ <code>layoutEditParts</code> methods delegate to registered providers. You should not override those.
+ <br/>You only have to add all the providers that should be used to layout with method
+ <code>addProvider</code>.
+ </p>
+ <h5 id="Example">Example</h5>
+ <p>Compound and wrapping providers are used for example by the composite providers that can be used from a VSM declaration:</p>
+ <pre><code>public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeDownTopLayoutProvider cdtp = new CompositeDownTopLayoutProvider();
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ AbstractLayoutProvider abstractLayoutProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ }
+ return this.layoutNodeProvider;
}
-}
</code></pre>
+ <p>We see that this composite provider is composed with the
+ <code>PinnedElementsLayoutProvider</code> in a compound provider. The composite provider does its layouting first but does not handle pinned elements. The pinned one restore pinned elements to their original position and fix potential overlaps.
+ <br/>Then the compound provider is wrapped in a
+ <code>BorderItemAwareLayoutProvider</code> that is also wrapped in the
+ <code>ArrangeSelectionLayoutProvider</code>.
+ <br/>The layout execution flow is the following:
+ <br/>
+ <code>ArrangeSelectionLayoutProvider</code> is called first. Then
+ <code>CompoundLayoutProvider</code> is called and delegates to
+ <code>CompositeDownTopLayoutProvider</code> first and
+ <code>PinnedElementsLayoutProvider</code> second. Lastly
+ <code>BorderItemAwareLayoutProvider</code> is called.
+ </p>
+ <h2 id="ProvideacustomlayoutalgorithmwithGMFextensionpoint">Provide a custom layout algorithm with GMF extension point</h2>
+ <p>This extension point provided by GMF can be used to provide your custom layout algorithm in Sirius diagram editors if you don&#8217;t need any of the features and implementation ease brought by Sirius API.</p>
+ <p>To do that, your layout algorithm in the form of an
+ <code>AbstractLayoutEditPartProvider</code> can be declared in GMF extension point
+ <code>org.eclipse.gmf.runtime.diagram.ui.layoutProviders</code>.
+ </p>
+ <p>The priority of the default one used by Sirius is medium. To be override your priority must be lowest than medium.</p>
</body>
</html> \ No newline at end of file
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.textile b/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.textile
index 42fad6a051..8d29e783e5 100644
--- a/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.textile
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/extensions-provide_custom-arrange-all.textile
@@ -1,335 +1,609 @@
-h1. Provide a custom arrange-all
+h1. Providing a custom diagram layout algorithm ("Arrange All")
-h2. Goals
+h2. The Arrange All functionality in short
-One of the main issues of visual modelers is the global arrangement of all elements. GMF provides a default implementation of an &quot;Arrange All&quot; algorithm to solve this issue but it happens that this default behavior is not adapted for some diagrams. Imagine a diagram representing the hierarchy between a program classes, the &quot;natural&quot; representation a human thinks about is that of a tree. When you add associations on such diagrams, GMF won't keep the tree representation of the diagram. Sirius provides an API to arrange diagrams according to custom business rules.
+The arrange-all functionality is available in Sirius diagram editors in the form of a button and a context menu:
-h2. The arrange all concept as implemented by GMF
+!images/arrange-all/arrange-all-ui.png!
+
+Its effect is to layout the selected diagram elements (or the whole diagram if no elements are selected) based on the layout algorithm defined for the diagram, or using a default, generic algorithm if nothin is specified.
-GMF provides basic API and implementations to ease the customization of the &quot;Arrange All&quot; mechanism. It also implements a complete algorithm that is based on the graphical elements.
+By default, there are two different layout algorithm that can be configured in the VSM for a diagram:
+* The @Ordered Tree Layout@ algorithm: useful to represent elements in a hierarchical way.
+* The @Composite Layout@ algorithm: used to customize specific aspects of the default algorithm, i.e. the general layout orientation and the padding between elements.
-The top level type of this this API is @ILayoutNodeProvider@
+ !images/arrange-all/arrange-all-vsm.png!
-!images/arrange-all/arrange-all-tlinterface.jpg!
+If none of these algorithms fit your needs, Sirius provides two extension points @org.eclipse.sirius.diagram.ui.layoutProvider@ and @org.eclipse.sirius.diagram.ui.viewOrderingProvider@ as well as an API to ease the writing of your own layout algorithms and their usage in Sirius diagram editors.
-As you can see, this interface is designed for genericity. Fortunately, GMF provides abstract classes that handle the low-level work while letting you define the business rules:
+This API reuse the GMF "Arrange All" API and augments it with features needed by Sirius layout algorithms like:
+* The need to take in consideration pinned diagram elements
+* The need to take in consideration bordered nodes connected to edges
-!images/arrange-all/arrange-all-ls.jpg!
+h2. The Arrange All concept as implemented by GMF
-This can be done by implementing three operations:
-* @boolean provides(IOperation operation)@
+GMF provides basic API and implementations to ease the customization of the "Arrange All" mechanism. It also implements a complete algorithm that is based on the graphical elements.
+
+The top level type of this this API is @ILayoutNodeProvider@ :
+
+ !images/arrange-all/arrange-all-iproviderApi.png!
+
+This interface is very generic, but GMF provides abstract classes that handle the low-level work while letting you define only the layouting business rules:
+
+ !images/arrange-all/arrange-all-ilayoutNodeproviderApi.png!
+
+This can be done by creating a component inheriting the abstract class @AbstractLayoutEditPartProvider@ and implementing its methods:
+* @boolean provides(IOperation operation)@ from @IProvider@ super interface
* @Command layoutEditParts(GraphicalEditPart containerEditPart, IAdaptable layoutHint)@
* @Command layoutEditParts(selectedObjectst List, IAdaptable layoutHint)@
-The @provides@ operation is meant to return true if the class can arrange the diagram for the specified operation.
+The @provides@ operation is meant to return true if the class can arrange the diagram for the specified operation.
-The @layoutEditParts@ operations will return the commands that will actually be in charge of arranging the diagrams' edit parts. The first one takes the main container that is to be arranged while the latter accepts a list of edit parts to arrange.
+The @layoutEditParts@ operations will return the commands that will actually be in charge of arranging the diagrams' edit parts. The first one takes the main container that is to be arranged while the latter accepts a list of edit parts to arrange.
-h2. The LayoutProviders as provided by Sirius
+The implementation of those three methods forms your layout algorithm.
-The class @AbstractLayoutEditPartProvider@ is the simplest one. Sirius provides utility classes to ease the implementation of &quot;Arrange All&quot; algorithms:
+With this API comes an extension point @org.eclipse.gmf.runtime.diagram.ui.layoutProviders@. It allows your own @AbstractLayoutEditPart@ layout algorithm to be used.
-!images/arrange-all/arrange-all-air.jpg!
+h3. The views and edit parts
-Here is a list of all provided layout providers and a basic description of each:
-* @LineLayoutProvider@: lays out all views on a single line (either vertical or horizontal).
-* @GrigLayoutProvider@: lays out all views as a grid.
-* @InlineEdgeLayoutProvider@: lays out connections alongside their source and target nodes (useful on the sequence diagram for example).
+When doing layouting with GMF based tools like Sirius you will hear about views and edit parts. It is important to understand what they are.
-h2. The ViewOrderings
+The views are persisted model elements that when interpreted represent your diagram visually. You have the @Node@, @Edge@, @Style@, etc...
-h3. The API
+They contain all visual information like the position, the size of the element, its color, etc...
+Edit parts ties the model (the views) to a visual representation with a one on one relationship. One edit part points at one view. They are responsible for making changes to the model and interpret and display graphically the view.
-!images/arrange-all/viewordering.jpg!
+h2. Sirius Layouting API
-All @LayoutProvider@ provided by Sirius can be used with a @ViewOrdering@ which has the responsibility of actually ordering the views.
+The Sirius Layouting API simplifies the writing of a custom layout algorithm by providing different layout providers specific to Sirius context that you can reuse easily in addition of your own layout algorithm if it does not conflict with these.
-The aim of all these classes is to order the GMF views and to provide this result to an @AbstractLayoutProvider@.
+It also provides utility methods that you can find useful
-h3. Sample
+The Sirius API for layouting Sirius diagrams is the following:
-Here is a sample ordering all views to get a tree from a list of UML2 packages :
+!images/arrange-all/arrange-all-layoutingAPI.png!
-pre..
-/**
- * Orders packages.
- */
-public class PackageTreeOrdering extends SemanticTreeOrdering {
+h3(#siriusLayoutProviders). Sirius Layout providers
- public List getSemanticChildren(EObject semanticParent, List candidates) {
- List result = Collections.EMPTY_LIST;
- if (semanticParent instanceof Package) {
- result = new LinkedList&lt;Package&gt;(((Package) semanticParent).getNestedPackages());
- result.retainAll(candidates);
- }
- return result;
- }
+Sirius defines and already uses various different layout providers in different contexts.
+
+Here is a list of all of those with a basic description of each:
+
+h5. DefaultLayoutProvider
+
+It is used by Sirius as entry point to dispatch arrange requests on a Sirius diagram to registered layout providers. The dispatch takes in consideration layout algorithm specified in the VSM and layout providers provided from the Sirius extension point @org.eclipse.sirius.diagram.ui.layoutProvider@.
+
+h5. LineLayoutProvider
+
+Lays out all views on a single line (either vertical or horizontal).
+
+h5. GridLayoutProvider
+
+Lays out all views as a grid.
+
+h5. InlineEdgeLayoutProvider
+
+Lays out connections alongside their source and target nodes (useful on the sequence diagram for example).
+
+h5. ArrangeSelectionLayoutProvider
+
+This provider only purpose is to delegate arrangement to attached layout provider after having added information about not selected parts in the layout hint.
+
+It is used for example with our composite layout providers to keep fixed the not selected parts and to avoid putting other selected parts on it when layouting.
+
+It is used primary by default provider whenever the arrange-all action is called because the arrangement can be done on a selection and not on all diagram elements.
+
+h5. ArrangeAllOnlyLayoutProvider
+
+This provider is used to delegate layouting to attached provider only when an arrange-all is done on a diagram and not an arrange selection.
+
+When used as primary provider, the arrange selection action is not available in the menu of a Sirius editor using this provider.
+
+It is used for example in the @OrderedTreeLayoutProvider@ where it does not make sense to make a tree of just some elements because the all concept is to have a complete tree representation.
+
+h5. PinnedElementLayoutProvider
+
+This provider is designed to work with another layout provider. When its attached layout provider has done its layouting part, this provider iterates on all diagram elements that are pinned (should not have its position changes by an automatic layout) to put it back at its original position. In case of visual overlap conflict with a non-pinned element, the non-pinned element is move near the pinned one where no overlap is visible.
+
+h5. CompoundLayoutProvider
+
+This provider allows to compose different layout providers into a compound one. It is useful to reuse some layouting rules that does not conflict with others needed ones.
+
+For example the providers @CompositeDownTopLayoutProvider@ and @PinnedElementLayoutProvider@ can be attached to a compound instance. Then those providers are called in their attach order one after another to do their layouting parts. It avoids the composite provider to duplicate code to handle pinned elements.
+
+h5. BorderedItemAwareLayoutProvider
+
+This provider arranges all the bordered nodes which are connected to one edge. It reduces the path of the edge between each extremity. For example:
+
+ !images/arrange-all/arrange-all-border1.png!
+
+Becomes
+
+ !images/arrange-all/arrange-all-border2.png!
+
+h3. The view ordering
+
+h4. API
+
+The view ordering is an API used by layout algorithms provided by Sirius. It allows to define a sub class of @ViewOrdering@ that will sort children views of a parent view. The layouting will be done on sorted views instead of the original order in the layout provider.
- public List getSemanticRoots(List objects) {
- List&lt;Package&gt; roots = new LinkedList&lt;Package&gt;();
- for (Object object : objects) {
- EObject semantic = (EObject) object;
- if (semantic instanceof Package) {
- Package package_ = (Package) semantic;
- if (package_.eContainer() == null || !objects.contains(package_.eContainer())) {
- roots.add(package_);
+For example, if I use the @LineLayoutProvider@ with default view ordering component in a diagram with two elements, views will be aligned in their natural iteration order:
+
+ !images/arrange-all/arrange-all-viewOrdering.png!
+
+If I define a view ordering component that reorder view in the lexicographic order, views will be aligned accordingly:
+
+ !images/arrange-all/arrange-all-viewOrdering2.png!
+
+This mechanism avoid to rewrite a layout provider if the only thing that should be changed is the order the layout provider lays out its views.
+
+Its architecture is the following:
+
+ !images/arrange-all/arrange-all-viewOrderingArchitecture.png!
+
+h4. Compatible providers
+
+Layout providers need to sort view by using the view ordering framework so your view ordering component can be used. The Sirius providers using this framework are the following:
+
+* @GridLayoutProvider@
+* @InlineEdgeLAyoutProvider@
+* @LineLAyoutProvider@
+
+h4. Writing a ViewOrdering
+
+To contribute a @ViewOrdering@ that should be used in a Sirius provider, you have to create a sub class of @AbstractViewOrdering@ or @AbstractViewOrdering@ or @ViewOrdering@ if you need to do an ordering different from what Sirius offers with its abstract classes.
+Sirius abstract classes offers ordering only on Node views by default.
+
+For example the lexicographic view ordering component would be the following:
+
+bc.. public class LexicographicViewOrdering extends AbstractViewOrdering {
+
+ @Override
+ protected List<View> sortViews(List<View> views) {
+ Comparator<View> comparing = Comparator.comparing(new Function<View, String>() {
+ @Override
+ public String apply(View t) {
+ DDiagramElement element = (DDiagramElement) t.getElement();
+ return element.getName();
}
- }
+ });
+ Collections.sort(views, comparing);
+ return views;
}
- return roots;
}
-}
+h4. Contributing your ViewOrdering with extension point
+
+Once your view ordering component has been written you have to make Sirius aware of it so it can be used.
+To do that Sirius provides an extension point @org.eclipse.sirius.diagram.viewOrderingProvider@.
+It allows to register a @ViewOrderingProvider@ that will provide your view ordering component:
-This tells us how to order the packages. We must notify Sirius that this @ViewOrdering@ has to be used for the Package Hierarchy diagram.
+ !images/arrange-all/arrange-all-viewOrderingProvider.png!
+
+It contains the following methods:
+- @provides@: tell Sirius if your ordering component should be used when layouting views associated to the given mapping.
+- @getViewOrdering@: tell Sirius what view ordering component to use to order views when the provides method returns true.
-h3. The @ViewOrderingProvider@
+For example with the lexicographic you will have:
+
+ !images/arrange-all/arrange-all-viewOrderingExtensionPoint.png!
-Here is the implementation of a @ViewOrderingProvider@ for an UML2 modeler :
+bc.. <extension point="org.eclipse.sirius.diagram.viewOrderingProvider">
+ <viewOrderingProvider providerClass="org.eclipse.sirius.diagram.ui.tools.internal.providers.LexicographicViewOrderingProvider" />
+</extension>
-pre..
-/**
- * The view ordering provider for UML2 modeler.
- */
-public class Uml2ViewOrderingProvider implements ViewOrderingProvider {
- /** The classifier ordering. */
- private ClassifierTreeOrdering classifierOrdering = new ClassifierTreeOrdering();
+p. The @LexicographicViewOrderingProvider@ code would be:
- public Uml2ViewOrderingProvider() {
- classifierOrdering.setUserAwareCapable(true);
- }
+bc.. public class LexicographicViewOrderingProvider implements ViewOrderingProvider {
- public ViewOrdering getViewOrdering(DiagramElementMapping mapping) {
- return (ViewOrdering) getMappingToViewOrdering().get(getMappingName(mapping));
+ public LexicographicViewOrderingProvider() {
}
+ @Override
public boolean provides(DiagramElementMapping mapping) {
- return getMappingToViewOrdering().containsKey(getMappingName(mapping));
- }
-
- private String getMappingName(DiagramElementMapping mapping) {
- String result = null;
- if (mapping instanceof NodeMapping) {
- result = ((NodeMapping) mapping).getName();
- } else if (mapping instanceof EdgeMapping) {
- result = ((EdgeMapping) mapping).getName();
- } else if (mapping instanceof ContainerMapping) {
- result = ((ContainerMapping) mapping).getName();
- }
- return result;
+ return true;
}
- /**
- * Returns a map : MappingName(String) -&gt; ViewOrdering.
- *
- * @return a map : MappingName(String) -&gt; ViewOrdering.
- */
- private Map getMappingToViewOrdering() {
- Map result = new HashMap();
- result.put(Uml2Constants.LIFELINE_MAPPING_NAME, new LifelineOrdering());
- result.put(Uml2Constants.MESSAGE_MAPPING_NAME, new MessageOrdering());
- result.put(Uml2Constants.CLASS_MAPPING_NAME, this.classifierOrdering);
- result.put(Uml2Constants.INTERFACE_MAPPING_NAME, this.classifierOrdering);
- return result;
+ @Override
+ public ViewOrdering getViewOrdering(DiagramElementMapping mapping) {
+ return new LexicographicViewOrdering();
}
-
}
-p. Once this has been implemented, we need to add the extension to the plugin.xml :
+h3. Write your custom layout algorithm
-!images/arrange-all/arrange-all-provider-extension.png!
+To create your own layout algorithm with Sirius API you have to subclass one Sirius abstract class depending on what you need to use:
-bc.
-<extension point="org.eclipse.sirius.diagram.viewOrderingProvider">
- <viewOrderingProvider providerClass="com.example.uml2.specific.provider.Uml2ViewOrderingProvider" />
-</extension>
+h5. AbstractLayoutEditPartProvider
+This class should be extended if you do not need what AbstractLayoutProvider provides.
+Its API is:
-h2. How to map a Layout Provider with a Diagram
+!images/arrange-all/arrange-all-abstractLayoutEditPart.png!
+
+Only the abstract methods @layoutEditParts@ should be override. It is these methods that do the layouting by providing commands modifying underlying views information.
-Now, we know how to both order and arrange views. We still need to let Sirius know that we want to use a custom Layout Provider for a specific Diagram.
+h5. AbstractLayoutProvider
-!images/arrange-all/airlayoutprovider.jpg!
+This class should be extended if your layouting algorithm is meant to be used in addition to others during a same layouting pass and if you need to be aware of the bound changes produced by the other algorithms. It also should be used if you need all the utility methods regarding view bounds manipulation provided by this abstract class.
-Here is a provider designed for an UML2 modeler:
+When sub classing this one, you only have to implement @layoutEditParts(List, IAdaptable)@ and to override @provides(IOperation)@ methods.
-pre..
-public class Uml2LayoutProvider implements LayoutProvider {
+For example the @LineLayoutProvider@ have the following code:
- /** The GMF layout provider. */
- private CompoundLayoutProvider layoutProvider;
+bc.. public class LineLayoutProvider extends AbstractLayoutProvider {
- /** The class diagram layout provider. */
- private GridLayoutProvider classDiagramLayoutProvider;
+ /** The default padding. */
+ private static final Insets DEFAULT_PADDING = new Insets(30, 30, 30, 30);
- /** The package hierarchy layout provider. */
- private GridLayoutProvider packageHierarchyLayoutProvider;
+ /**
+ * <code>true</code> if the line is horizontal, <code>false</code> if the line is vertical.
+ */
+ private boolean horizontal = true;
+ /**
+ * <code>true</code> if the line is horizontal, <code>false</code> if the line is vertical.
+ *
+ * @param horizontal
+ * <code>true</code> if the line is horizontal, <code>false</code> if the line is vertical.
+ */
+ public void setHorizontal(final boolean horizontal) {
+ this.horizontal = horizontal;
+ }
- public AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container) {
- if (isSequenceDiagram(container)) {
- if (this.layoutProvider == null) {
- this.layoutProvider = new CompoundLayoutProvider();
- LineLayoutProvider lineLayoutProvider = new LineLayoutProvider();
- lineLayoutProvider.getPadding().right = 80;
- lineLayoutProvider.setHorizontal(true);
- this.layoutProvider.addProvider(lineLayoutProvider);
- inlineEdgeLayoutProvider inlineEdgeLayoutProvider = new InlineEdgeLayoutProvider();
- inlineEdgeLayoutProvider.setSide(PositionConstants.EAST_WEST);
- inlineEdgeLayoutProvider.setStart(PositionConstants.RIGHT);
- inlineEdgeLayoutProvider.setAlignment(PositionConstants.VERTICAL);
- inlineEdgeLayoutProvider.setChangeNodeHeight(true);
- inlineEdgeLayoutProvider.setChangeNodeWidth(true);
- inlineEdgeLayoutProvider.getPaddings().top = 50;
- this.layoutProvider.addProvider(inlineEdgeLayoutProvider);
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ final Iterator<?> iterEditParts = selectedObjects.iterator();
+ final List<View> views = new ArrayList<View>(selectedObjects.size());
+ final Map<View, ShapeEditPart> viewsToEditPartMap = new HashMap<View, ShapeEditPart>();
+ while (iterEditParts.hasNext()) {
+ final Object next = iterEditParts.next();
+ if (next instanceof ShapeEditPart && !(next instanceof IBorderItemEditPart)) {
+ final ShapeEditPart shapeEditPart = (ShapeEditPart) next;
+ final View view = shapeEditPart.getNotationView();
+ viewsToEditPartMap.put(view, shapeEditPart);
+ views.add(view);
+ } else {
+ iterEditParts.remove();
}
- return this.layoutProvider;
- } else if (isClassDiagram(container)) {
- return this.getClassDiagramLayoutProvider();
- } else if (isPackageHierarchyDiagram(container)) {
- return this.getPackageHierarchyLayoutProvider();
}
- return null;
- }
+ ViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ // use a simple view ordering ... too bad.
+ viewOrdering = new SimpleViewOrdering();
+ }
- public boolean provides(IGraphicalEditPart container) {
- return (isClassDiagram(container) &amp;&amp; isAbleToLayoutClassDiagram(container)) || isSequenceDiagram(container) || isPackageHierarchyDiagram(container);
+ viewOrdering.setViews(views);
+ final List<View> sortedViews = viewOrdering.getSortedViews();
+ final List<ShapeEditPart> sortedEditParts = new ArrayList<ShapeEditPart>(sortedViews.size());
+ final Iterator<View> iterSortedViews = sortedViews.listIterator();
+ while (iterSortedViews.hasNext()) {
+ final View currentView = iterSortedViews.next();
+ final ShapeEditPart currentEditPart = viewsToEditPartMap.get(currentView);
+ sortedEditParts.add(currentEditPart);
+ }
+ return createNodeChangeBoundCommands(sortedEditParts);
}
- private boolean isSequenceDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof DDiagram) {
- DDiagram diagram = (DDiagram) editPart.resolveSemanticElement();
- if (viewPoint.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.SEQUENCE_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
+ /**
+ * Create the change bounds commands.
+ *
+ * @param sortedNodes
+ * the nodes to move.
+ * @return the change bounds command.
+ */
+ protected Command createNodeChangeBoundCommands(final List<ShapeEditPart> sortedNodes) {
+ final CompoundCommand result = new CompoundCommand();
+ final Iterator<ShapeEditPart> iterEditParts = sortedNodes.iterator();
+ int currentX = 0;
+ while (iterEditParts.hasNext()) {
+ final ShapeEditPart shapeEditPart = iterEditParts.next();
+ if (!(shapeEditPart instanceof IBorderItemEditPart)) {
+
+ final View view = shapeEditPart.getNotationView();
+ // the zoom.
+ double scale = 1.0;
+ if (shapeEditPart.getRoot() instanceof DiagramRootEditPart) {
+ final ZoomManager zoomManager = ((DiagramRootEditPart) shapeEditPart.getRoot()).getZoomManager();
+ scale = zoomManager.getZoom();
+ }
+ //
+ // Compute request data.
+ final Point ptOldLocation = shapeEditPart.getFigure().getBounds().getLocation();
+ // shapeEditPart.getFigure().translateToAbsolute(ptOldLocation);
+ final int locationX = horizontal ? currentX + this.getPadding().left : this.getPadding().left;
+ final int locationY = horizontal ? this.getPadding().top : currentX + this.getPadding().top;
+ final Point ptLocation = new Point(locationX, locationY);
+ final Dimension delta = ptLocation.getDifference(ptOldLocation);
+
+ final Object existingRequest = this.findRequest(view, org.eclipse.gef.RequestConstants.REQ_MOVE);
+ int step = 0;
+ if (existingRequest == null) {
+ final ChangeBoundsRequest request = new ChangeBoundsRequest(org.eclipse.gef.RequestConstants.REQ_MOVE);
+ request.setEditParts(shapeEditPart);
+ request.setMoveDelta(new PrecisionPoint(delta.width * scale, delta.height * scale));
+ request.setLocation(new PrecisionPoint(ptLocation.x * scale, ptLocation.y * scale));
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+
+ final Command cmd = this.buildCommandWrapper(request, shapeEditPart);
+ if (cmd != null && cmd.canExecute()) {
+ result.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(view,
+ // request);
+ }
+ } else if (existingRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingRequest;
+ changeBoundsRequest.setMoveDelta(new PrecisionPoint(delta.width * scale, delta.height * scale));
+ changeBoundsRequest.setLocation(new PrecisionPoint(ptLocation.x * scale, ptLocation.y * scale));
+
+ step = this.horizontal ? getBounds(shapeEditPart).width : getBounds(shapeEditPart).height;
+ }
+ currentX += horizontal ? step + getPadding().right + getPadding().left : step + this.getPadding().bottom + this.getPadding().top;
+
+ // check the size of the container.
+ EditPart container = shapeEditPart.getParent();
+ while (container instanceof CompartmentEditPart) {
+ container = container.getParent();
+ }
+ if (container instanceof ShapeEditPart) {
+ final ShapeEditPart containerEditPart = (ShapeEditPart) container;
+
+ // The minimum witdh
+ final int minWidth = this.horizontal ? ((getPadding().left + getPadding().right) * sortedNodes.size()) + (getNodeMaxWidth(sortedNodes) * sortedNodes.size())
+ : getPadding().left + getNodeMaxWidth(sortedNodes) + getPadding().right;
+ // The minimum height
+ final int minHeight = this.horizontal ? getPadding().top + this.getNodeMaxHeight(sortedNodes) + this.getPadding().bottom
+ : ((getPadding().top + getPadding().bottom) * sortedNodes.size()) + (this.getNodeMaxHeight(sortedNodes) * sortedNodes.size());
+
+ final Dimension minDimension = new Dimension(minWidth, minHeight);
+
+ final Dimension difference = minDimension.getShrinked(containerEditPart.getFigure().getBounds().getSize());
+ if (difference.width > 0 || difference.height > 0) {
+ final Object existingContainerRequest = this.findRequest(containerEditPart, org.eclipse.gef.RequestConstants.REQ_RESIZE); // ;this.getViewsToChangeBoundsRequest().get(containerEditPart.getNotationView());
+ createChangeBoundsCommand(result, existingContainerRequest, containerEditPart, difference, scale);
+ }
+
}
+
}
}
- return false;
+ return result;
}
- private boolean isClassDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof ViewPoint) {
- DDiagram diagram = (DDaiagram) editPart.resolveSemanticElement();
- if (diagram.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.CLASS_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
- }
+ private void createChangeBoundsCommand(final CompoundCommand compoundCommand, final Object existingContainerRequest, final ShapeEditPart containerEditPart, final Dimension difference,
+ final double scale) {
+
+ if (existingContainerRequest == null) {
+ final ChangeBoundsRequest changeBoundsRequest = new ChangeBoundsRequest();
+ changeBoundsRequest.setEditParts(containerEditPart);
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
+ changeBoundsRequest.setLocation(new Point(0, 0));
+ changeBoundsRequest.setType(org.eclipse.gef.RequestConstants.REQ_RESIZE);
+ final Command cmd = this.buildCommandWrapper(changeBoundsRequest, containerEditPart);
+ if (cmd.canExecute()) {
+ compoundCommand.add(cmd);
+ // this.getViewsToChangeBoundsRequest().put(containerEditPart.getNotationView(),
+ // changeBoundsRequest);
}
+ } else if (existingContainerRequest instanceof ChangeBoundsRequest) {
+ final ChangeBoundsRequest changeBoundsRequest = (ChangeBoundsRequest) existingContainerRequest;
+ changeBoundsRequest.setResizeDirection(PositionConstants.SOUTH_EAST);
+ changeBoundsRequest.setSizeDelta(new Dimension((int) (difference.width * scale), (int) (difference.height * scale)));
}
- return false;
}
- private boolean isPackageHierarchyDiagram(IGraphicalEditPart container) {
- if (container instanceof AbstractDDiagramEditPart) {
- AbstractDDiagramEditPart editPart = (AbstractDDiagramEditPart) container;
- if (editPart.resolveSemanticElement() instanceof DDiagram) {
- DDiagram diagram = (DDiagram) editPart.resolveSemanticElement();
- if (viewPoint.getDescription() != null) {
- DiagramDescription diagramDescription = diagram.getDescription();
- return Uml2Constants.PACKAGE_HIERARCHY_DIAGRAM_DESCRIPTION_NAME.equals(diagramDescription.getName());
- }
+ /**
+ * Return the maximum width of all nodes (instances of {@link ShapeEditPart} ) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxWidth(final List<ShapeEditPart> nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final Object existingRequest = this.getViewsToChangeBoundsRequest().get(shapeEditPart.getNotationView());
+ int width = shapeEditPart.getFigure().getBounds().width;
+ if (existingRequest instanceof ChangeBoundsRequest) {
+ width = width + ((ChangeBoundsRequest) existingRequest).getSizeDelta().width;
+ }
+ if (width > max) {
+ max = width;
}
}
- return false;
+ return max;
}
- private boolean isAbleToLayoutClassDiagram(IGraphicalEditPart container) {
- if (container instanceof DiagramEditPart) {
- int nbNoInherance = 0;
- int nbInheritance = 0;
- Iterator iterConnections = ((DiagramEditPart) container).getConnections().iterator();
- while (iterConnections.hasNext()) {
- ConnectionEditPart connectionEditPart = (ConnectionEditPart) iterConnections.next();
- EObject semantic = connectionEditPart.resolveSemanticElement();
- if (semantic != null &amp;&amp; semantic instanceof DecorateSemanticElement) {
- EObject realSemantic = ((DecorateSemanticElement) semantic).getTarget();
- if (realSemantic instanceof Generalization) {
- nbInheritance++;
- } else {
- nbNoInherance++;
- }
- } else {
- nbNoInherance++;
- }
+ /**
+ * Return the maximum height of all nodes (instances of {@link ShapeEditPart}) that are in the specified list.
+ *
+ * @param nodes
+ * the nodes.
+ * @return the maximum width of all nodes that are in the specified list.
+ */
+ protected int getNodeMaxHeight(final List<ShapeEditPart> nodes) {
+ int max = -1;
+ for (final ShapeEditPart shapeEditPart : nodes) {
+ final int height = this.getBounds(shapeEditPart).height;
+ if (height > max) {
+ max = height;
}
- return nbInheritance &gt; nbNoInherance;
}
- return false;
+ return max;
+ }
+
+ @Override
+ public boolean provides(final IOperation operation) {
+ final View cview = getContainer(operation);
+ if (cview == null) {
+ return false;
+ }
+ final IAdaptable layoutHint = ((ILayoutNodeOperation) operation).getLayoutHint();
+ final String layoutType = layoutHint.getAdapter(String.class);
+ return LayoutType.DEFAULT.equals(layoutType);
+ }
+
+ /**
+ * Return the padding to use.
+ *
+ * @return the padding to use.
+ */
+ public Insets getPadding() {
+ return DEFAULT_PADDING;
}
/**
- * Returns the class diagram layout provider.
- *
- * @return the class diagram layout provider.
+ * Get the container edit part of an object list. Currently the function takes only the first object of the list
+ *
+ * @param selectedObjects
+ * the selected object
+ * @return the container edit part
*/
- public GridLayoutProvider getClassDiagramLayoutProvider() {
- if (classDiagramLayoutProvider == null) {
- classDiagramLayoutProvider = new GridLayoutProvider();
- classDiagramLayoutProvider.setColumnSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- classDiagramLayoutProvider.setLineSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- classDiagramLayoutProvider.getPadding().top = 20;
- classDiagramLayoutProvider.getPadding().bottom = 20;
- classDiagramLayoutProvider.getPadding().left = 20;
- classDiagramLayoutProvider.getPadding().right = 20;
+ protected IGraphicalEditPart getContainerEditPart(final List<EditPart> selectedObjects) {
+ if (selectedObjects != null && !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) (selectedObjects.iterator().next()).getParent();
}
- return classDiagramLayoutProvider;
+ return null;
}
- public GridLayoutProvider getPackageHierarchyLayoutProvider() {
- if (packageHierarchyLayoutProvider == null) {
- packageHierarchyLayoutProvider = new GridLayoutProvider();
- packageHierarchyLayoutProvider.setColumnSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- packageHierarchyLayoutProvider.setLineSizeMode(GridLayoutProvider.DIMENSION_BY_LINE_OR_COLUMN);
- packageHierarchyLayoutProvider.getPadding().top = 20;
- packageHierarchyLayoutProvider.getPadding().bottom = 20;
- packageHierarchyLayoutProvider.getPadding().left = 30;
- packageHierarchyLayoutProvider.getPadding().right = 30;
+}
+h4. Allow view ordering customization
+
+If you want to add the capability for other developers to customize the order the views are laid out in your layout algorithm, you have to use the Sirius view ordering API. For example you will have in your @org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LineLayoutProvider.layoutEditParts(List, IAdaptable)@ method of your layout provider the following code:
+
+bc.. ViewOrdering viewOrdering = ViewOrderingHint.getInstance().consumeViewOrdering(getContainerEditPart(selectedObjects).getNotationView());
+ if (viewOrdering == null) {
+ //Use the default one that return the same order.
+ viewOrdering = new SimpleViewOrdering();
+ }
+
+ viewOrdering.setViews(views);
+ final List<View> sortedViews = viewOrdering.getSortedViews();
+p. with the method @getContainerEditPart@ that would be :
+
+bc.. protected IGraphicalEditPart getContainerEditPart(final List<EditPart> selectedObjects) {
+ if (selectedObjects != null && !selectedObjects.isEmpty()) {
+ return (IGraphicalEditPart) (selectedObjects.iterator().next()).getParent();
+ }
+ return null;
+ }
+p. Then you will apply your layout algorithm on those ordered views.
+
+h3. Integrate your custom layout algorithm to Sirius
+
+To be used, your custom algorithm should be declared to Sirius with the provided extension point @org.eclipse.sirius.diagram.ui.layoutProvider@. This extension point requires a sub class of @LayoutProvider@ that will provide your layout algorithm. Its API is the following:
+
+ !images/arrange-all/arrange-all-layoutProvider.png!
+
+The @LayoutProvider@ interface contains the following methods:
+* @isDiagramLayoutProvider@: This method should return true if the provided layout algorithm can handle layouting from root diagram part when this part is layout action's target. It means your provider will be called with @org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider.layoutEditParts(GraphicalEditPart, IAdaptable)@ in this case. The call will only be done if your provider inherits from @org.eclipse.sirius.diagram.ui.tools.api.layout.provider.AbstractLayoutProvider@. If not or if @isDiagramLayoutProvider@ returns false, then the method @org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider.layoutEditParts(List, IAdaptable)@ is called and will delegate to the method @layoutEditParts(List, IAdaptable)@ of your provider.
+* @provides@: Should return true if your @LayoutProvider@ do provide a layout algorithm for the view associated to the given edit part and should be used. False otherwise.
+* @getLayoutNodeProvider@: Return the layout algorithm component to use to lay out the diagram elements target of the layout action.
+
+For example the left right composite providers is declared as followed:
+
+bc.. public class CompositeLeftRightProvider implements LayoutProvider {
+ /** The delegated GMF provider. */
+ private AbstractLayoutEditPartProvider layoutNodeProvider;
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeLeftRightLayoutProvider cdtp = new CompositeLeftRightLayoutProvider();
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ if (ENABLE_BORDERED_NODES_ARRANGE_ALL) {
+ // ArrangeSelectionLayoutProvider wrap all providers to manage
+ // the selected diagram element on diagram "Arrange all"
+ AbstractLayoutProvider abstractLayoutProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ } else {
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(clp);
+ }
}
- return packageHierarchyLayoutProvider;
+ return this.layoutNodeProvider;
}
- public boolean isDiagramLayoutProvider() {
+ public boolean provides(final IGraphicalEditPart container) {
+ return isInDDiagramWithConfiguredLeftRightLayout(container.getNotationView());
+ }
+
+ private boolean isInDDiagramWithConfiguredLeftRightLayout(final View view) {
+ final Layout foundLayout = DiagramLayoutCustomization.findLayoutSettings(view);
+ if (foundLayout instanceof CompositeLayout) {
+ return ((CompositeLayout) foundLayout).getDirection() == LayoutDirection.LEFT_TO_RIGHT;
+ }
return false;
}
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
}
-p. Finally, we add the extension in the plug-in file :
+p. The layout algorithm provided by this @LayoutProvider@ will be used if the view to layout is associated to a Sirius mapping contained by a diagram mapping declaring the left right composite provider in the VSM.
-!images/arrange-all/arrange-all-layoutprovider-extension.png!
+After this provider creation, you have to registered it with the extension point:
+ !images/arrange-all/arrange-all-layoutprovider-extension.png!
-bc.
-<extension point="org.eclipse.sirius.diagram.layoutProvider">
- <layoutProvider priority="high" providerClass="com.example.uml2.specific.provider.Uml2LayoutProvider">
- </layoutProvider>
-</extension>
+A priority can be set. If two layout providers provide layouting for a same object, the one with the higher priority will be used.
+h4. Composing your layout providers
-h2. Enable the bordered nodes layout on a custom LayoutProvider
+You may want to reuse some of the Sirius layout providers in addition of your own layout provider to avoid code rewrite or duplication if the layouting you are doing does not conflict with the layouting other providers are doing.
-The bordered nodes layout arranges all the bordered nodes which are connected to one edge. This arrange reduces the path of the edge between each extremity.
+To do that, Sirius offers a @CompoundLayoutProvider@ allowing to trigger layouting of many compatible providers in their insertion order. The compatible providers are:
-Currently, the layout of the bordered nodes is activated on the default Layout Provider (CompositeDownTopProvider, CompositeLeftRightProvider and OrderedTreeLayoutProvider. To enable the bordered nodes layout on a new LayoutProvider, in the method getLayoutNodeProvider(IGraphicalEditPart), you must create a new BorderItemAwareLayoutProvider with your own LayoutProvider in parameter. This new BorderItemAwareLayoutProvider must be return instead of your own.
+* The PinnedElementsLayoutProvider
+* The LineLayoutProvider
+* The GridLayoutProvider
-Example of the OrderedTreeLayoutProvider
+Also some providers are not compatible with the compound one but instead use a wrapping mechanism. They wrap another provider. Then their layouting code is called before or after the wrapped's code:
-bc.
-public AbstractLayoutEditPartProvider getLayoutNodeProvider(IGraphicalEditPart container) {
- if (isDDiagramWithConfiguredOrderedTreeLayout(container)) {
- //Get the expected layout provider
- AbstractLayoutProvider layoutNodeProvider = getGridLayoutProvider();
- //Create new BorderItemAwareLayoutProvider
- layoutNodeProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(layoutNodeProvider);
- //Return the BorderItemAwareLayoutProvider which wrap the previous one
- return layoutNodeProvider;
- } else {
- return null;
+* The ArrangeSelectionLayoutProvider is called before wrapped provider
+* The ArrangeAllOnlyLayoutProvider is called before wrapped provider
+* The BorderItemAwareLayoutProvider is called after wrapped provider. Its initialization is done with the code
+bc. BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
+
+@PinnedElementsLayoutProvider@ should always do its layouting before BorderItemAwareLayoutProvider but after any other layouting.
+@BorderItemAwareLayoutProvider@ should always do its layouting at the end.
+To know more about these providers you can read the section "Sirius Layout Providers":#siriusLayoutProviders.
+
+The @CompoundLayoutProvider@ API is the following:
+
+ !images/arrange-all/arrange-all-CompoundLayoutProvider.png!
+
+The @provides@ and @layoutEditParts@ methods delegate to registered providers. You should not override those.
+You only have to add all the providers that should be used to layout with method @addProvider@.
+
+h5. Example
+
+Compound and wrapping providers are used for example by the composite providers that can be used from a VSM declaration:
+
+bc. public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ if (this.layoutNodeProvider == null) {
+ final CompoundLayoutProvider clp = new CompoundLayoutProvider();
+ final CompositeDownTopLayoutProvider cdtp = new CompositeDownTopLayoutProvider();
+ clp.addProvider(cdtp);
+ clp.addProvider(new PinnedElementsLayoutProvider(cdtp));
+ AbstractLayoutProvider abstractLayoutProvider = BorderItemAwareLayoutProviderHelper.createBorderItemAwareLayoutProvider(clp);
+ this.layoutNodeProvider = new ArrangeSelectionLayoutProvider(abstractLayoutProvider);
+ }
+ return this.layoutNodeProvider;
}
-}
+
+We see that this composite provider is composed with the @PinnedElementsLayoutProvider@ in a compound provider. The composite provider does its layouting first but does not handle pinned elements. The pinned one restore pinned elements to their original position and fix potential overlaps.
+Then the compound provider is wrapped in a @BorderItemAwareLayoutProvider@ that is also wrapped in the @ArrangeSelectionLayoutProvider@.
+The layout execution flow is the following:
+@ArrangeSelectionLayoutProvider@ is called first. Then @CompoundLayoutProvider@ is called and delegates to @CompositeDownTopLayoutProvider@ first and @PinnedElementsLayoutProvider@ second. Lastly @BorderItemAwareLayoutProvider@ is called.
+
+h2. Provide a custom layout algorithm with GMF extension point
+
+This extension point provided by GMF can be used to provide your custom layout algorithm in Sirius diagram editors if you don't need any of the features and implementation ease brought by Sirius API.
+
+To do that, your layout algorithm in the form of an @AbstractLayoutEditPartProvider@ can be declared in GMF extension point @org.eclipse.gmf.runtime.diagram.ui.layoutProviders@.
+
+The priority of the default one used by Sirius is medium. To be override your priority must be lowest than medium.
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/airlayoutprovider.jpg b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/airlayoutprovider.jpg
deleted file mode 100644
index 844336bc89..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/airlayoutprovider.jpg
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-CompoundLayoutProvider.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-CompoundLayoutProvider.png
new file mode 100644
index 0000000000..1186d4de7e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-CompoundLayoutProvider.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-abstractLayoutEditPart.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-abstractLayoutEditPart.png
new file mode 100644
index 0000000000..f046f71358
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-abstractLayoutEditPart.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-air.jpg b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-air.jpg
deleted file mode 100644
index 6539686ecc..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-air.jpg
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border1.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border1.png
new file mode 100644
index 0000000000..572ffcccbd
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border1.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border2.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border2.png
new file mode 100644
index 0000000000..ce54f9e376
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-border2.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ilayoutNodeproviderApi.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ilayoutNodeproviderApi.png
new file mode 100644
index 0000000000..97485c812f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ilayoutNodeproviderApi.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-iproviderApi.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-iproviderApi.png
new file mode 100644
index 0000000000..66d9771003
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-iproviderApi.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutProvider.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutProvider.png
new file mode 100644
index 0000000000..d0b2e7cdd3
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutProvider.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutingAPI.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutingAPI.png
new file mode 100644
index 0000000000..c62e9aca8a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutingAPI.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutprovider-extension.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutprovider-extension.png
index db453d33e9..3c501d742d 100644
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutprovider-extension.png
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-layoutprovider-extension.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ls.jpg b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ls.jpg
deleted file mode 100644
index 440fe8adec..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ls.jpg
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-provider-extension.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-provider-extension.png
deleted file mode 100644
index 1123052156..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-provider-extension.png
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-tlinterface.jpg b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-tlinterface.jpg
deleted file mode 100644
index 0e00a63c64..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-tlinterface.jpg
+++ /dev/null
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ui.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ui.png
new file mode 100644
index 0000000000..ef38c7061a
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-ui.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering.png
new file mode 100644
index 0000000000..260853186b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering2.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering2.png
new file mode 100644
index 0000000000..3b869bf324
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrdering2.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingArchitecture.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingArchitecture.png
new file mode 100644
index 0000000000..fa8a978664
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingArchitecture.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingExtensionPoint.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingExtensionPoint.png
new file mode 100644
index 0000000000..2dfa5bf6e6
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingExtensionPoint.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingProvider.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingProvider.png
new file mode 100644
index 0000000000..531899559e
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-viewOrderingProvider.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-vsm.png b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-vsm.png
new file mode 100644
index 0000000000..2008f936fa
--- /dev/null
+++ b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/arrange-all-vsm.png
Binary files differ
diff --git a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/viewordering.jpg b/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/viewordering.jpg
deleted file mode 100644
index 07e5294b4d..0000000000
--- a/plugins/org.eclipse.sirius.doc/doc/developer/images/arrange-all/viewordering.jpg
+++ /dev/null
Binary files differ

Back to the top