Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Guilet2018-02-19 17:27:07 +0000
committerPierre Guilet2018-02-28 13:14:58 +0000
commitca5a79711048c86fd7d0dfe05c98b036660fd6c1 (patch)
tree4d641c3adef158631e262cb098fa4f8028c7ab4c
parent866e12d3c9c48529d32ef856956298f053bb8cdf (diff)
downloadorg.eclipse.sirius-ca5a79711048c86fd7d0dfe05c98b036660fd6c1.tar.gz
org.eclipse.sirius-ca5a79711048c86fd7d0dfe05c98b036660fd6c1.tar.xz
org.eclipse.sirius-ca5a79711048c86fd7d0dfe05c98b036660fd6c1.zip
[509070] ELK algorithms integration to Sirius
ELK algorithms have been integrated to Sirius. A specifier can now add in the VSM a GenericLayout pointing at the id of an ELK algorithm. This algorithm will then be used to do the arrange-all action. A registry has been made allowing to provide generic layout providers to be use from the VSM directly. This registry can accept any provider subclassing DefaultLayoutProvider. Not only the ELK provider. ELK integration is now available with Sirius build. An ELK feature has been created and is present in the Sirius update site under the Sirius category. Bug: 509070 Change-Id: Ifdd28184fa2b1c6d5a118b212f5d9e9f15093ce5 Signed-off-by: pguilet <pierre.guilet@obeo.fr>
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/.project17
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/build.properties3
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/epl-v10.html328
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/feature.properties21
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/feature.xml41
-rw-r--r--packaging/org.eclipse.sirius.diagram.elk.feature/pom.xml65
-rw-r--r--packaging/org.eclipse.sirius.parent/pom.xml3
-rw-r--r--packaging/org.eclipse.sirius.update/category.xml32
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/.classpath7
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/.project28
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/.settings/org.eclipse.jdt.core.prefs7
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/META-INF/MANIFEST.MF23
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/build.properties6
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/plugin.properties13
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/plugin.xml19
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/pom.xml26
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ApplyLayoutRequest.java133
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/DiagramElkPlugin.java61
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ELKLayoutNodeProvider.java42
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkDiagramLayoutConnector.java1084
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkSiriusLayoutSetup.java71
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutCommand.java273
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutEditPolicy.java603
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/IEditPartFilter.java45
-rw-r--r--plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/LayoutEditPolicyProvider.java53
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF1
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/plugin.xml8
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src-gen/org/eclipse/sirius/diagram/ui/provider/DiagramUIPlugin.java45
-rw-r--r--plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/internal/layout/GenericLayoutProvider.java81
-rw-r--r--releng/org.eclipse.sirius.targets/modules/elk-0.3.tpd12
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_neon.target9
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_neon.targetplatform1
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_oxygen.target9
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_oxygen.targetplatform1
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_photon.target9
-rw-r--r--releng/org.eclipse.sirius.targets/sirius_photon.targetplatform1
36 files changed, 3163 insertions, 18 deletions
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/.project b/packaging/org.eclipse.sirius.diagram.elk.feature/.project
new file mode 100644
index 0000000000..c8faf7774a
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.sirius.diagram.elk.feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/build.properties b/packaging/org.eclipse.sirius.diagram.elk.feature/build.properties
new file mode 100644
index 0000000000..5864ee043e
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/build.properties
@@ -0,0 +1,3 @@
+bin.includes = feature.xml,\
+ epl-v10.html,\
+ feature.properties
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/epl-v10.html b/packaging/org.eclipse.sirius.diagram.elk.feature/epl-v10.html
new file mode 100644
index 0000000000..ed4b196655
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/epl-v10.html
@@ -0,0 +1,328 @@
+<html xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 9">
+<meta name=Originator content="Microsoft Word 9">
+<link rel=File-List
+href="./Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml">
+<title>Eclipse Public License - Version 1.0</title>
+<!--[if gte mso 9]><xml>
+ <o:DocumentProperties>
+ <o:Revision>2</o:Revision>
+ <o:TotalTime>3</o:TotalTime>
+ <o:Created>2004-03-05T23:03:00Z</o:Created>
+ <o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
+ <o:Pages>4</o:Pages>
+ <o:Words>1626</o:Words>
+ <o:Characters>9270</o:Characters>
+ <o:Lines>77</o:Lines>
+ <o:Paragraphs>18</o:Paragraphs>
+ <o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
+ <o:Version>9.4402</o:Version>
+ </o:DocumentProperties>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:TrackRevisions/>
+ </w:WordDocument>
+</xml><![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+@font-face
+ {font-family:Tahoma;
+ panose-1:2 11 6 4 3 5 4 4 2 4;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:553679495 -2147483648 8 0 66047 0;}
+ /* Style Definitions */
+p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+p
+ {margin-right:0in;
+ mso-margin-top-alt:auto;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+p.BalloonText, li.BalloonText, div.BalloonText
+ {mso-style-name:"Balloon Text";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:8.0pt;
+ font-family:Tahoma;
+ mso-fareast-font-family:"Times New Roman";}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.25in 1.0in 1.25in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+-->
+</style>
+</head>
+
+<body lang=EN-US style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
+</p>
+
+<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
+THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
+REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
+OF THIS AGREEMENT.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+in the case of the initial Contributor, the initial code and documentation
+distributed under this Agreement, and<br clear=left>
+b) in the case of each subsequent Contributor:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+changes to the Program, and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+additions to the Program;</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
+such changes and/or additions to the Program originate from and are distributed
+by that particular Contributor. A Contribution 'originates' from a Contributor
+if it was added to the Program by such Contributor itself or anyone acting on
+such Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in conjunction
+with the Program under their own license agreement, and (ii) are not derivative
+works of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
+entity that distributes the Program.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
+claims licensable by a Contributor which are necessarily infringed by the use
+or sale of its Contribution alone or when combined with the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
+distributed in accordance with this Agreement.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
+receives the Program under this Agreement, including all Contributors.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+Subject to the terms of this Agreement, each Contributor hereby grants Recipient
+a non-exclusive, worldwide, royalty-free copyright license to<span
+style='color:red'> </span>reproduce, prepare derivative works of, publicly
+display, publicly perform, distribute and sublicense the Contribution of such
+Contributor, if any, and such derivative works, in source code and object code
+form.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
+patent license under Licensed Patents to make, use, sell, offer to sell, import
+and otherwise transfer the Contribution of such Contributor, if any, in source
+code and object code form. This patent license shall apply to the combination
+of the Contribution and the Program if, at the time the Contribution is added
+by the Contributor, such addition of the Contribution causes such combination
+to be covered by the Licensed Patents. The patent license shall not apply to
+any other combinations which include the Contribution. No hardware per se is
+licensed hereunder. </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
+Recipient understands that although each Contributor grants the licenses to its
+Contributions set forth herein, no assurances are provided by any Contributor
+that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient
+for claims brought by any other entity based on infringement of intellectual
+property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility
+to secure any other intellectual property rights needed, if any. For example,
+if a third party patent license is required to allow Recipient to distribute
+the Program, it is Recipient's responsibility to acquire that license before
+distributing the Program.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
+Each Contributor represents that to its knowledge it has sufficient copyright
+rights in its Contribution, if any, to grant the copyright license set forth in
+this Agreement. </span></p>
+
+<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
+Program in object code form under its own license agreement, provided that:</span>
+</p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it complies with the terms and conditions of this Agreement; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+its license agreement:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+effectively excludes on behalf of all Contributors all liability for damages,
+including direct, indirect, special, incidental and consequential damages, such
+as lost profits; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
+states that any provisions which differ from this Agreement are offered by that
+Contributor alone and not by any other party; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
+states that source code for the Program is available from such Contributor, and
+informs licensees how to obtain it in a reasonable manner on or through a
+medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
+
+<p><span style='font-size:10.0pt'>When the Program is made available in source
+code form:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it must be made available under this Agreement; and </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
+copy of this Agreement must be included with each copy of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
+copyright notices contained within the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
+originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution. </span></p>
+
+<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
+
+<p><span style='font-size:10.0pt'>Commercial distributors of software may
+accept certain responsibilities with respect to end users, business partners
+and the like. While this license is intended to facilitate the commercial use
+of the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes the
+Program in a commercial product offering, such Contributor (&quot;Commercial
+Contributor&quot;) hereby agrees to defend and indemnify every other
+Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
+costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
+legal actions brought by a third party against the Indemnified Contributor to
+the extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor
+to control, and cooperate with the Commercial Contributor in, the defense and
+any related settlement negotiations. The Indemnified Contributor may participate
+in any such claim at its own expense.</span> </p>
+
+<p><span style='font-size:10.0pt'>For example, a Contributor might include the
+Program in a commercial product offering, Product X. That Contributor is then a
+Commercial Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance claims and
+warranties are such Commercial Contributor's responsibility alone. Under this
+section, the Commercial Contributor would have to defend claims against the
+other Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
+WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and distributing the
+Program and assumes all risks associated with its exercise of rights under this
+Agreement , including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs or
+equipment, and unavailability or interruption of operations. </span></p>
+
+<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
+THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
+
+<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
+or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without
+further action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.</span> </p>
+
+<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
+against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with
+other software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the date
+such litigation is filed. </span></p>
+
+<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
+shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable
+period of time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive. </span></p>
+
+<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
+copies of this Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The Agreement
+Steward reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement Steward has
+the right to modify this Agreement. The Eclipse Foundation is the initial
+Agreement Steward. The Eclipse Foundation may assign the responsibility to
+serve as the Agreement Steward to a suitable separate entity. Each new version
+of the Agreement will be given a distinguishing version number. The Program
+(including Contributions) may always be distributed subject to the version of
+the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly stated
+in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.</span> </p>
+
+<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
+State of New York and the intellectual property laws of the United States of
+America. No party to this Agreement will bring a legal action under this
+Agreement more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.</span> </p>
+
+<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
+
+</div>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/feature.properties b/packaging/org.eclipse.sirius.diagram.elk.feature/feature.properties
new file mode 100644
index 0000000000..7eca5b189a
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/feature.properties
@@ -0,0 +1,21 @@
+# ====================================================================
+# Copyright (c) 2018 Obeo
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Obeo - initial API and implementation
+# ====================================================================
+featureName = Sirius ELK integration
+providerName = Eclipse Modeling Project
+copyright=\
+Copyright (c) 2018 Obeo and others.\n\
+All rights reserved. This program and the accompanying materials\n\
+are made available under the terms of the Eclipse Public License v1.0\n\
+which accompanies this distribution, and is available at\n\
+http://www.eclipse.org/legal/epl-v10.html\n\
+\n\
+Contributors:\n\
+ Obeo - initial API and implementation\n
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/feature.xml b/packaging/org.eclipse.sirius.diagram.elk.feature/feature.xml
new file mode 100644
index 0000000000..d701a5b333
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/feature.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.sirius.diagram.elk.feature"
+ label="%featureName"
+ version="6.0.0.qualifier"
+ provider-name="%providerName"
+ license-feature="org.eclipse.license"
+ license-feature-version="0.0.0">
+
+ <description url="http://www.eclipse.org/sirius">
+ ELK integration allowing to arrange diagram with ELK layout algorithms.
+ </description>
+
+ <copyright>
+ %copyright
+ </copyright>
+
+ <license url="%licenseURL">
+ %license
+ </license>
+
+ <includes
+ id="org.eclipse.elk.algorithms.feature"
+ version="0.0.0"/>
+
+ <includes
+ id="org.eclipse.elk.feature"
+ version="0.0.0"/>
+
+ <includes
+ id="org.eclipse.elk.graphviz.feature"
+ version="0.0.0"/>
+
+ <plugin
+ id="org.eclipse.sirius.diagram.elk"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/packaging/org.eclipse.sirius.diagram.elk.feature/pom.xml b/packaging/org.eclipse.sirius.diagram.elk.feature/pom.xml
new file mode 100644
index 0000000000..b2b5d17b99
--- /dev/null
+++ b/packaging/org.eclipse.sirius.diagram.elk.feature/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2018 Obeo
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ Obeo - Initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.sirius</groupId>
+ <artifactId>sirius-parent</artifactId>
+ <version>6.0.0-SNAPSHOT</version>
+ <relativePath>../../packaging/org.eclipse.sirius.parent</relativePath>
+ </parent>
+
+ <properties>
+ <!-- Skip feature in Sonar analysis -->
+ <sonar.skip>true</sonar.skip>
+ </properties>
+
+ <artifactId>org.eclipse.sirius.diagram.elk.feature</artifactId>
+ <packaging>eclipse-feature</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.tycho.extras</groupId>
+ <artifactId>tycho-source-feature-plugin</artifactId>
+ <version>${tycho-extras-version}</version>
+ <executions>
+ <execution>
+ <id>source-feature</id>
+ <phase>package</phase>
+ <goals>
+ <goal>source-feature</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.tycho</groupId>
+ <artifactId>tycho-p2-plugin</artifactId>
+ <version>${tycho-version}</version>
+ <executions>
+ <execution>
+ <id>attached-p2-metadata</id>
+ <phase>package</phase>
+ <goals>
+ <goal>p2-metadata</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/packaging/org.eclipse.sirius.parent/pom.xml b/packaging/org.eclipse.sirius.parent/pom.xml
index 7667f9b189..58bed21b00 100644
--- a/packaging/org.eclipse.sirius.parent/pom.xml
+++ b/packaging/org.eclipse.sirius.parent/pom.xml
@@ -380,6 +380,7 @@
<module>../../plugins/org.eclipse.sirius.common.ui</module>
<module>../../plugins/org.eclipse.sirius.common.ui.ext</module>
<module>../../plugins/org.eclipse.sirius.common.xtext</module>
+ <module>../../plugins/org.eclipse.sirius.diagram.elk</module>
<module>../../plugins/org.eclipse.sirius.diagram.sequence.edit</module>
<module>../../plugins/org.eclipse.sirius.diagram.sequence.ui</module>
<module>../../plugins/org.eclipse.sirius.diagram.sequence</module>
@@ -445,6 +446,8 @@
<module>../../packaging/org.eclipse.sirius.properties.feature</module>
<module>../../packaging/org.eclipse.sirius.specifier.properties.feature</module>
<module>../../packaging/org.eclipse.sirius.samples.properties.feature</module>
+
+ <module>../../packaging/org.eclipse.sirius.diagram.elk.feature</module>
<!-- update sites -->
<module>../../packaging/org.eclipse.sirius.update</module>
diff --git a/packaging/org.eclipse.sirius.update/category.xml b/packaging/org.eclipse.sirius.update/category.xml
index 66c5d25257..43e2b4ae0f 100644
--- a/packaging/org.eclipse.sirius.update/category.xml
+++ b/packaging/org.eclipse.sirius.update/category.xml
@@ -3,10 +3,8 @@
<description url="http://www.eclipse.org/sirius">
Sirius
</description>
- <feature id="org.eclipse.sirius.aql" version="0.0.0">
- </feature>
- <feature id="org.eclipse.sirius.aql.source" version="0.0.0">
- </feature>
+ <feature id="org.eclipse.sirius.aql" version="0.0.0"/>
+ <feature id="org.eclipse.sirius.aql.source" version="0.0.0"/>
<feature id="org.eclipse.sirius.runtime" version="0.0.0">
<category name="Sirius"/>
</feature>
@@ -37,10 +35,8 @@
<feature id="org.eclipse.sirius.runtime.ide.ui.source" version="0.0.0">
<category name="Sirius.SDK"/>
</feature>
- <feature id="org.eclipse.sirius.specifier" version="0.0.0">
- </feature>
- <feature id="org.eclipse.sirius.specifier.source" version="0.0.0">
- </feature>
+ <feature id="org.eclipse.sirius.specifier" version="0.0.0"/>
+ <feature id="org.eclipse.sirius.specifier.source" version="0.0.0"/>
<feature id="org.eclipse.sirius.specifier.ide.ui" version="0.0.0">
<category name="Sirius"/>
</feature>
@@ -113,16 +109,23 @@
<feature id="org.eclipse.sirius.specifier.properties.feature.source" version="0.0.0">
<category name="Sirius.SDK"/>
</feature>
- <!-- Non-categorized -->
- <feature id="org.eclipse.acceleo.query" version="0.0.0" />
- <feature id="org.eclipse.acceleo.query.source" version="0.0.0" />
- <feature id="org.eclipse.acceleo.ui.interpreter" version="0.0.0" />
- <feature id="org.eclipse.acceleo.ui.interpreter.source" version="0.0.0" />
+ <feature id="org.eclipse.acceleo.query" version="0.0.0"/>
+ <feature id="org.eclipse.acceleo.query.source" version="0.0.0"/>
+ <feature id="org.eclipse.acceleo.ui.interpreter" version="0.0.0"/>
+ <feature id="org.eclipse.acceleo.ui.interpreter.source" version="0.0.0"/>
<feature id="org.eclipse.eef.sdk.feature" version="0.0.0"/>
<feature id="org.eclipse.eef.sdk.feature.source" version="0.0.0"/>
<feature id="org.eclipse.eef.ext.widgets.reference.feature" version="0.0.0"/>
<feature id="org.eclipse.eef.ext.widgets.reference.feature.source" version="0.0.0"/>
-
+ <feature id="org.eclipse.elk.algorithms.feature" version="0.0.0"/>
+ <feature id="org.eclipse.elk.feature" version="0.0.0"/>
+ <feature id="org.eclipse.elk.graphviz.feature" version="0.0.0"/>
+ <feature url="features/org.eclipse.sirius.diagram.elk.feature_6.0.0.qualifier.jar" id="org.eclipse.sirius.diagram.elk.feature" version="6.0.0.qualifier">
+ <category name="Sirius"/>
+ </feature>
+ <feature url="features/org.eclipse.elk.algorithms.feature.source_0.3.0.jar" id="org.eclipse.elk.algorithms.feature.source" version="0.3.0"/>
+ <feature url="features/org.eclipse.elk.feature.source_0.3.0.jar" id="org.eclipse.elk.feature.source" version="0.3.0"/>
+ <feature url="features/org.eclipse.elk.graphviz.feature.source_0.3.0.jar" id="org.eclipse.elk.graphviz.feature.source" version="0.3.0"/>
<category-def name="Sirius" label="Sirius">
<description>
The Sirius Modeling Platform
@@ -133,6 +136,5 @@
The Sirius Modeling Platform SDK
</description>
</category-def>
-
<category-def name="Sirius.Dependencies" label="Sirius Dependencies"/>
</site>
diff --git a/plugins/org.eclipse.sirius.diagram.elk/.classpath b/plugins/org.eclipse.sirius.diagram.elk/.classpath
new file mode 100644
index 0000000000..eca7bdba8f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.sirius.diagram.elk/.project b/plugins/org.eclipse.sirius.diagram.elk/.project
new file mode 100644
index 0000000000..9229c9155f
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.sirius.diagram.elk</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.sirius.diagram.elk/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.sirius.diagram.elk/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..0c68a61dca
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/plugins/org.eclipse.sirius.diagram.elk/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.diagram.elk/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..c1d89bfb0c
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Localization: plugin
+Bundle-SymbolicName: org.eclipse.sirius.diagram.elk;singleton:=true
+Bundle-Version: 6.0.0.qualifier
+Bundle-Activator: org.eclipse.sirius.diagram.elk.DiagramElkPlugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.sirius.diagram;bundle-version="6.0.0",
+ org.eclipse.sirius.diagram.ui;bundle-version="6.0.0",
+ org.eclipse.draw2d,
+ org.eclipse.gef,
+ org.eclipse.gmf.runtime.diagram.ui,
+ org.eclipse.elk.core.service,
+ org.eclipse.elk.graph,
+ org.eclipse.gmf.runtime.diagram.ui.render;bundle-version="1.7.0",
+ org.eclipse.emf.common,
+ org.eclipse.emf.common.ui
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Bundle-ActivationPolicy: lazy
+Import-Package: com.google.common.collect;version="15.0.0"
+Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.sirius.diagram.elk/build.properties b/plugins/org.eclipse.sirius.diagram.elk/build.properties
new file mode 100644
index 0000000000..0dc34f7833
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties
diff --git a/plugins/org.eclipse.sirius.diagram.elk/plugin.properties b/plugins/org.eclipse.sirius.diagram.elk/plugin.properties
new file mode 100644
index 0000000000..dfd4666fa4
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/plugin.properties
@@ -0,0 +1,13 @@
+# ====================================================================
+# Copyright (c) 2018 Obeo
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Obeo - initial API and implementation
+# ====================================================================
+
+pluginName=Sirius ELK integration
+providerName = Eclipse Modeling Project
diff --git a/plugins/org.eclipse.sirius.diagram.elk/plugin.xml b/plugins/org.eclipse.sirius.diagram.elk/plugin.xml
new file mode 100644
index 0000000000..523c6fff2b
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/plugin.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension
+ point="org.eclipse.elk.core.service.layoutConnectors">
+ <setup
+ class="org.eclipse.sirius.diagram.elk.ElkSiriusLayoutSetup">
+ </setup>
+ </extension>
+ <extension
+ point="org.eclipse.gmf.runtime.diagram.ui.editpolicyProviders">
+ <editpolicyProvider
+ class="org.eclipse.sirius.diagram.elk.LayoutEditPolicyProvider">
+ <Priority
+ name="Lowest">
+ </Priority>
+ </editpolicyProvider>
+ </extension>
+</plugin>
diff --git a/plugins/org.eclipse.sirius.diagram.elk/pom.xml b/plugins/org.eclipse.sirius.diagram.elk/pom.xml
new file mode 100644
index 0000000000..fd147c62c0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2018 Obeo
+ All rights reserved. This program and the accompanying materials
+ are made available under the terms of the Eclipse Public License v1.0
+ which accompanies this distribution, and is available at
+ http://www.eclipse.org/legal/epl-v10.html
+
+ Contributors:
+ Obeo - Initial API and implementation
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.sirius</groupId>
+ <artifactId>sirius-parent</artifactId>
+ <version>6.0.0-SNAPSHOT</version>
+ <relativePath>../../packaging/org.eclipse.sirius.parent</relativePath>
+ </parent>
+
+ <artifactId>org.eclipse.sirius.diagram.elk</artifactId>
+ <version>6.0.0-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+
+</project> \ No newline at end of file
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ApplyLayoutRequest.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ApplyLayoutRequest.java
new file mode 100644
index 0000000000..a3337ad1be
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ApplyLayoutRequest.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.elk.core.util.Pair;
+import org.eclipse.elk.graph.ElkGraphElement;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.Request;
+
+/**
+ * Request for automatic layout on a set of edit parts of a diagram.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.ApplyLayoutRequest of commit
+ * 53a98c9c35bc38b6b7513e0e73fd9d688c34937f.
+ *
+ * @author msp
+ * @kieler.design proposed by msp
+ * @kieler.rating proposed yellow by msp
+ *
+ */
+public class ApplyLayoutRequest extends Request {
+
+ /** the request type used to apply layout. */
+ public static final String REQ_APPLY_LAYOUT = "apply layout";
+
+ /** list of layout graph elements and the corresponding edit parts. */
+ private List<Pair<ElkGraphElement, GraphicalEditPart>> mappingList = new LinkedList<>();
+
+ /** the upper bound for horizontal coordinates. */
+ private double boundx = Float.MAX_VALUE;
+
+ /** the upper bound for vertical coordinates. */
+ private double boundy = Float.MAX_VALUE;
+
+ /** the scale factor for all coordinates. */
+ private double scale = 1.0f;
+
+ /**
+ * Creates a request to apply layout.
+ */
+ public ApplyLayoutRequest() {
+ super(REQ_APPLY_LAYOUT);
+ }
+
+ /**
+ * Adds the given graph element and edit part to the request, if it has been
+ * modified by a layout algorithm.
+ *
+ * @param element
+ * graph element with layout data
+ * @param editPart
+ * the corresponding edit part
+ */
+ public void addElement(final ElkGraphElement element, final GraphicalEditPart editPart) {
+ // Back in the old days (Pepperidge Farm remembers...), an element was
+ // added to the mappingList only if
+ // its layout information had been modified. For the moment, we have
+ // removed the modified flag from graph
+ // elements. If they return, this would be a place to check for them.
+ mappingList.add(new Pair<ElkGraphElement, GraphicalEditPart>(element, editPart));
+ }
+
+ /**
+ * Returns a list of the graph elements and edit parts of this request.
+ *
+ * @return a list with graph elements and corresponding edit parts
+ */
+ public List<Pair<ElkGraphElement, GraphicalEditPart>> getElements() {
+ return mappingList;
+ }
+
+ /**
+ * Set an upper bound on the coordinates of the layout graph.
+ *
+ * @param x
+ * the upper bound for horizontal coordinates
+ * @param y
+ * the upper bound for vertical coordinates
+ */
+ public void setUpperBound(final double x, final double y) {
+ this.boundx = x;
+ this.boundy = y;
+ }
+
+ /**
+ * Returns the upper bound for horizontal coordinates.
+ *
+ * @return the x bound
+ */
+ public double getXBound() {
+ return boundx;
+ }
+
+ /**
+ * Returns the upper bound for vertical coordinates.
+ *
+ * @return the y bound
+ */
+ public double getYBound() {
+ return boundy;
+ }
+
+ /**
+ * Returns the factor to use for scaling coordinates.
+ *
+ * @return the scale factor
+ */
+ public double getScale() {
+ return scale;
+ }
+
+ /**
+ * Sets the factor to use for scaling coordinates.
+ *
+ * @param thescale
+ * the scale factor
+ */
+ public void setScale(final double thescale) {
+ this.scale = thescale;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/DiagramElkPlugin.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/DiagramElkPlugin.java
new file mode 100644
index 0000000000..4f1c903585
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/DiagramElkPlugin.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Obeo
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.Collection;
+
+import org.eclipse.elk.core.data.LayoutAlgorithmData;
+import org.eclipse.elk.core.data.LayoutMetaDataService;
+import org.eclipse.sirius.diagram.ui.provider.DiagramUIPlugin;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Activator registering ELK layout algorithms to Sirius registry.
+ *
+ * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a>
+ */
+public class DiagramElkPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.sirius.diagram.elk"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DiagramElkPlugin plugin;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+
+ Collection<LayoutAlgorithmData> algorithmData = LayoutMetaDataService.getInstance().getAlgorithmData();
+ for (LayoutAlgorithmData layoutAlgorithmData : algorithmData) {
+ DiagramUIPlugin.getPlugin().addLayoutProvider(layoutAlgorithmData.getId(), () -> new ELKLayoutNodeProvider());
+ }
+
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DiagramElkPlugin getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ELKLayoutNodeProvider.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ELKLayoutNodeProvider.java
new file mode 100644
index 0000000000..64ecd5cb09
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ELKLayoutNodeProvider.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Obeo
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.elk.core.service.LayoutConnectorsService;
+import org.eclipse.elk.core.service.LayoutMapping;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider;
+
+import com.google.inject.Injector;
+
+/**
+ * Layout node provider allowing to apply an ELK layout algorithm while
+ * arranging diagram elements.
+ *
+ * @author <a href=mailto:pierre.guilet@obeo.fr>Pierre Guilet</a>
+ *
+ */
+public class ELKLayoutNodeProvider extends DefaultLayoutProvider {
+
+ @Override
+ public Command layoutEditParts(final List selectedObjects, final IAdaptable layoutHint) {
+ Injector injector = LayoutConnectorsService.getInstance().getInjector(null, selectedObjects);
+ ElkDiagramLayoutConnector connector = injector.getInstance(ElkDiagramLayoutConnector.class);
+ LayoutMapping layoutMapping = connector.buildLayoutGraph(null, selectedObjects);
+ connector.layout(layoutMapping);
+ connector.transferLayout(layoutMapping);
+ return connector.getApplyCommand(layoutMapping);
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkDiagramLayoutConnector.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkDiagramLayoutConnector.java
new file mode 100644
index 0000000000..111601a5f0
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkDiagramLayoutConnector.java
@@ -0,0 +1,1084 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2016 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ * Camille Letavernier (CEA LIST) - Bug 485905
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.eclipse.draw2d.Connection;
+import org.eclipse.draw2d.ConnectionLocator;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.Label;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Insets;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.elk.core.IGraphLayoutEngine;
+import org.eclipse.elk.core.math.ElkPadding;
+import org.eclipse.elk.core.math.KVector;
+import org.eclipse.elk.core.options.CoreOptions;
+import org.eclipse.elk.core.options.EdgeLabelPlacement;
+import org.eclipse.elk.core.service.ElkServicePlugin;
+import org.eclipse.elk.core.service.IDiagramLayoutConnector;
+import org.eclipse.elk.core.service.LayoutMapping;
+import org.eclipse.elk.core.util.BasicProgressMonitor;
+import org.eclipse.elk.core.util.ElkUtil;
+import org.eclipse.elk.core.util.Maybe;
+import org.eclipse.elk.graph.ElkConnectableShape;
+import org.eclipse.elk.graph.ElkEdge;
+import org.eclipse.elk.graph.ElkEdgeSection;
+import org.eclipse.elk.graph.ElkGraphElement;
+import org.eclipse.elk.graph.ElkLabel;
+import org.eclipse.elk.graph.ElkNode;
+import org.eclipse.elk.graph.ElkPort;
+import org.eclipse.elk.graph.properties.IProperty;
+import org.eclipse.elk.graph.properties.IPropertyHolder;
+import org.eclipse.elk.graph.properties.Property;
+import org.eclipse.elk.graph.util.ElkGraphUtil;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.gef.EditPart;
+import org.eclipse.gef.RootEditPart;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.AbstractBorderItemEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ResizableCompartmentEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ShapeNodeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.figures.ResizableCompartmentFigure;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+import org.eclipse.gmf.runtime.draw2d.ui.figures.WrappingLabel;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.sirius.diagram.DDiagram;
+import org.eclipse.sirius.diagram.description.DiagramDescription;
+import org.eclipse.sirius.diagram.description.GenericLayout;
+import org.eclipse.sirius.diagram.ui.tools.api.figure.SiriusWrapLabel;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.ui.IWorkbenchPart;
+
+import com.google.common.collect.BiMap;
+
+/**
+ * Diagram layout connector that is able to generically layout diagrams
+ * generated by Sirius. The internal KGraph graph structure is built from the
+ * structure of edit parts in the diagram. The new layout is applied to the
+ * diagram using {@link GmfLayoutEditPolicy}, which creates a
+ * {@link GmfLayoutCommand} to directly manipulate data in the GMF notation
+ * model, where layout information is stored persistently.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.GmfDiagramLayoutConnector of commit
+ * a54c87f94fc4a9bb9ff426311c49ada9d3e72b97.
+ *
+ * This component has been added the capacity to launch diagram layout
+ * computing.
+ *
+ * It also has been added the general options setup from VSM specification.
+ *
+ * @kieler.design proposed by msp
+ * @kieler.rating yellow 2012-07-19 review KI-20 by cds, jjc
+ * @author ars
+ * @author msp
+ * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a>
+ *
+ */
+@Singleton
+public class ElkDiagramLayoutConnector implements IDiagramLayoutConnector {
+
+ /** list of connection edit parts that were found in the diagram. */
+ public static final IProperty<List<ConnectionEditPart>> CONNECTIONS = new Property<List<ConnectionEditPart>>("gmf.connections");
+
+ /** diagram edit part of the currently layouted diagram. */
+ public static final IProperty<DiagramEditPart> DIAGRAM_EDIT_PART = new Property<DiagramEditPart>("gmf.diagramEditPart");
+
+ /** the command that applies the transferred layout to the diagram. */
+ public static final IProperty<Command> LAYOUT_COMMAND = new Property<Command>("gmf.applyLayoutCommand");
+
+ /** the offset to add for all coordinates. */
+ public static final IProperty<KVector> COORDINATE_OFFSET = new Property<KVector>("gmf.coordinateOffset");
+
+ public static final String PREF_EXEC_TIME_MEASUREMENT = "elk.exectime.measure";
+
+ @Inject
+ private IEditPartFilter editPartFilter;
+
+ @Inject
+ private IGraphLayoutEngine graphLayoutEngine;
+
+ /**
+ * Calculates the absolute bounds of the given figure.
+ *
+ * @param figure
+ * a figure
+ * @return the absolute bounds
+ */
+ public static Rectangle getAbsoluteBounds(final IFigure figure) {
+ Rectangle bounds = new Rectangle(figure.getBounds()) {
+ static final long serialVersionUID = 1;
+
+ @Override
+ public void performScale(final double factor) {
+ // don't perform any scaling to avoid distortion by the zoom
+ // level
+ }
+ };
+ figure.translateToAbsolute(bounds);
+ return bounds;
+ }
+
+ /**
+ * Finds the diagram edit part of an edit part.
+ *
+ * @param editPart
+ * an edit part
+ * @return the diagram edit part, or {@code null} if there is no containing
+ * diagram edit part
+ */
+ public static DiagramEditPart getDiagramEditPart(final EditPart editPart) {
+ EditPart ep = editPart;
+ while (ep != null && !(ep instanceof DiagramEditPart) && !(ep instanceof RootEditPart)) {
+ ep = ep.getParent();
+ }
+ if (ep instanceof RootEditPart) {
+ // the diagram edit part is a direct child of the root edit part
+ RootEditPart root = (RootEditPart) ep;
+ ep = null;
+ for (Object child : root.getChildren()) {
+ if (child instanceof DiagramEditPart) {
+ ep = (EditPart) child;
+ }
+ }
+ }
+ return (DiagramEditPart) ep;
+ }
+
+ /**
+ * If the workbench part is a diagram editor, returns that. Otherwise,
+ * returns {@code null}. This is more or less just a fancy cast.
+ *
+ * @param workbenchPart
+ * the workbench part to check.
+ * @return the workbench part as a diagram editor, or {@code null}.
+ */
+ protected DiagramEditor getDiagramEditor(final IWorkbenchPart workbenchPart) {
+ if (workbenchPart instanceof DiagramEditor) {
+ return (DiagramEditor) workbenchPart;
+ }
+ return null;
+ }
+
+ @Override
+ public LayoutMapping buildLayoutGraph(final IWorkbenchPart workbenchPart, final Object diagramPart) {
+
+ // get the diagram editor part
+ DiagramEditor diagramEditor = getDiagramEditor(workbenchPart);
+
+ // choose the layout root edit part
+ IGraphicalEditPart layoutRootPart = null;
+ List<ShapeNodeEditPart> selectedParts = null;
+ if (diagramPart instanceof ShapeNodeEditPart || diagramPart instanceof DiagramEditPart) {
+ layoutRootPart = (IGraphicalEditPart) diagramPart;
+ } else if (diagramPart instanceof IGraphicalEditPart) {
+ EditPart tgEditPart = ((IGraphicalEditPart) diagramPart).getTopGraphicEditPart();
+ if (tgEditPart instanceof ShapeNodeEditPart) {
+ layoutRootPart = (IGraphicalEditPart) tgEditPart;
+ }
+ } else if (diagramPart instanceof Collection) {
+ Collection<?> selection = (Collection<?>) diagramPart;
+ // determine the layout root part from the selection
+ for (Object object : selection) {
+ if (object instanceof IGraphicalEditPart) {
+ if (layoutRootPart != null) {
+ EditPart parent = commonParent(layoutRootPart, (EditPart) object);
+ if (parent != null && !(parent instanceof RootEditPart)) {
+ layoutRootPart = (IGraphicalEditPart) parent;
+ }
+ } else if (!(object instanceof ConnectionEditPart)) {
+ layoutRootPart = (IGraphicalEditPart) object;
+ }
+ }
+ }
+ // build a list of edit parts that shall be layouted completely
+ if (layoutRootPart != null) {
+ selectedParts = new ArrayList<ShapeNodeEditPart>(selection.size());
+ for (Object object : selection) {
+ if (object instanceof IGraphicalEditPart) {
+ EditPart editPart = (EditPart) object;
+ while (editPart != null && editPart.getParent() != layoutRootPart) {
+ editPart = editPart.getParent();
+ }
+ if (editPart instanceof ShapeNodeEditPart && editPartFilter.filter(editPart) && !selectedParts.contains(editPart)) {
+ selectedParts.add((ShapeNodeEditPart) editPart);
+ }
+ }
+ }
+ }
+ }
+ if (layoutRootPart == null && diagramEditor != null) {
+ layoutRootPart = diagramEditor.getDiagramEditPart();
+ }
+ if (layoutRootPart == null) {
+ throw new IllegalArgumentException("Not supported by this layout connector: Workbench part " + workbenchPart + ", Edit part " + diagramPart);
+ }
+
+ // create the mapping
+ LayoutMapping mapping = buildLayoutGraph(layoutRootPart, selectedParts, workbenchPart);
+
+ return mapping;
+ }
+
+ /**
+ * Determine the lowest common parent of the two edit parts.
+ *
+ * @param editPart1
+ * the first edit part
+ * @param editPart2
+ * the second edit part
+ * @return the common parent, or {@code null} if there is none
+ */
+ protected static EditPart commonParent(final EditPart editPart1, final EditPart editPart2) {
+ EditPart ep1 = editPart1;
+ EditPart ep2 = editPart2;
+ do {
+ if (isParent(ep1, ep2)) {
+ return ep1;
+ }
+ if (isParent(ep2, ep1)) {
+ return ep2;
+ }
+ ep1 = ep1.getParent();
+ ep2 = ep2.getParent();
+ } while (ep1 != null && ep2 != null);
+ return null;
+ }
+
+ /**
+ * Determine whether the first edit part is a parent of or equals the second
+ * one.
+ *
+ * @param parent
+ * the tentative parent
+ * @param child
+ * the tentative child
+ * @return true if the parent is actually a parent of the child
+ */
+ protected static boolean isParent(final EditPart parent, final EditPart child) {
+ EditPart editPart = child;
+ do {
+ if (editPart == parent) {
+ return true;
+ }
+ editPart = editPart.getParent();
+ } while (editPart != null);
+ return false;
+ }
+
+ /**
+ * Creates the actual mapping given an edit part which functions as the root
+ * for the layout.
+ *
+ * @param layoutRootPart
+ * the layout root edit part
+ * @param selection
+ * a selection of contained edit parts to process, or
+ * {@code null} if the whole content shall be processed
+ * @param workbenchPart
+ * the workbench part, or {@code null}
+ * @return a layout graph mapping
+ */
+ protected LayoutMapping buildLayoutGraph(final IGraphicalEditPart layoutRootPart, final List<ShapeNodeEditPart> selection, final IWorkbenchPart workbenchPart) {
+
+ LayoutMapping mapping = new LayoutMapping(workbenchPart);
+ mapping.setProperty(CONNECTIONS, new LinkedList<ConnectionEditPart>());
+ mapping.setParentElement(layoutRootPart);
+
+ // find the diagram edit part
+ mapping.setProperty(DIAGRAM_EDIT_PART, getDiagramEditPart(layoutRootPart));
+
+ ElkNode topNode;
+ if (layoutRootPart instanceof ShapeNodeEditPart) {
+ // start with a specific node as root for layout
+ topNode = createNode(mapping, (ShapeNodeEditPart) layoutRootPart, null, null, null);
+ } else {
+ // start with the whole diagram as root for layout
+ topNode = ElkGraphUtil.createGraph();
+ Rectangle rootBounds = layoutRootPart.getFigure().getBounds();
+ if (layoutRootPart instanceof DiagramEditPart) {
+ String labelText = ((DiagramEditPart) layoutRootPart).getDiagramView().getName();
+ if (labelText.length() > 0) {
+ ElkLabel label = ElkGraphUtil.createLabel(topNode);
+ label.setText(labelText);
+ }
+ } else {
+ topNode.setLocation(rootBounds.x, rootBounds.y);
+ }
+ topNode.setDimensions(rootBounds.width, rootBounds.height);
+ mapping.getGraphMap().put(topNode, layoutRootPart);
+ }
+
+ // we set the ELK algorithm to use from viewpoint id defined.
+ final View view = layoutRootPart.getNotationView();
+ final EObject modelElement = view.getElement();
+ if (view instanceof Diagram && modelElement instanceof DDiagram) {
+ final DDiagram vp = (DDiagram) modelElement;
+ final DiagramDescription desc = vp.getDescription();
+ if (desc != null) {
+ final GenericLayout layout = (GenericLayout) desc.getLayout();
+ topNode.setProperty(CoreOptions.ALGORITHM, layout.getID().trim());
+ // topNode.setProperty(CoreOptions.PADDING, new ElkPadding(50));
+ }
+ }
+
+ mapping.setLayoutGraph(topNode);
+
+ if (selection != null && !selection.isEmpty()) {
+ // layout only the selected elements
+ double minx = Integer.MAX_VALUE;
+ double miny = Integer.MAX_VALUE;
+ Maybe<ElkPadding> kinsets = new Maybe<>();
+ for (ShapeNodeEditPart editPart : selection) {
+ ElkNode node = createNode(mapping, editPart, layoutRootPart, topNode, kinsets);
+ minx = Math.min(minx, node.getX());
+ miny = Math.min(miny, node.getY());
+ buildLayoutGraphRecursively(mapping, editPart, node, editPart);
+ }
+ mapping.setProperty(COORDINATE_OFFSET, new KVector(minx, miny));
+ } else {
+ // traverse all children of the layout root part
+ buildLayoutGraphRecursively(mapping, layoutRootPart, topNode, layoutRootPart);
+ }
+
+ // transform all connections in the selected area
+ processConnections(mapping);
+
+ return mapping;
+ }
+
+ /**
+ * Transfer all layout data from the last created KGraph instance to the
+ * original diagram. The diagram is not modified yet, but all required
+ * preparations are performed. This is separated from
+ * {@link #applyLayout(LayoutMapping)} to allow better code modularization.
+ *
+ * @param mapping
+ * a layout mapping that was created by this layout connector
+ */
+ public void transferLayout(final LayoutMapping mapping) {
+ // create a new request to change the layout
+ ApplyLayoutRequest applyLayoutRequest = new ApplyLayoutRequest();
+ for (Entry<ElkGraphElement, Object> entry : mapping.getGraphMap().entrySet()) {
+ if (!(entry.getValue() instanceof DiagramEditPart)) {
+ ElkGraphElement graphElement = entry.getKey();
+ IGraphicalEditPart part = (IGraphicalEditPart) entry.getValue();
+ applyLayoutRequest.addElement(graphElement, part);
+
+ }
+ }
+
+ ElkNode layoutGraph = mapping.getLayoutGraph();
+ applyLayoutRequest.setUpperBound(layoutGraph.getWidth(), layoutGraph.getHeight());
+
+ // correct the layout by adding the offset determined from the selection
+ KVector offset = mapping.getProperty(COORDINATE_OFFSET);
+ if (offset != null) {
+ addOffset(mapping.getLayoutGraph(), offset);
+ }
+
+ // check the validity of the editing domain to catch cases where it is
+ // disposed
+ DiagramEditPart diagramEditPart = mapping.getProperty(DIAGRAM_EDIT_PART);
+ if (((InternalTransactionalEditingDomain) diagramEditPart.getEditingDomain()).getChangeRecorder() != null) {
+ // retrieve a command for the request; the command is created by
+ // GmfLayoutEditPolicy
+ Command applyLayoutCommand = diagramEditPart.getCommand(applyLayoutRequest);
+ mapping.setProperty(LAYOUT_COMMAND, applyLayoutCommand);
+ }
+ }
+
+ /**
+ * Add the given offset to all direct children of the given graph.
+ *
+ * @param parentNode
+ * the parent node
+ * @param offset
+ * the offset to add
+ */
+ protected static void addOffset(final ElkNode parentNode, final KVector offset) {
+ // correct the offset with the minimal computed coordinates
+ double minx = Integer.MAX_VALUE;
+ double miny = Integer.MAX_VALUE;
+ for (ElkNode child : parentNode.getChildren()) {
+ minx = Math.min(minx, child.getX());
+ miny = Math.min(miny, child.getY());
+ }
+
+ // add the corrected offset
+ offset.add(-minx, -miny);
+ ElkUtil.translate(parentNode, offset.x, offset.y);
+ }
+
+ /**
+ * Apply the transferred layout to the original diagram. This final step is
+ * where the actual change to the diagram is done. This method is always
+ * called after {@link #transferLayout(LayoutMapping)} has been done.
+ *
+ * @param mapping
+ * a layout mapping that was created by this layout connector
+ */
+ public Command getApplyCommand(final LayoutMapping mapping) {
+ Command applyLayoutCommand = mapping.getProperty(LAYOUT_COMMAND);
+
+ return applyLayoutCommand;
+ }
+
+ /**
+ * Recursively builds a layout graph by analyzing the children of the given
+ * edit part.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param parentEditPart
+ * the parent edit part of the current elements
+ * @param parentLayoutNode
+ * the corresponding KNode
+ * @param currentEditPart
+ * the currently analyzed edit part
+ */
+ protected void buildLayoutGraphRecursively(final LayoutMapping mapping, final IGraphicalEditPart parentEditPart, final ElkNode parentLayoutNode, final IGraphicalEditPart currentEditPart) {
+
+ Maybe<ElkPadding> kinsets = new Maybe<ElkPadding>();
+ // autoSize.prepareForArrangeAll(Iterators.filter(currentEditPart.getChildren().iterator(),
+ // AbstractDiagramElementContainerEditPart.class), new ArrayList<>());
+ // iterate through the children of the element
+ for (Object obj : currentEditPart.getChildren()) {
+
+ // check visibility of the child
+ if (obj instanceof IGraphicalEditPart) {
+ IFigure figure = ((IGraphicalEditPart) obj).getFigure();
+ if (!figure.isVisible()) {
+ continue;
+ }
+ }
+
+ // process a port (border item)
+ if (obj instanceof AbstractBorderItemEditPart) {
+ AbstractBorderItemEditPart borderItem = (AbstractBorderItemEditPart) obj;
+ if (editPartFilter.filter(borderItem)) {
+ createPort(mapping, borderItem, parentEditPart, parentLayoutNode);
+ }
+
+ // process a compartment, which may contain other elements
+ } else if (obj instanceof ResizableCompartmentEditPart && ((CompartmentEditPart) obj).getChildren().size() > 0) {
+
+ CompartmentEditPart compartment = (CompartmentEditPart) obj;
+ if (editPartFilter.filter(compartment)) {
+ boolean compExp = true;
+ IFigure compartmentFigure = compartment.getFigure();
+ if (compartmentFigure instanceof ResizableCompartmentFigure) {
+ ResizableCompartmentFigure resizCompFigure = (ResizableCompartmentFigure) compartmentFigure;
+ // check whether the compartment is collapsed
+ compExp = resizCompFigure.isExpanded();
+ }
+
+ if (compExp) {
+ buildLayoutGraphRecursively(mapping, parentEditPart, parentLayoutNode, compartment);
+ }
+ }
+
+ // process a node, which may be a parent of ports, compartments,
+ // or other nodes
+ } else if (obj instanceof ShapeNodeEditPart) {
+ ShapeNodeEditPart childNodeEditPart = (ShapeNodeEditPart) obj;
+ if (editPartFilter.filter(childNodeEditPart)) {
+ ElkNode node = createNode(mapping, childNodeEditPart, parentEditPart, parentLayoutNode, kinsets);
+ // process the child as new current edit part
+ buildLayoutGraphRecursively(mapping, childNodeEditPart, node, childNodeEditPart);
+ }
+
+ // process a label of the current node
+ } else if (obj instanceof IGraphicalEditPart) {
+ ElkLabel newNodeLabel = createNodeLabel(mapping, (IGraphicalEditPart) obj, parentEditPart, parentLayoutNode);
+ if (newNodeLabel != null) {
+ parentLayoutNode.getLabels().add(newNodeLabel);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a node while building the layout graph.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param nodeEditPart
+ * the node edit part
+ * @param parentEditPart
+ * the parent node edit part that contains the current node
+ * @param parentElkNode
+ * the corresponding parent layout node
+ * @param elkinsets
+ * reference parameter for insets; the insets are calculated if
+ * this has not been done before
+ * @return the created node
+ */
+ protected ElkNode createNode(final LayoutMapping mapping, final ShapeNodeEditPart nodeEditPart, final IGraphicalEditPart parentEditPart, final ElkNode parentElkNode,
+ final Maybe<ElkPadding> elkinsets) {
+
+ IFigure nodeFigure = nodeEditPart.getFigure();
+ ElkNode childLayoutNode = ElkGraphUtil.createNode(parentElkNode);
+
+ // set location and size
+ Rectangle childBounds = getAbsoluteBounds(nodeFigure);
+ Rectangle containerBounds = getAbsoluteBounds(nodeFigure.getParent());
+ childLayoutNode.setX(childBounds.x - containerBounds.x);
+ childLayoutNode.setY(childBounds.y - containerBounds.y);
+ childLayoutNode.setDimensions(childBounds.width, childBounds.height);
+
+ // We would set the modified flag to false here, but that doesn't exist
+ // anymore
+
+ // determine minimal size of the node
+ try {
+ Dimension minSize = nodeFigure.getMinimumSize();
+ childLayoutNode.setProperty(CoreOptions.NODE_SIZE_MINIMUM, new KVector(minSize.width, minSize.height));
+ } catch (SWTException exception) {
+ // getMinimumSize() can cause this exception when fonts are disposed
+ // for some reason;
+ // ignore exception and leave the default minimal size
+ }
+
+ if (parentElkNode != null) {
+ // set insets if not yet defined
+ if (elkinsets.get() == null) {
+ Insets insets = calcSpecificInsets(parentEditPart.getFigure(), nodeFigure);
+ ElkPadding ei = new ElkPadding(insets.top, insets.right, insets.bottom, insets.left);
+ childLayoutNode.setProperty(CoreOptions.PADDING, ei);
+ elkinsets.set(ei);
+ }
+
+ parentElkNode.getChildren().add(childLayoutNode);
+ }
+ mapping.getGraphMap().put(childLayoutNode, nodeEditPart);
+
+ // store all the connections to process them later
+ addConnections(mapping, nodeEditPart);
+ return childLayoutNode;
+ }
+
+ /**
+ * Determines the insets for a parent figure, relative to the given child.
+ * Subclasses may override this if the generic insets calculation does not
+ * work.
+ *
+ * @param parent
+ * the figure of a parent edit part
+ * @param child
+ * the figure of a child edit part
+ * @return the insets to add to the relative coordinates of the child
+ */
+ protected Insets calcSpecificInsets(final IFigure parent, final IFigure child) {
+ Insets result = new Insets(0);
+ IFigure currentChild = child;
+ IFigure currentParent = child.getParent();
+ Point coordsToAdd = null;
+ boolean isRelative = false;
+ // follow the chain of parents in the figure hierarchy up to the given
+ // parent figure
+ while (currentChild != parent && currentParent != null) {
+ if (currentParent.isCoordinateSystem()) {
+ // the content of the current parent is relative to that
+ // figure's position
+ isRelative = true;
+ result.add(currentParent.getInsets());
+ if (coordsToAdd != null) {
+ // add the position of the previous parent with local
+ // coordinate system
+ result.left += coordsToAdd.x;
+ result.top += coordsToAdd.y;
+ }
+ coordsToAdd = currentParent.getBounds().getLocation();
+ } else if (currentParent == parent && coordsToAdd != null) {
+ // we found the top parent, and it does not have local
+ // coordinate system,
+ // so subtract the parent's coordinates from the previous
+ // parent's position
+ Point parentCoords = parent.getBounds().getLocation();
+ result.left += coordsToAdd.x - parentCoords.x;
+ result.top += coordsToAdd.y - parentCoords.y;
+ }
+ currentChild = currentParent;
+ currentParent = currentChild.getParent();
+ }
+ if (!isRelative) {
+ // there is no local coordinate system, so just subtract the
+ // coordinates
+ Rectangle parentBounds = parent.getBounds();
+ currentParent = child.getParent();
+ Rectangle containerBounds = currentParent.getBounds();
+ result.left = containerBounds.x - parentBounds.x;
+ result.top = containerBounds.y - parentBounds.y;
+ }
+ // In theory it would be better to get the bottom and right insets from
+ // the size.
+ // However, due to the inpredictability of Draw2D layout managers, this
+ // leads to
+ // bad results in many cases, so a fixed insets value is more stable.
+ result.right = result.left;
+ result.bottom = result.left;
+ return result;
+ }
+
+ /**
+ * Create a port while building the layout graph.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param portEditPart
+ * the port edit part
+ * @param nodeEditPart
+ * the parent node edit part
+ * @param elknode
+ * the corresponding layout node
+ * @return the created port
+ */
+ protected ElkPort createPort(final LayoutMapping mapping, final AbstractBorderItemEditPart portEditPart, final IGraphicalEditPart nodeEditPart, final ElkNode elknode) {
+
+ ElkPort port = ElkGraphUtil.createPort(elknode);
+
+ // set the port's layout, relative to the node position
+ Rectangle portBounds = getAbsoluteBounds(portEditPart.getFigure());
+ Rectangle nodeBounds = getAbsoluteBounds(nodeEditPart.getFigure());
+ double xpos = portBounds.x - nodeBounds.x;
+ double ypos = portBounds.y - nodeBounds.y;
+ port.setLocation(xpos, ypos);
+ port.setDimensions(portBounds.width, portBounds.height);
+
+ // We would set the modified flag to false here, but that doesn't exist
+ // anymore
+
+ mapping.getGraphMap().put(port, portEditPart);
+
+ // store all the connections to process them later
+ addConnections(mapping, portEditPart);
+
+ // set the port label
+ for (Object portChildObj : portEditPart.getChildren()) {
+ if (portChildObj instanceof IGraphicalEditPart) {
+ IFigure labelFigure = ((IGraphicalEditPart) portChildObj).getFigure();
+ String text = null;
+ if (labelFigure instanceof WrappingLabel) {
+ text = ((WrappingLabel) labelFigure).getText();
+ } else if (labelFigure instanceof Label) {
+ text = ((Label) labelFigure).getText();
+ }
+
+ if (text != null) {
+ ElkLabel portLabel = ElkGraphUtil.createLabel(port);
+ portLabel.setText(text);
+ mapping.getGraphMap().put(portLabel, portChildObj);
+
+ // set the port label's layout
+ Rectangle labelBounds = getAbsoluteBounds(labelFigure);
+ portLabel.setLocation(labelBounds.x - portBounds.x, labelBounds.y - portBounds.y);
+ try {
+ Dimension size = labelFigure.getPreferredSize();
+ portLabel.setDimensions(size.width, size.height);
+ } catch (SWTException exception) {
+ // ignore exception and leave the label size to (0, 0)
+ }
+
+ // We would set the modified flag to false here, but that
+ // doesn't exist anymore
+ }
+ }
+ }
+
+ return port;
+ }
+
+ /**
+ * Create a node label while building the layout graph.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param labelEditPart
+ * the label edit part
+ * @param nodeEditPart
+ * the parent node edit part
+ * @param elknode
+ * the layout node for which the label is set
+ * @return the created label
+ */
+ protected ElkLabel createNodeLabel(final LayoutMapping mapping, final IGraphicalEditPart labelEditPart, final IGraphicalEditPart nodeEditPart, final ElkNode elknode) {
+
+ IFigure labelFigure = labelEditPart.getFigure();
+ String text = null;
+ Font font = null;
+
+ if (labelFigure instanceof WrappingLabel) {
+ WrappingLabel wrappingLabel = (WrappingLabel) labelFigure;
+ text = wrappingLabel.getText();
+ font = wrappingLabel.getFont();
+ } else if (labelFigure instanceof Label) {
+ Label label = (Label) labelFigure;
+ text = label.getText();
+ font = label.getFont();
+ } else if (labelFigure instanceof SiriusWrapLabel) {
+ SiriusWrapLabel label = (SiriusWrapLabel) labelFigure;
+ text = label.getText();
+ font = label.getFont();
+ }
+
+ if (text != null) {
+ ElkLabel label = ElkGraphUtil.createLabel(elknode);
+ label.setText(text);
+ mapping.getGraphMap().put(label, labelEditPart);
+ Rectangle labelBounds = getAbsoluteBounds(labelFigure);
+ Rectangle nodeBounds = getAbsoluteBounds(nodeEditPart.getFigure());
+ label.setLocation(labelBounds.x - nodeBounds.x, labelBounds.y - nodeBounds.y);
+
+ try {
+ Dimension size = labelFigure.getPreferredSize();
+ label.setDimensions(size.width, size.height);
+ if (font != null && !font.isDisposed()) {
+ label.setProperty(CoreOptions.FONT_NAME, font.getFontData()[0].getName());
+ label.setProperty(CoreOptions.FONT_SIZE, font.getFontData()[0].getHeight());
+ }
+ } catch (SWTException exception) {
+ // ignore exception and leave the label size to (0, 0)
+ }
+
+ // We would set the modified flag to false here, but that doesn't
+ // exist anymore
+
+ return label;
+ }
+ return null;
+ }
+
+ /**
+ * Adds all target connections and connected connections to the list of
+ * connections that must be processed later.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param editPart
+ * an edit part
+ */
+ protected void addConnections(final LayoutMapping mapping, final IGraphicalEditPart editPart) {
+ for (Object targetConn : editPart.getTargetConnections()) {
+ if (targetConn instanceof ConnectionEditPart) {
+ ConnectionEditPart connectionEditPart = (ConnectionEditPart) targetConn;
+ if (editPartFilter.filter(connectionEditPart)) {
+ mapping.getProperty(CONNECTIONS).add(connectionEditPart);
+ addConnections(mapping, connectionEditPart);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates new edges and takes care of the labels for each connection
+ * identified in the {@code buildLayoutGraphRecursively} method.
+ *
+ * @param mapping
+ * the layout mapping
+ */
+ protected void processConnections(final LayoutMapping mapping) {
+ Map<EReference, ElkEdge> reference2EdgeMap = new HashMap<>();
+
+ for (ConnectionEditPart connection : mapping.getProperty(CONNECTIONS)) {
+ boolean isOppositeEdge = false;
+ EdgeLabelPlacement edgeLabelPlacement = EdgeLabelPlacement.UNDEFINED;
+ ElkEdge edge;
+
+ // Check whether the edge belongs to an Ecore reference, which may
+ // have opposites.
+ // This is required for the layout of Ecore diagrams, since the bend
+ // points of
+ // opposite references are kept synchronized by the editor.
+ EObject modelObject = connection.getNotationView().getElement();
+ if (modelObject instanceof EReference) {
+ EReference reference = (EReference) modelObject;
+ edge = reference2EdgeMap.get(reference.getEOpposite());
+ if (edge != null) {
+ edgeLabelPlacement = EdgeLabelPlacement.TAIL;
+ isOppositeEdge = true;
+ } else {
+ edge = ElkGraphUtil.createEdge(null);
+ reference2EdgeMap.put(reference, edge);
+ }
+ } else {
+ edge = ElkGraphUtil.createEdge(null);
+ }
+
+ BiMap<Object, ElkGraphElement> inverseGraphMap = mapping.getGraphMap().inverse();
+
+ // find a proper source node and source port
+ ElkGraphElement sourceElem;
+ EditPart sourceObj = connection.getSource();
+ if (sourceObj instanceof ConnectionEditPart) {
+ sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getSource());
+ if (sourceElem == null) {
+ sourceElem = inverseGraphMap.get(((ConnectionEditPart) sourceObj).getTarget());
+ }
+ } else {
+ sourceElem = inverseGraphMap.get(sourceObj);
+ }
+
+ ElkConnectableShape sourceShape = null;
+ ElkPort sourcePort = null;
+ ElkNode sourceNode = null;
+ if (sourceElem instanceof ElkNode) {
+ sourceNode = (ElkNode) sourceElem;
+ sourceShape = sourceNode;
+ } else if (sourceElem instanceof ElkPort) {
+ sourcePort = (ElkPort) sourceElem;
+ sourceNode = sourcePort.getParent();
+ sourceShape = sourcePort;
+ } else {
+ continue;
+ }
+
+ // find a proper target node and target port
+ ElkGraphElement targetElem;
+ EditPart targetObj = connection.getTarget();
+ if (targetObj instanceof ConnectionEditPart) {
+ targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getTarget());
+ if (targetElem == null) {
+ targetElem = inverseGraphMap.get(((ConnectionEditPart) targetObj).getSource());
+ }
+ } else {
+ targetElem = inverseGraphMap.get(targetObj);
+ }
+
+ ElkConnectableShape targetShape = null;
+ ElkNode targetNode = null;
+ ElkPort targetPort = null;
+ if (targetElem instanceof ElkNode) {
+ targetNode = (ElkNode) targetElem;
+ targetShape = targetNode;
+ } else if (targetElem instanceof ElkPort) {
+ targetPort = (ElkPort) targetElem;
+ targetNode = targetPort.getParent();
+ targetShape = targetPort;
+ } else {
+ continue;
+ }
+
+ // calculate offset for edge and label coordinates
+ ElkNode edgeContainment = ElkGraphUtil.findLowestCommonAncestor(sourceNode, targetNode);
+
+ KVector offset = new KVector();
+ ElkUtil.toAbsolute(offset, edgeContainment);
+
+ if (!isOppositeEdge) {
+ // set source and target
+ edge.getSources().add(sourceShape);
+ edge.getTargets().add(targetShape);
+
+ // now that source and target are set, put the edge into the
+ // graph
+ edgeContainment.getContainedEdges().add(edge);
+
+ mapping.getGraphMap().put(edge, connection);
+
+ // store the current coordinates of the edge
+ setEdgeLayout(edge, connection, offset);
+ }
+
+ // process edge labels
+ processEdgeLabels(mapping, connection, edge, edgeLabelPlacement, offset);
+ }
+ }
+
+ /**
+ * Stores the layout information of the given connection edit part into an
+ * edge layout.
+ *
+ * @param edge
+ * an edge layout
+ * @param connection
+ * a connection edit part
+ * @param offset
+ * offset to be subtracted from coordinates
+ */
+ protected void setEdgeLayout(final ElkEdge edge, final ConnectionEditPart connection, final KVector offset) {
+ Connection figure = connection.getConnectionFigure();
+ PointList pointList = figure.getPoints();
+
+ // our edge will have exactly one edge section
+ ElkEdgeSection edgeSection = ElkGraphUtil.createEdgeSection(edge);
+
+ // source point
+ Point firstPoint = pointList.getPoint(0);
+ edgeSection.setStartX(firstPoint.x - offset.x);
+ edgeSection.setStartY(firstPoint.y - offset.y);
+
+ // bend points
+ for (int i = 1; i < pointList.size() - 1; i++) {
+ Point point = pointList.getPoint(i);
+ ElkGraphUtil.createBendPoint(edgeSection, point.x - offset.x, point.y - offset.y);
+ }
+
+ // target point
+ Point lastPoint = pointList.getPoint(pointList.size() - 1);
+ edgeSection.setEndX(lastPoint.x - offset.x);
+ edgeSection.setEndY(lastPoint.y - offset.y);
+
+ // We would set the modified flag to false here, but that doesn't exist
+ // anymore
+ }
+
+ /**
+ * Process the labels of an edge.
+ *
+ * @param mapping
+ * the layout mapping
+ * @param connection
+ * the connection edit part
+ * @param edge
+ * the layout edge
+ * @param placement
+ * predefined placement for all labels, or {@code UNDEFINED} if
+ * the placement shall be derived from the edit part
+ * @param offset
+ * the offset for coordinates
+ */
+ protected void processEdgeLabels(final LayoutMapping mapping, final ConnectionEditPart connection, final ElkEdge edge, final EdgeLabelPlacement placement, final KVector offset) {
+ /*
+ * ars: source and target is exchanged when defining it in the gmfgen
+ * file. So if Emma sets a label to be placed as target on a connection,
+ * then the label will show up next to the source node in the diagram
+ * editor. So correct it here, very ugly.
+ */
+ for (Object obj : connection.getChildren()) {
+ if (obj instanceof LabelEditPart) {
+ LabelEditPart labelEditPart = (LabelEditPart) obj;
+ IFigure labelFigure = labelEditPart.getFigure();
+
+ // Check if the label is visible in the first place
+ if (labelFigure == null || !labelFigure.isVisible()) {
+ continue;
+ }
+
+ Rectangle labelBounds = getAbsoluteBounds(labelFigure);
+ String labelText = null;
+ Dimension iconBounds = null;
+
+ if (labelFigure instanceof WrappingLabel) {
+ WrappingLabel wrappingLabel = (WrappingLabel) labelFigure;
+ labelText = wrappingLabel.getText();
+ if (wrappingLabel.getIcon() != null) {
+ iconBounds = new Dimension();
+ iconBounds.width = wrappingLabel.getIcon().getBounds().width + wrappingLabel.getIconTextGap();
+ iconBounds.height = wrappingLabel.getIcon().getBounds().height;
+ // Add more characters to the text for layouters that
+ // need the text to
+ // determine the label size.
+ labelText = "O " + labelText;
+ }
+ } else if (labelFigure instanceof Label) {
+ Label label = (Label) labelFigure;
+ labelText = label.getText();
+ if (label.getIcon() != null) {
+ iconBounds = label.getIconBounds().getSize();
+ iconBounds.width += label.getIconTextGap();
+ // Add more characters to the text for layouters that
+ // need the text to
+ // determine the label size.
+ labelText = "O " + labelText;
+ }
+ } else if (labelFigure instanceof SiriusWrapLabel) {
+ SiriusWrapLabel label = (SiriusWrapLabel) labelFigure;
+ labelText = label.getText();
+ if (label.getIcon() != null) {
+ iconBounds = label.getIconBounds().getSize();
+ iconBounds.width += label.getIconTextGap();
+ // Add more characters to the text for layouters that
+ // need the text to
+ // determine the label size.
+ labelText = "O " + labelText;
+ }
+ }
+
+ if (labelText != null && labelText.length() > 0) {
+ ElkLabel label = ElkGraphUtil.createLabel(edge);
+ if (placement == EdgeLabelPlacement.UNDEFINED) {
+ switch (labelEditPart.getKeyPoint()) {
+ case ConnectionLocator.SOURCE:
+ label.setProperty(CoreOptions.EDGE_LABELS_PLACEMENT, EdgeLabelPlacement.HEAD);
+ break;
+ case ConnectionLocator.MIDDLE:
+ label.setProperty(CoreOptions.EDGE_LABELS_PLACEMENT, EdgeLabelPlacement.CENTER);
+ break;
+ case ConnectionLocator.TARGET:
+ label.setProperty(CoreOptions.EDGE_LABELS_PLACEMENT, EdgeLabelPlacement.TAIL);
+ break;
+ }
+ } else {
+ label.setProperty(CoreOptions.EDGE_LABELS_PLACEMENT, placement);
+ }
+ Font font = labelFigure.getFont();
+ if (font != null && !font.isDisposed()) {
+ label.setProperty(CoreOptions.FONT_NAME, font.getFontData()[0].getName());
+ label.setProperty(CoreOptions.FONT_SIZE, font.getFontData()[0].getHeight());
+ }
+ label.setLocation(labelBounds.x - offset.x, labelBounds.y - offset.y);
+ if (iconBounds != null) {
+ label.setWidth(labelBounds.width + iconBounds.width);
+ } else {
+ label.setWidth(labelBounds.width);
+ }
+ label.setHeight(labelBounds.height);
+
+ // We would set the modified flag to false here, but that
+ // doesn't exist anymore
+
+ label.setText(labelText);
+ mapping.getGraphMap().put(label, labelEditPart);
+ } else {
+ // add the label to the mapping anyway so it is reset to its
+ // reference location
+ ElkLabel label = ElkGraphUtil.createLabel(null);
+ mapping.getGraphMap().put(label, labelEditPart);
+ }
+ }
+ }
+ }
+
+ public void layout(LayoutMapping layoutMapping) {
+ BasicProgressMonitor basicProgressMonitor = new BasicProgressMonitor(0, ElkServicePlugin.getInstance().getPreferenceStore().getBoolean(PREF_EXEC_TIME_MEASUREMENT));
+ graphLayoutEngine.layout(layoutMapping.getLayoutGraph(), basicProgressMonitor.subTask(1));
+
+ }
+
+ @Override
+ public void applyLayout(LayoutMapping mapping, IPropertyHolder settings) {
+ // not used
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkSiriusLayoutSetup.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkSiriusLayoutSetup.java
new file mode 100644
index 0000000000..f39e050ec8
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/ElkSiriusLayoutSetup.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.Collection;
+
+import org.eclipse.elk.core.service.IDiagramLayoutConnector;
+import org.eclipse.elk.core.service.ILayoutSetup;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.util.Modules;
+
+/**
+ * Layout setup for the Sirius connector allowing to inject
+ * {@link ElkDiagramLayoutConnector} in the ELK layout engine.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.GmfLayoutSetup of commit
+ * e99248e44c71a5a02fe45bc4cd5150cd7f50c559.
+ *
+ * Adapted to use our custom connector.
+ *
+ * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a>
+ *
+ */
+public class ElkSiriusLayoutSetup implements ILayoutSetup {
+
+ @Override
+ public boolean supports(final Object object) {
+ if (object instanceof Collection) {
+ Collection<?> collection = (Collection<?>) object;
+ for (Object o : collection) {
+ if (o instanceof IGraphicalEditPart) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return object instanceof DiagramEditor || object instanceof IGraphicalEditPart;
+ }
+
+ @Override
+ public Injector createInjector(final Module defaultModule) {
+ return Guice.createInjector(Modules.override(defaultModule).with(new SiriusLayoutModule()));
+ }
+
+ /**
+ * Guice module for the Sirius connector.
+ */
+ public static class SiriusLayoutModule implements Module {
+
+ @Override
+ public void configure(final Binder binder) {
+ binder.bind(IDiagramLayoutConnector.class).to(ElkDiagramLayoutConnector.class);
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutCommand.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutCommand.java
new file mode 100644
index 0000000000..0732933103
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutCommand.java
@@ -0,0 +1,273 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.CommandResult;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.emf.commands.core.command.AbstractTransactionalCommand;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.IdentityAnchor;
+import org.eclipse.gmf.runtime.notation.NotationFactory;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.RelativeBendpoints;
+import org.eclipse.gmf.runtime.notation.Routing;
+import org.eclipse.gmf.runtime.notation.RoutingStyle;
+import org.eclipse.gmf.runtime.notation.Smoothness;
+import org.eclipse.gmf.runtime.notation.StringValueStyle;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.gmf.runtime.notation.datatype.RelativeBendpoint;
+
+/**
+ * Command used to apply layout.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.GmfLayoutCommand of commit
+ * e99248e44c71a5a02fe45bc4cd5150cd7f50c559.
+ *
+ * @author msp
+ * @kieler.design proposed by msp
+ * @kieler.rating proposed yellow by msp
+ * @see org.eclipse.gmf.runtime.diagram.ui.commands.SetBoundsCommand
+ * @see org.eclipse.gmf.runtime.diagram.ui.internal.commands.SetConnectionBendpointsCommand
+ * @see org.eclipse.gmf.runtime.diagram.core.commands.SetConnectionAnchorsCommand
+ */
+@SuppressWarnings("restriction")
+public class GmfLayoutCommand extends AbstractTransactionalCommand {
+
+ /** Style name for serialized junction points. */
+ public static final String JUNCTION_POINTS_STYLE_NAME = "junctionPoints";
+
+ /** layout data for node shapes. */
+ private static final class ShapeLayoutData {
+ private View view;
+
+ private Point location;
+
+ private Dimension size;
+
+ private ShapeLayoutData() {
+ }
+ }
+
+ /** layout data for edges. */
+ private static final class EdgeLayoutData {
+ private Edge edge;
+
+ private PointList bends;
+
+ private String junctionPoints;
+
+ private String sourceTerminal;
+
+ private String targetTerminal;
+
+ private EdgeLayoutData() {
+ }
+ }
+
+ /** adapter for the view of the base diagram. */
+ private IAdaptable diagramViewAdapter;
+
+ /** list of shape layouts to be applied to nodes. */
+ private List<ShapeLayoutData> shapeLayouts = new LinkedList<ShapeLayoutData>();
+
+ /** list of edge layouts to be applied to edges. */
+ private List<EdgeLayoutData> edgeLayouts = new LinkedList<EdgeLayoutData>();
+
+ /** indicates whether oblique routing style shall be enforced. */
+ private boolean obliqueRouting = false;
+
+ /**
+ * Creates a command to apply layout.
+ *
+ * @param domain
+ * the editing domain through which model changes are made
+ * @param label
+ * the command label
+ * @param adapter
+ * an adapter to the {@code View} of the base diagram
+ */
+ public GmfLayoutCommand(final TransactionalEditingDomain domain, final String label, final IAdaptable adapter) {
+ super(domain, label, null);
+ this.diagramViewAdapter = adapter;
+ }
+
+ /**
+ * Adds the given shape layout data to this command.
+ *
+ * @param view
+ * view from the GMF notation model
+ * @param location
+ * new location for the view, or {@code null} if the location
+ * shall not be changed
+ * @param size
+ * new size for the view, or {@code null} if the size shall not
+ * be changed
+ */
+ public void addShapeLayout(final View view, final Point location, final Dimension size) {
+ assert view != null;
+ ShapeLayoutData layout = new ShapeLayoutData();
+ layout.view = view;
+ layout.location = location;
+ layout.size = size;
+ shapeLayouts.add(layout);
+ }
+
+ /**
+ * Adds the given edge layout data to this command.
+ *
+ * @param edge
+ * edge from the GMF notation model
+ * @param bends
+ * list of bend points for the edge, or {@code null} if the bend
+ * points shall not be changed
+ * @param junctionPoints
+ * list of junction points to draw on the edge, encoded as
+ * string, or {@code null} if no junction points shall be drawn
+ * @param sourceTerminal
+ * new source terminal, encoded as string, or {@code null} if the
+ * source terminal shall not be changed
+ * @param targetTerminal
+ * new target terminal, encoded as string, or {@code null} if the
+ * target terminal shall not be changed
+ */
+ public void addEdgeLayout(final Edge edge, final PointList bends, final String sourceTerminal, final String targetTerminal, final String junctionPoints) {
+ assert edge != null;
+ EdgeLayoutData layout = new EdgeLayoutData();
+ layout.edge = edge;
+ layout.bends = bends;
+ layout.junctionPoints = junctionPoints;
+ layout.sourceTerminal = sourceTerminal;
+ layout.targetTerminal = targetTerminal;
+ edgeLayouts.add(layout);
+ }
+
+ /**
+ * Enforces all edges to be drawn with oblique routing style.
+ *
+ * @param theobliqueRouting
+ * whether oblique routing stlye shall be used or not
+ */
+ public void setObliqueRouting(final boolean theobliqueRouting) {
+ this.obliqueRouting = theobliqueRouting;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected CommandResult doExecuteWithResult(final IProgressMonitor monitor, final IAdaptable info) throws ExecutionException {
+ monitor.beginTask(getLabel(), 1);
+ // process shape layout data
+ for (ShapeLayoutData shapeLayout : shapeLayouts) {
+ // set new location of the element
+ if (shapeLayout.location != null) {
+ ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getLocation_X(), Integer.valueOf(shapeLayout.location.x));
+ ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getLocation_Y(), Integer.valueOf(shapeLayout.location.y));
+ }
+ // set new size of the element
+ if (shapeLayout.size != null) {
+ ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getSize_Width(), Integer.valueOf(shapeLayout.size.width));
+ ViewUtil.setStructuralFeatureValue(shapeLayout.view, NotationPackage.eINSTANCE.getSize_Height(), Integer.valueOf(shapeLayout.size.height));
+ }
+ }
+ shapeLayouts.clear();
+
+ // process edge layout data
+ for (EdgeLayoutData edgeLayout : edgeLayouts) {
+ // set new bend points of the edge
+ if (edgeLayout.bends != null) {
+ List<RelativeBendpoint> newBendpoints = new ArrayList<RelativeBendpoint>(edgeLayout.bends.size());
+ Point sourcePoint = edgeLayout.bends.getFirstPoint();
+ Point targetPoint = edgeLayout.bends.getLastPoint();
+ for (int i = 0; i < edgeLayout.bends.size(); i++) {
+ Point bend = edgeLayout.bends.getPoint(i);
+ newBendpoints.add(new RelativeBendpoint(bend.x - sourcePoint.x, bend.y - sourcePoint.y, bend.x - targetPoint.x, bend.y - targetPoint.y));
+ }
+ RelativeBendpoints points = (RelativeBendpoints) edgeLayout.edge.getBendpoints();
+ points.setPoints(newBendpoints);
+ }
+
+ // set new source anchor point of the edge
+ if (edgeLayout.sourceTerminal != null) {
+ IdentityAnchor anchor = (IdentityAnchor) edgeLayout.edge.getSourceAnchor();
+ if (anchor == null) {
+ anchor = NotationFactory.eINSTANCE.createIdentityAnchor();
+ edgeLayout.edge.setSourceAnchor(anchor);
+ }
+ anchor.setId(edgeLayout.sourceTerminal);
+ }
+ // set new target anchor point of the edge
+ if (edgeLayout.targetTerminal != null) {
+ IdentityAnchor anchor = (IdentityAnchor) edgeLayout.edge.getTargetAnchor();
+ if (anchor == null) {
+ anchor = NotationFactory.eINSTANCE.createIdentityAnchor();
+ edgeLayout.edge.setTargetAnchor(anchor);
+ }
+ anchor.setId(edgeLayout.targetTerminal);
+ }
+
+ // set junction points as style
+ StringValueStyle style = (StringValueStyle) edgeLayout.edge.getNamedStyle(NotationPackage.eINSTANCE.getStringValueStyle(), JUNCTION_POINTS_STYLE_NAME);
+ if (edgeLayout.junctionPoints == null) {
+ if (style != null) {
+ edgeLayout.edge.getStyles().remove(style);
+ }
+ } else {
+ if (style == null) {
+ style = NotationFactory.eINSTANCE.createStringValueStyle();
+ style.setName(JUNCTION_POINTS_STYLE_NAME);
+ edgeLayout.edge.getStyles().add(style);
+ }
+ style.setStringValue(edgeLayout.junctionPoints);
+ }
+
+ // set routing style to oblique
+ if (obliqueRouting) {
+ RoutingStyle routingStyle = (RoutingStyle) edgeLayout.edge.getStyle(NotationPackage.eINSTANCE.getRoutingStyle());
+ if (routingStyle != null) {
+ routingStyle.setRouting(Routing.MANUAL_LITERAL);
+ routingStyle.setSmoothness(Smoothness.NONE_LITERAL);
+ }
+ }
+ }
+ edgeLayouts.clear();
+
+ monitor.done();
+ return CommandResult.newOKCommandResult();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<?> getAffectedFiles() {
+ if (diagramViewAdapter != null) {
+ View view = diagramViewAdapter.getAdapter(View.class);
+ if (view != null) {
+ return getWorkspaceFiles(view);
+ }
+ }
+ return super.getAffectedFiles();
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutEditPolicy.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutEditPolicy.java
new file mode 100644
index 0000000000..0b584dd589
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/GmfLayoutEditPolicy.java
@@ -0,0 +1,603 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.draw2d.ConnectionAnchor;
+import org.eclipse.draw2d.ConnectionLocator;
+import org.eclipse.draw2d.IFigure;
+import org.eclipse.draw2d.geometry.Dimension;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.draw2d.geometry.PointList;
+import org.eclipse.draw2d.geometry.PrecisionPoint;
+import org.eclipse.draw2d.geometry.Rectangle;
+import org.eclipse.elk.core.math.ElkMath;
+import org.eclipse.elk.core.math.KVector;
+import org.eclipse.elk.core.math.KVectorChain;
+import org.eclipse.elk.core.options.CoreOptions;
+import org.eclipse.elk.core.options.EdgeLabelPlacement;
+import org.eclipse.elk.core.options.EdgeRouting;
+import org.eclipse.elk.core.util.ElkUtil;
+import org.eclipse.elk.core.util.Pair;
+import org.eclipse.elk.core.util.WrappedException;
+import org.eclipse.elk.graph.ElkConnectableShape;
+import org.eclipse.elk.graph.ElkEdge;
+import org.eclipse.elk.graph.ElkEdgeSection;
+import org.eclipse.elk.graph.ElkGraphElement;
+import org.eclipse.elk.graph.ElkLabel;
+import org.eclipse.elk.graph.ElkNode;
+import org.eclipse.elk.graph.ElkPort;
+import org.eclipse.elk.graph.ElkShape;
+import org.eclipse.elk.graph.util.ElkGraphUtil;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.gef.GraphicalEditPart;
+import org.eclipse.gef.Request;
+import org.eclipse.gef.commands.Command;
+import org.eclipse.gef.editpolicies.AbstractEditPolicy;
+import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
+import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.ConnectionEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.INodeEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.LabelEditPart;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.LineSeg;
+import org.eclipse.gmf.runtime.draw2d.ui.geometry.PointListUtilities;
+import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
+import org.eclipse.gmf.runtime.gef.ui.figures.SlidableAnchor;
+import org.eclipse.gmf.runtime.notation.Edge;
+import org.eclipse.gmf.runtime.notation.NotationPackage;
+import org.eclipse.gmf.runtime.notation.View;
+
+/**
+ * Edit policy used to apply layout. This edit policy creates a
+ * {@link GmfLayoutCommand} to directly manipulate layout data in the GMF
+ * notation model.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.GmfLayoutEditPolicy of commit
+ * 53a98c9c35bc38b6b7513e0e73fd9d688c34937f.
+ *
+ * @author msp
+ * @kieler.design proposed by msp
+ * @kieler.rating proposed yellow by msp
+ * @see org.eclipse.gmf.runtime.diagram.ui.editpolicies.XYLayoutEditPolicy
+ * @see org.eclipse.gmf.runtime.diagram.ui.editpolicies.ConnectionBendpointEditPolicy
+ * @see org.eclipse.gmf.runtime.diagram.ui.editpolicies.GraphicalNodeEditPolicy
+ */
+public class GmfLayoutEditPolicy extends AbstractEditPolicy {
+
+ /** map of edge layouts to existing point lists. */
+ private Map<ElkEdgeSection, PointList> pointListMap = new HashMap<>();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean understandsRequest(final Request req) {
+ return (ApplyLayoutRequest.REQ_APPLY_LAYOUT.equals(req.getType()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Command getCommand(final Request request) {
+ if (ApplyLayoutRequest.REQ_APPLY_LAYOUT.equals(request.getType())) {
+ if (request instanceof ApplyLayoutRequest) {
+ ApplyLayoutRequest layoutRequest = (ApplyLayoutRequest) request;
+ IGraphicalEditPart hostEditPart = (IGraphicalEditPart) getHost();
+ GmfLayoutCommand command = new GmfLayoutCommand(hostEditPart.getEditingDomain(), "Automatic Layout", new EObjectAdapter((View) hostEditPart.getModel()));
+ double scale = layoutRequest.getScale();
+
+ // retrieve layout data from the request and compute layout data
+ // for the command
+ for (Pair<ElkGraphElement, GraphicalEditPart> layoutPair : layoutRequest.getElements()) {
+ if (layoutPair.getFirst() instanceof ElkNode) {
+ addShapeLayout(command, (ElkShape) layoutPair.getFirst(), layoutPair.getSecond(), scale);
+ } else if (layoutPair.getFirst() instanceof ElkPort) {
+ addShapeLayout(command, (ElkPort) layoutPair.getFirst(), layoutPair.getSecond(), scale);
+ } else if (layoutPair.getFirst() instanceof ElkEdge) {
+ addEdgeLayout(command, (ElkEdge) layoutPair.getFirst(), (ConnectionEditPart) layoutPair.getSecond(), scale);
+ } else if (layoutPair.getFirst() instanceof ElkLabel) {
+ addLabelLayout(command, (ElkLabel) layoutPair.getFirst(), layoutPair.getSecond(), scale);
+ }
+ }
+
+ // TODO Make this configurable?
+ command.setObliqueRouting(true);
+
+ pointListMap.clear();
+ return new ICommandProxy(command);
+ } else {
+ return null;
+ }
+ } else {
+ return super.getCommand(request);
+ }
+ }
+
+ /**
+ * Adds a shape layout to the given command.
+ *
+ * @param command
+ * command to which a shape layout shall be added
+ * @param elkShape
+ * graph element with layout data
+ * @param editPart
+ * edit part to which layout is applied
+ * @param scale
+ * scale factor for coordinates
+ */
+ private void addShapeLayout(final GmfLayoutCommand command, final ElkShape elkShape, final GraphicalEditPart editPart, final double scale) {
+
+ View view = (View) editPart.getModel();
+
+ // check whether the location has changed
+ Point newLocation = new Point((int) (elkShape.getX() * scale), (int) (elkShape.getY() * scale));
+ Object oldx = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getLocation_X());
+ Object oldy = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getLocation_Y());
+
+ if (oldx != null && oldy != null && newLocation.x == (Integer) oldx && newLocation.y == (Integer) oldy) {
+ newLocation = null;
+ }
+
+ // check whether the size has changed
+ Dimension newSize = new Dimension((int) (elkShape.getWidth() * scale), (int) (elkShape.getHeight() * scale));
+ Object oldWidth = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getSize_Width());
+ Object oldHeight = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getSize_Height());
+
+ if (oldWidth != null && oldHeight != null && newSize.width == (Integer) oldWidth && newSize.height == (Integer) oldHeight) {
+
+ newSize = null;
+ }
+
+ if (newLocation != null || newSize != null) {
+ command.addShapeLayout(view, newLocation, newSize);
+ }
+ }
+
+ /**
+ * Adds an edge layout to the given command.
+ *
+ * @param command
+ * command to which an edge layout shall be added
+ * @param elkEdge
+ * edge with layout data
+ * @param connectionEditPart
+ * edit part to which layout is applied
+ * @param scale
+ * scale factor for coordinates
+ */
+ private void addEdgeLayout(final GmfLayoutCommand command, final ElkEdge elkEdge, final ConnectionEditPart connectionEditPart, final double scale) {
+
+ if (connectionEditPart.getSource() != null && connectionEditPart.getTarget() != null) {
+ // create source terminal identifier
+ INodeEditPart sourceEditPart = (INodeEditPart) connectionEditPart.getSource();
+ ConnectionAnchor sourceAnchor;
+ if (sourceEditPart instanceof ConnectionEditPart) {
+ // if the edge source is a connection, don't consider the source
+ // point
+ sourceAnchor = new SlidableAnchor(sourceEditPart.getFigure());
+ } else {
+ KVector sourceRel = getRelativeSourcePoint(elkEdge);
+ sourceAnchor = new SlidableAnchor(sourceEditPart.getFigure(), new PrecisionPoint(sourceRel.x, sourceRel.y));
+ }
+ String sourceTerminal = sourceEditPart.mapConnectionAnchorToTerminal(sourceAnchor);
+
+ // create target terminal identifier
+ INodeEditPart targetEditPart = (INodeEditPart) connectionEditPart.getTarget();
+ ConnectionAnchor targetAnchor;
+ if (targetEditPart instanceof ConnectionEditPart) {
+ // if the edge target is a connection, don't consider the target
+ // point
+ targetAnchor = new SlidableAnchor(targetEditPart.getFigure());
+ } else {
+ KVector targetRel = getRelativeTargetPoint(elkEdge);
+ targetAnchor = new SlidableAnchor(targetEditPart.getFigure(), new PrecisionPoint(targetRel.x, targetRel.y));
+ }
+ String targetTerminal = targetEditPart.mapConnectionAnchorToTerminal(targetAnchor);
+
+ PointList bendPoints = getBendPoints(elkEdge, connectionEditPart.getFigure(), scale);
+
+ // check whether the connection is a note attachment to an edge,
+ // then remove bend points
+ if (sourceEditPart instanceof ConnectionEditPart || targetEditPart instanceof ConnectionEditPart) {
+ while (bendPoints.size() > 2) {
+ bendPoints.removePoint(1);
+ }
+ }
+
+ // retrieve junction points and transform them to absolute
+ // coordinates
+ KVectorChain junctionPoints = elkEdge.getProperty(CoreOptions.JUNCTION_POINTS);
+ String serializedJP = null;
+ if (junctionPoints != null) {
+ for (KVector point : junctionPoints) {
+ ElkUtil.toAbsolute(point, elkEdge.getContainingNode());
+ }
+ serializedJP = junctionPoints.toString();
+ }
+
+ command.addEdgeLayout((Edge) connectionEditPart.getModel(), bendPoints, sourceTerminal, targetTerminal, serializedJP);
+ }
+ }
+
+ /**
+ * Create a vector that contains the relative position of the source point
+ * to the corresponding source node or port.
+ *
+ * @param edge
+ * an edge
+ * @return the relative source point
+ */
+ private KVector getRelativeSourcePoint(final ElkEdge edge) {
+ // The edge should have exactly one source shape
+ ElkConnectableShape sourceShape = edge.getSources().get(0);
+
+ // The edge should have one edge section after layout
+ ElkEdgeSection edgeSection = edge.getSections().get(0);
+ KVector sourcePoint = new KVector(edgeSection.getStartX(), edgeSection.getStartY());
+
+ // We will now make the source point absolute, and then relative to the
+ // source node
+ ElkUtil.toAbsolute(sourcePoint, edge.getContainingNode());
+ ElkUtil.toRelative(sourcePoint, ElkGraphUtil.connectableShapeToNode(sourceShape));
+
+ // The end result will be coordinates between 0 and 1, with 0 being at
+ // the left / top or the source shape and
+ // 1 being at the right / bottom
+ if (sourceShape instanceof ElkPort) {
+ ElkPort sourcePort = (ElkPort) sourceShape;
+
+ // calculate the relative position to the port size
+ if (sourcePort.getWidth() <= 0) {
+ sourcePoint.x = 0;
+ } else {
+ sourcePoint.x = (sourcePoint.x - sourcePort.getX()) / sourcePort.getWidth();
+ }
+
+ if (sourcePort.getHeight() <= 0) {
+ sourcePoint.y = 0;
+ } else {
+ sourcePoint.y = (sourcePoint.y - sourcePort.getY()) / sourcePort.getHeight();
+ }
+ } else {
+ // calculate the relative position to the node size
+ if (sourceShape.getWidth() <= 0) {
+ sourcePoint.x = 0;
+ } else {
+ sourcePoint.x /= sourceShape.getWidth();
+ }
+ if (sourceShape.getHeight() <= 0) {
+ sourcePoint.y = 0;
+ } else {
+ sourcePoint.y /= sourceShape.getHeight();
+ }
+ }
+
+ // check the bound of the relative position
+ return sourcePoint.bound(0, 0, 1, 1);
+ }
+
+ /**
+ * Create a vector that contains the relative position of the target point
+ * to the corresponding target node or port.
+ *
+ * @param edge
+ * an edge
+ * @return the relative target point
+ */
+ private KVector getRelativeTargetPoint(final ElkEdge edge) {
+ // The edge should have exactly one source shape
+ ElkConnectableShape targetShape = edge.getTargets().get(0);
+
+ // The edge should have one edge section after layout
+ ElkEdgeSection edgeSection = edge.getSections().get(0);
+ KVector targetPoint = new KVector(edgeSection.getEndX(), edgeSection.getEndY());
+
+ // We will now make the source point absolute, and then relative to the
+ // source node
+ ElkUtil.toAbsolute(targetPoint, edge.getContainingNode());
+ ElkUtil.toRelative(targetPoint, ElkGraphUtil.connectableShapeToNode(targetShape));
+
+ // The end result will be coordinates between 0 and 1, with 0 being at
+ // the left / top or the source shape and
+ // 1 being at the right / bottom
+ if (targetShape instanceof ElkPort) {
+ ElkPort targetPort = (ElkPort) targetShape;
+
+ // calculate the relative position to the port size
+ if (targetPort.getWidth() <= 0) {
+ targetPoint.x = 0;
+ } else {
+ targetPoint.x = (targetPoint.x - targetPort.getX()) / targetPort.getWidth();
+ }
+
+ if (targetPort.getHeight() <= 0) {
+ targetPoint.y = 0;
+ } else {
+ targetPoint.y = (targetPoint.y - targetPort.getY()) / targetPort.getHeight();
+ }
+ } else {
+ // calculate the relative position to the node size
+ if (targetShape.getWidth() <= 0) {
+ targetPoint.x = 0;
+ } else {
+ targetPoint.x /= targetShape.getWidth();
+ }
+ if (targetShape.getHeight() <= 0) {
+ targetPoint.y = 0;
+ } else {
+ targetPoint.y /= targetShape.getHeight();
+ }
+ }
+
+ // check the bound of the relative position
+ return targetPoint.bound(0, 0, 1, 1);
+ }
+
+ /** see LabelViewConstants.TARGET_LOCATION. */
+ private static final int SOURCE_LOCATION = 85;
+
+ /** see LabelViewConstants.MIDDLE_LOCATION. */
+ private static final int MIDDLE_LOCATION = 50;
+
+ /** see LabelViewConstants.SOURCE_LOCATION. */
+ private static final int TARGET_LOCATION = 15;
+
+ /**
+ * Adds an edge label layout to the given command.
+ *
+ * @param command
+ * command to which the edge label layout shall be added
+ * @param klabel
+ * label with layout data
+ * @param labelEditPart
+ * edit part to which layout is applied
+ * @param scale
+ * scale factor for coordinates
+ */
+ private void addLabelLayout(final GmfLayoutCommand command, final ElkLabel klabel, final GraphicalEditPart labelEditPart, final double scale) {
+
+ ElkGraphElement parent = klabel.getParent();
+
+ // node and port labels are processed separately
+ if (parent instanceof ElkNode || parent instanceof ElkPort) {
+ View view = (View) labelEditPart.getModel();
+ int xpos = (int) (klabel.getX() * scale);
+ int ypos = (int) (klabel.getY() * scale);
+ Object oldx = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getLocation_X());
+ Object oldy = ViewUtil.getStructuralFeatureValue(view, NotationPackage.eINSTANCE.getLocation_Y());
+
+ if (oldx == null || oldy == null || xpos != (Integer) oldx || ypos != (Integer) oldy) {
+ command.addShapeLayout(view, new Point(xpos, ypos), null);
+ }
+ return;
+ } else if (parent instanceof ElkEdge) {
+ // calculate direct new location of the label
+ Rectangle targetBounds = new Rectangle(labelEditPart.getFigure().getBounds());
+ targetBounds.x = (int) (klabel.getX() * scale);
+ targetBounds.y = (int) (klabel.getY() * scale);
+
+ ConnectionEditPart connectionEditPart = (ConnectionEditPart) labelEditPart.getParent();
+ PointList bendPoints = getBendPoints((ElkEdge) parent, connectionEditPart.getFigure(), scale);
+ EObject modelElement = connectionEditPart.getNotationView().getElement();
+ EdgeLabelPlacement labelPlacement = klabel.getProperty(CoreOptions.EDGE_LABELS_PLACEMENT);
+
+ // for labels of the opposite reference of an ecore reference,
+ // the list of bend points must be reversed
+ if (modelElement instanceof EReference && labelPlacement == EdgeLabelPlacement.TAIL) {
+ bendPoints = bendPoints.getCopy();
+ bendPoints.reverse();
+ }
+
+ // get the referencePoint for the label
+ int fromEnd, keyPoint = ConnectionLocator.MIDDLE;
+ if (labelEditPart instanceof LabelEditPart) {
+ keyPoint = ((LabelEditPart) labelEditPart).getKeyPoint();
+ }
+ switch (keyPoint) {
+ case ConnectionLocator.SOURCE:
+ fromEnd = SOURCE_LOCATION;
+ break;
+ case ConnectionLocator.TARGET:
+ fromEnd = TARGET_LOCATION;
+ break;
+ default:
+ fromEnd = MIDDLE_LOCATION;
+ break;
+ }
+ Point refPoint = PointListUtilities.calculatePointRelativeToLine(bendPoints, 0, fromEnd, true);
+
+ // get the new relative location
+ Point normalPoint = offsetFromRelativeCoordinate(targetBounds, bendPoints, refPoint);
+ if (normalPoint != null) {
+ command.addShapeLayout((View) labelEditPart.getModel(), normalPoint, null);
+ }
+ }
+ }
+
+ /**
+ * Transform the bend points of the given edge layout into a point list,
+ * reusing existing ones if possible. The source and target points of the
+ * edge layout are included in the point list.
+ *
+ * @param edge
+ * the edge for which to fetch bend points
+ * @param isSplineEdge
+ * indicates whether the connection supports splines
+ * @return point list with the bend points of the edge layout
+ * @param scale
+ * scale factor for coordinates
+ */
+ private PointList getBendPoints(final ElkEdge edge, final IFigure edgeFigure, final double scale) {
+ // This assumes that the edge has at least one edge section, which by
+ // this point it should
+ ElkEdgeSection edgeSection = edge.getSections().get(0);
+ PointList pointList = pointListMap.get(edgeSection);
+ if (pointList == null) {
+ KVectorChain bendPoints = ElkUtil.createVectorChain(edgeSection);
+
+ // for connections that support splines the control points are
+ // passed without change
+ boolean approx = handleSplineConnection(edgeFigure, edge.getProperty(CoreOptions.EDGE_ROUTING));
+
+ // in other cases an approximation is used
+ if (approx && bendPoints.size() >= 1) {
+ bendPoints = ElkMath.approximateBezierSpline(bendPoints);
+ }
+
+ bendPoints.scale(scale);
+ pointList = new PointList(bendPoints.size() + 2);
+ for (KVector bendPoint : bendPoints) {
+ pointList.addPoint((int) bendPoint.x, (int) bendPoint.y);
+ }
+
+ pointListMap.put(edgeSection, pointList);
+ }
+ return pointList;
+ }
+
+ /**
+ * class name of the ELK SplineConnection.
+ *
+ * TODO: This class doesn't exist anymore...
+ */
+ private static final String SPLINE_CONNECTION = "org.eclipse.elk.core.model.gmf.figures.SplineConnection";
+
+ /**
+ * Handle the ELK SplineConnection class without a direct reference to it.
+ * Reflection is used to avoid a dependency to its containing plugin.
+ *
+ * @param edgeFigure
+ * the edge figure instance
+ * @param edgeRouting
+ * the edge routing returned by the layout algorithm
+ * @return {@code true} if an approximation should be used to represent the
+ * spline
+ */
+ private static boolean handleSplineConnection(final IFigure edgeFigure, final EdgeRouting edgeRouting) {
+ boolean isSC;
+ Class<?> clazz = edgeFigure.getClass();
+ do {
+ String canonicalName = clazz.getCanonicalName();
+ // in some cases, eg anonymous classes, the canonical name may be
+ // null
+ isSC = canonicalName != null && canonicalName.equals(SPLINE_CONNECTION);
+ clazz = clazz.getSuperclass();
+ } while (!isSC && clazz != null);
+ if (isSC) {
+ clazz = edgeFigure.getClass();
+ try {
+ if (edgeRouting == EdgeRouting.SPLINES) {
+ // SplineConnection.SPLINE_CUBIC
+ clazz.getMethod("setSplineMode", int.class).invoke(edgeFigure, 1);
+ } else {
+ // SplineConnection.SPLINE_OFF
+ clazz.getMethod("setSplineMode", int.class).invoke(edgeFigure, 0);
+ }
+ return false;
+ } catch (Exception exception) {
+ throw new WrappedException(exception);
+ }
+ }
+ // no spline connection class, but spline representation is requested
+ return edgeRouting == EdgeRouting.SPLINES;
+ }
+
+ /**
+ * <!-- CHECKSTYLEOFF LineLength --> Calculates the label offset from the
+ * reference point given the label bounds and a points list. This code has
+ * been copied and adapted from
+ * {@link org.eclipse.gmf.runtime.diagram.ui.internal.figures.LabelHelper#offsetFromRelativeCoordinate(IFigure, Rectangle, PointList, Point)}
+ * ,
+ * {@link org.eclipse.gmf.runtime.diagram.ui.internal.figures.LabelHelper#normalizeRelativePointToPointOnLine(PointList, Point, Point)}
+ * , and
+ * {@link org.eclipse.gmf.runtime.diagram.ui.internal.figures.LabelHelper#getOrthogonalDistances(LineSeg, Point, Point)}
+ * .
+ *
+ * <!-- CHECKSTYLEON LineLength -->
+ *
+ * @param bounds
+ * the {@code Rectangle} that is the bounding box of the label
+ * @param points
+ * the {@code PointList} that the label offset is relative to
+ * @param therefPoint
+ * the {@code Point} that is the reference point that the offset
+ * is based on, or {@code null}
+ * @return a {@code Point} which represents a value offset from the
+ * {@code refPoint} point oriented based on the nearest line
+ * segment, or {@code null} if no such point can be determined
+ */
+ @SuppressWarnings("restriction")
+ public static Point offsetFromRelativeCoordinate(final Rectangle bounds, final PointList points, final Point therefPoint) {
+ Point refPoint = therefPoint;
+ if (refPoint == null) {
+ refPoint = points.getFirstPoint();
+ }
+ // compensate for the fact that we are using the figure center
+ bounds.translate(bounds.width / 2, bounds.height / 2);
+ Point offset = new Point(bounds.x - refPoint.x, bounds.y - refPoint.y);
+ // calculate slope of line
+ if (points.size() == 1) {
+ // this is a node...
+ return offset;
+ } else if (points.size() >= 2) {
+ // this is an edge...
+ int segIndex = PointListUtilities.findNearestLineSegIndexOfPoint(points, refPoint);
+ @SuppressWarnings("rawtypes")
+ List segmentsList = PointListUtilities.getLineSegments(points);
+ if (segIndex <= 0) {
+ segIndex = 0;
+ } else if (segIndex > segmentsList.size()) {
+ segIndex = segmentsList.size() - 1;
+ } else {
+ segIndex--;
+ }
+ LineSeg segment = (LineSeg) segmentsList.get(segIndex);
+ Point normalOffset = null;
+ if (segment.isHorizontal()) {
+ if (segment.getOrigin().x > segment.getTerminus().x) {
+ normalOffset = offset.getNegated();
+ return normalOffset;
+ } else {
+ normalOffset = offset;
+ return normalOffset;
+ }
+ } else if (segment.isVertical()) {
+ if (segment.getOrigin().y < segment.getTerminus().y) {
+ normalOffset = offset.scale(-1, 1).transpose();
+ return normalOffset;
+ } else {
+ normalOffset = offset.scale(1, -1).transpose();
+ return normalOffset;
+ }
+ } else {
+ Point offsetRefPoint = refPoint.getTranslated(offset);
+ LineSeg parallelSeg = segment.getParallelLineSegThroughPoint(offsetRefPoint);
+ Point p1 = parallelSeg.perpIntersect(refPoint.x, refPoint.y);
+ double dx = p1.getDistance(offsetRefPoint) * ((p1.x > offsetRefPoint.x) ? -1 : 1);
+ double dy = p1.getDistance(refPoint) * ((p1.y < refPoint.y) ? -1 : 1);
+ Point orth = new PrecisionPoint(dx, dy);
+ // reflection in the y axis
+ if (segment.getOrigin().x > segment.getTerminus().x) {
+ orth = orth.scale(-1, -1);
+ }
+ return orth;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/IEditPartFilter.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/IEditPartFilter.java
new file mode 100644
index 0000000000..f037d6bbfa
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/IEditPartFilter.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import org.eclipse.gef.EditPart;
+
+import com.google.inject.ImplementedBy;
+
+/**
+ * Interface for edit part filters. Use this to exclude certain diagram parts
+ * from automatic layout.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.IEditPartFilter of commit
+ * e99248e44c71a5a02fe45bc4cd5150cd7f50c559.
+ */
+@ImplementedBy(IEditPartFilter.DefaultImpl.class)
+public interface IEditPartFilter {
+
+ /**
+ * Whether to accept the given edit part and include it in the layout graph.
+ */
+ boolean filter(EditPart editPart);
+
+ /**
+ * This implementation includes all edit parts (returns always
+ * {@code true}).
+ */
+ class DefaultImpl implements IEditPartFilter {
+
+ @Override
+ public boolean filter(final EditPart editPart) {
+ return true;
+ }
+
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/LayoutEditPolicyProvider.java b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/LayoutEditPolicyProvider.java
new file mode 100644
index 0000000000..858aae5245
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.elk/src/org/eclipse/sirius/diagram/elk/LayoutEditPolicyProvider.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 Kiel University and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Kiel University - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.elk;
+
+import org.eclipse.gef.EditPart;
+import org.eclipse.gmf.runtime.common.core.service.AbstractProvider;
+import org.eclipse.gmf.runtime.common.core.service.IOperation;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.editpolicy.CreateEditPoliciesOperation;
+import org.eclipse.gmf.runtime.diagram.ui.services.editpolicy.IEditPolicyProvider;
+
+/**
+ * The edit policy provider for the <i>apply layout</i> edit policy.
+ *
+ * Copied from org.eclipse.elk.conn.gmf.LayoutEditPolicyProvider of commit
+ * e99248e44c71a5a02fe45bc4cd5150cd7f50c559.
+ *
+ * @author haf
+ * @kieler.design proposed by msp
+ * @kieler.rating proposed yellow by msp
+ */
+public class LayoutEditPolicyProvider extends AbstractProvider implements IEditPolicyProvider {
+
+ /** the key used to install an <i>apply layout</i> edit policy. */
+ public static final String APPLY_LAYOUT_ROLE = "ApplyLayoutEditPolicy";
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void createEditPolicies(final EditPart editPart) {
+ if (editPart instanceof DiagramEditPart) {
+ editPart.installEditPolicy(APPLY_LAYOUT_ROLE, new GmfLayoutEditPolicy());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean provides(final IOperation operation) {
+ return operation instanceof CreateEditPoliciesOperation;
+ }
+
+}
diff --git a/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
index dac96dad84..4ad069c190 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.sirius.diagram.ui/META-INF/MANIFEST.MF
@@ -87,6 +87,7 @@ Export-Package: org.eclipse.sirius.diagram.description.concern.provider;version=
org.eclipse.sirius.diagram.ui.internal.edit.parts.locator;version="3.1.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.internal.edit.parts.refresh;version="3.1.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.internal.edit.policies;version="3.0.0";x-internal:=true,
+ org.eclipse.sirius.diagram.ui.internal.layout;version="6.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.internal.operation;version="3.0.0";x-internal:=true,
org.eclipse.sirius.diagram.ui.internal.parsers;version="2.0.4";x-internal:=true,
org.eclipse.sirius.diagram.ui.internal.preferences;version="3.0.0";x-internal:=true,
diff --git a/plugins/org.eclipse.sirius.diagram.ui/plugin.xml b/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
index b40bb01423..1bd4ab6af8 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
+++ b/plugins/org.eclipse.sirius.diagram.ui/plugin.xml
@@ -1988,5 +1988,11 @@
</Priority>
</statusLineContributionItemProvider>
</extension>
-
+ <extension
+ point="org.eclipse.sirius.diagram.ui.layoutProvider">
+ <layoutProvider
+ priority="highest"
+ providerClass="org.eclipse.sirius.diagram.ui.internal.layout.GenericLayoutProvider">
+ </layoutProvider>
+ </extension>
</plugin>
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src-gen/org/eclipse/sirius/diagram/ui/provider/DiagramUIPlugin.java b/plugins/org.eclipse.sirius.diagram.ui/src-gen/org/eclipse/sirius/diagram/ui/provider/DiagramUIPlugin.java
index 18123d18a5..d6e4e8a2ff 100644
--- a/plugins/org.eclipse.sirius.diagram.ui/src-gen/org/eclipse/sirius/diagram/ui/provider/DiagramUIPlugin.java
+++ b/plugins/org.eclipse.sirius.diagram.ui/src-gen/org/eclipse/sirius/diagram/ui/provider/DiagramUIPlugin.java
@@ -13,10 +13,12 @@ package org.eclipse.sirius.diagram.ui.provider;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
@@ -49,6 +51,7 @@ import org.eclipse.sirius.diagram.ui.business.internal.image.ImageSelectorDescri
import org.eclipse.sirius.diagram.ui.business.internal.image.refresh.WorkspaceImageFigureRefresher;
import org.eclipse.sirius.diagram.ui.internal.refresh.listeners.WorkspaceFileResourceChangeListener;
import org.eclipse.sirius.diagram.ui.tools.api.decoration.SiriusDecorationProviderRegistry;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider;
import org.eclipse.sirius.diagram.ui.tools.api.preferences.SiriusDiagramUiPreferencesKeys;
import org.eclipse.sirius.diagram.ui.tools.internal.decoration.DescribedDecorationDescriptorProvider;
import org.eclipse.sirius.diagram.ui.tools.internal.decoration.EditModeDecorationDescriptorProvider;
@@ -152,6 +155,11 @@ public final class DiagramUIPlugin extends EMFPlugin {
private DynamicDiagramUIPreferences dynamicPreferences;
/**
+ * A registry containing all layout providers that can be specified directly in the VSM.
+ */
+ private Map<String, Supplier<DefaultLayoutProvider>> layoutProviderRegistry;
+
+ /**
* Creates an instance. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
@@ -160,11 +168,42 @@ public final class DiagramUIPlugin extends EMFPlugin {
super();
// Remember the static instance.
- //
DiagramUIPlugin.plugin = this;
}
/**
+ * Add a new layout provider to the registry.
+ *
+ * @param providerId
+ * the id of the layout provider to add in the registry.
+ * @param layoutSupplier
+ * the layout provider that should be used and that should extend {@link DefaultLayoutProvider}.
+ */
+ public void addLayoutProvider(String providerId, Supplier<DefaultLayoutProvider> layoutSupplier) {
+ layoutProviderRegistry.put(providerId, layoutSupplier);
+ }
+
+ /**
+ * Remove the layout provider identified by the given id from the registry.
+ *
+ * @param layoutProviderId
+ * the id of the layout provider to remove from the registry.
+ * @return the layout provider removed if such element exists.
+ */
+ public Supplier<DefaultLayoutProvider> removeLayoutProvider(String layoutProviderId) {
+ return layoutProviderRegistry.remove(layoutProviderId);
+ }
+
+ /**
+ * Returns the unmodifiable registry containing all layout providers that can be specified directly in the VSM.
+ *
+ * @return an unmodifiable map of layout providers suppliers associated to their ids.
+ */
+ public Map<String, Supplier<DefaultLayoutProvider>> getLayoutProviderRegistry() {
+ return Collections.unmodifiableMap(layoutProviderRegistry);
+ }
+
+ /**
* @not-generated create the image registry
*/
@Override
@@ -189,6 +228,8 @@ public final class DiagramUIPlugin extends EMFPlugin {
layoutDataManagerRegistryListener = new LayoutDataManagerRegistryListener();
layoutDataManagerRegistryListener.init();
+ layoutProviderRegistry = new HashMap<>();
+
registerCoreDecorationProviders();
}
@@ -220,7 +261,7 @@ public final class DiagramUIPlugin extends EMFPlugin {
// can occur when using CDO (if the view is
// closed when transactions have been closed)
}
-
+ layoutProviderRegistry = null;
formatDataManagerRegistryListener.dispose();
formatDataManagerRegistryListener = null;
diff --git a/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/internal/layout/GenericLayoutProvider.java b/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/internal/layout/GenericLayoutProvider.java
new file mode 100644
index 0000000000..b2e272ca02
--- /dev/null
+++ b/plugins/org.eclipse.sirius.diagram.ui/src/org/eclipse/sirius/diagram/ui/internal/layout/GenericLayoutProvider.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Obeo
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.sirius.diagram.ui.internal.layout;
+
+import java.util.function.Supplier;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
+import org.eclipse.gmf.runtime.diagram.ui.services.layout.AbstractLayoutEditPartProvider;
+import org.eclipse.gmf.runtime.notation.Diagram;
+import org.eclipse.gmf.runtime.notation.View;
+import org.eclipse.sirius.diagram.DDiagram;
+import org.eclipse.sirius.diagram.description.DiagramDescription;
+import org.eclipse.sirius.diagram.description.GenericLayout;
+import org.eclipse.sirius.diagram.description.Layout;
+import org.eclipse.sirius.diagram.ui.provider.DiagramUIPlugin;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.DefaultLayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.api.layout.provider.LayoutProvider;
+import org.eclipse.sirius.diagram.ui.tools.internal.layout.provider.ArrangeSelectionLayoutProvider;
+
+/**
+ * A generic layout provider that will allow to use a layout algorithm specified in a Sirius VSM.
+ *
+ * @author <a href="mailto:pierre.guilet@obeo.fr">Pierre Guilet</a>
+ *
+ */
+public class GenericLayoutProvider implements LayoutProvider {
+
+ @Override
+ public AbstractLayoutEditPartProvider getLayoutNodeProvider(final IGraphicalEditPart container) {
+ Supplier<DefaultLayoutProvider> layoutProvider = getGenericLayoutProvider(container);
+ if (layoutProvider != null) {
+
+ return new ArrangeSelectionLayoutProvider(layoutProvider.get());
+ }
+ return null;
+ }
+
+ @Override
+ public boolean provides(final IGraphicalEditPart container) {
+ return getGenericLayoutProvider(container) != null;
+ }
+
+ @Override
+ public boolean isDiagramLayoutProvider() {
+ return true;
+ }
+
+ /**
+ * Returns the generic layout provider associated to the description of the {@link DDiagram} related to the given
+ * part.
+ *
+ * @param container
+ * @return the generic layout provider associated to the description of the {@link DDiagram} related to the given
+ * part. Null if no such element exists.
+ */
+ private Supplier<DefaultLayoutProvider> getGenericLayoutProvider(final IGraphicalEditPart container) {
+ final View view = container.getNotationView();
+ final EObject modelElement = view.getElement();
+ if (view instanceof Diagram && modelElement instanceof DDiagram) {
+ final DDiagram vp = (DDiagram) modelElement;
+ final DiagramDescription desc = vp.getDescription();
+ if (desc != null) {
+ final Layout layout = desc.getLayout();
+ if (layout instanceof GenericLayout) {
+ return DiagramUIPlugin.getPlugin().getLayoutProviderRegistry().get(((GenericLayout) layout).getID());
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/releng/org.eclipse.sirius.targets/modules/elk-0.3.tpd b/releng/org.eclipse.sirius.targets/modules/elk-0.3.tpd
new file mode 100644
index 0000000000..51d7df002e
--- /dev/null
+++ b/releng/org.eclipse.sirius.targets/modules/elk-0.3.tpd
@@ -0,0 +1,12 @@
+target "elk-0.3"
+
+with source, requirements
+
+location ELK-0.3 "http://download.eclipse.org/elk/updates/releases/0.3.0/" {
+ org.eclipse.elk.feature.feature.group lazy
+ org.eclipse.elk.feature.source.feature.group lazy
+ org.eclipse.elk.algorithms.feature.feature.group lazy
+ org.eclipse.elk.algorithms.feature.source.feature.group lazy
+ org.eclipse.elk.graphviz.feature.feature.group lazy
+ org.eclipse.elk.graphviz.feature.source.feature.group lazy
+} \ No newline at end of file
diff --git a/releng/org.eclipse.sirius.targets/sirius_neon.target b/releng/org.eclipse.sirius.targets/sirius_neon.target
index 01eecc4c1f..055604cbf5 100644
--- a/releng/org.eclipse.sirius.targets/sirius_neon.target
+++ b/releng/org.eclipse.sirius.targets/sirius_neon.target
@@ -41,6 +41,15 @@
<repository id="EEF-Latest" location="http://download.eclipse.org/modeling/emft/eef/updates/nightly/latest/neon"/>
</location>
<location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.eclipse.elk.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.source.feature.group" version="0.0.0"/>
+ <repository id="ELK-0.3" location="http://download.eclipse.org/elk/updates/releases/0.3.0/"/>
+ </location>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
<unit id="org.eclipse.sirius.common.interpreter" version="0.0.0"/>
<repository id="Sirius-Neon-Master" location="http://download.eclipse.org/sirius/updates/nightly/latest/neon/"/>
</location>
diff --git a/releng/org.eclipse.sirius.targets/sirius_neon.targetplatform b/releng/org.eclipse.sirius.targets/sirius_neon.targetplatform
index 68e77f2e89..d7451d0963 100644
--- a/releng/org.eclipse.sirius.targets/sirius_neon.targetplatform
+++ b/releng/org.eclipse.sirius.targets/sirius_neon.targetplatform
@@ -6,6 +6,7 @@ include "modules/shared-license.tpd"
include "modules/aql-nightly.tpd"
include "modules/acceleo-nightly.tpd"
include "modules/eef-nightly.tpd"
+include "modules/elk-0.3.tpd"
with source, requirements
diff --git a/releng/org.eclipse.sirius.targets/sirius_oxygen.target b/releng/org.eclipse.sirius.targets/sirius_oxygen.target
index 7d9a60bdb7..cf3cc7a2d4 100644
--- a/releng/org.eclipse.sirius.targets/sirius_oxygen.target
+++ b/releng/org.eclipse.sirius.targets/sirius_oxygen.target
@@ -41,6 +41,15 @@
<repository id="EEF-Latest" location="http://download.eclipse.org/modeling/emft/eef/updates/nightly/latest/neon"/>
</location>
<location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.eclipse.elk.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.source.feature.group" version="0.0.0"/>
+ <repository id="ELK-0.3" location="http://download.eclipse.org/elk/updates/releases/0.3.0/"/>
+ </location>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
<unit id="org.eclipse.sirius.common.interpreter" version="0.0.0"/>
<repository id="Sirius-Oxygen-Master" location="http://download.eclipse.org/sirius/updates/nightly/latest/oxygen/"/>
</location>
diff --git a/releng/org.eclipse.sirius.targets/sirius_oxygen.targetplatform b/releng/org.eclipse.sirius.targets/sirius_oxygen.targetplatform
index 01b6ec0904..658f274c34 100644
--- a/releng/org.eclipse.sirius.targets/sirius_oxygen.targetplatform
+++ b/releng/org.eclipse.sirius.targets/sirius_oxygen.targetplatform
@@ -6,6 +6,7 @@ include "modules/shared-license.tpd"
include "modules/aql-nightly.tpd"
include "modules/acceleo-nightly.tpd"
include "modules/eef-nightly.tpd"
+include "modules/elk-0.3.tpd"
with source, requirements
diff --git a/releng/org.eclipse.sirius.targets/sirius_photon.target b/releng/org.eclipse.sirius.targets/sirius_photon.target
index 937a2dc064..7042ec925d 100644
--- a/releng/org.eclipse.sirius.targets/sirius_photon.target
+++ b/releng/org.eclipse.sirius.targets/sirius_photon.target
@@ -41,6 +41,15 @@
<repository id="EEF-Latest" location="http://download.eclipse.org/modeling/emft/eef/updates/nightly/latest/neon"/>
</location>
<location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
+ <unit id="org.eclipse.elk.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.algorithms.feature.source.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.feature.group" version="0.0.0"/>
+ <unit id="org.eclipse.elk.graphviz.feature.source.feature.group" version="0.0.0"/>
+ <repository id="ELK-0.3" location="http://download.eclipse.org/elk/updates/releases/0.3.0/"/>
+ </location>
+ <location includeMode="planner" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="false" type="InstallableUnit">
<unit id="org.eclipse.sirius.common.interpreter" version="0.0.0"/>
<repository id="Sirius-Oxygen-Master" location="http://download.eclipse.org/sirius/updates/nightly/latest/oxygen/"/>
</location>
diff --git a/releng/org.eclipse.sirius.targets/sirius_photon.targetplatform b/releng/org.eclipse.sirius.targets/sirius_photon.targetplatform
index 57572b0860..f01997beb7 100644
--- a/releng/org.eclipse.sirius.targets/sirius_photon.targetplatform
+++ b/releng/org.eclipse.sirius.targets/sirius_photon.targetplatform
@@ -6,6 +6,7 @@ include "modules/shared-license.tpd"
include "modules/aql-nightly.tpd"
include "modules/acceleo-nightly.tpd"
include "modules/eef-nightly.tpd"
+include "modules/elk-0.3.tpd"
with source, requirements
location Sirius-Oxygen-Master "http://download.eclipse.org/sirius/updates/nightly/latest/oxygen/" {

Back to the top