blob: 3160361c64a6f14e69515b6b82db5096e10c5aab [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>Providing add functionality</title>
<link href="../book.css" rel="Stylesheet" type="text/css">
<link href="../code.css" rel="Stylesheet" type="text/css">
</head>
<body>
<h1>Providing Add Functionality</h1>
<p>A detailed description of the architecture and basic concepts of Graphiti can
be found <a href="graphiti-introduction.htm#Architecture_and_Basic_Concepts">here</a>.</p>
<h2>Architecture: Pictogram Model Linked With Domain Model</h2>
<p>In the terms of&nbsp; Graphiti “add” means to add a graphical representation
of an existing domain model object (= business object) to the diagram. What kinds
of business objects can be added to a diagram of a specific type is decided by the
add features delivered by the feature provider.</p>
<p>For our example the graphical representation of a EClass is illustrated in the
Figure. We want to see a rounded rectangle containing a separator like horizontal
line and above that line the name of the corresponding EClass.</p>
<p>&nbsp;</p>
<p>
<img alt="Graphical representation of a
EClass" height="117" src="visio/package-shape.gif" width="155"></p>
<p><strong>Figure: Graphical representation of a EClass</strong></p>
<p>&nbsp;</p>
<p>Graphiti supports a kind of linkage between elements of the domain model and
elements of the model defining the graphical representation – the so called <em>
Pictograms Model.</em> These links are called <em>pictogram links</em>. Each diagram
contains one container for all pictogram links – called <em>diagram link</em>.</p>
<p>You can see the linkage structure of the example in the Figure: Column one shows
the entity model of the graphical representation of exactly one EClass. A container
shape aggregates two child shapes (a container shape itself can be aggregated in
another container shape or in a diagram). All three shapes themselves aggregate
specific graphics algorithms, providing the complete information to allow the rendering
on a screen. Examples for this information are background color, foreground color,
size, position, visibility and line width. In our example we have a rounded rectangle
providing an additional corner radius, a polyline having defined end- and bendpoints
and a text label containing a text value.</p>
<p>&nbsp;</p>
<p><img alt="" height="350" src="visio/pictogram-model.png" width="557"></p>
<p><strong>Figure: Linkage structure example</strong></p>
<p>&nbsp;</p>
<p>The container shape and likewise the shape containing the text label are related
to a corresponding EClass. This relationship is realized through special link objects
(pictogram link) holding references to both sides: to the pictograms side and to
the business side.</p>
<h2>Creating an add feature</h2>
<p>In this example we want to enable the editor’s users to add EClasses to the diagram.
As a result it should be possible to drag an EClass from the tree and drop it on
the diagram. Therefore we have to create an add feature and make it available in
the feature provider.</p>
<p>An add feature has to implement the interface
<a href="../../../javadoc/org/eclipse/graphiti/features/IAddFeature.html">IAddFeature</a>.
Instead of implementing it directly it should extend one of the available base classes.
In this example we extend the base class
<a href="../../../javadoc/org/eclipse/graphiti/features/impl/AbstractAddShapeFeature.html">
AbstractAddShapeFeature</a>.</p>
<p>In this case we have to implement/overwrite two methods:</p>
<ul>
<li>The method
<a href="../../../javadoc/org/eclipse/graphiti/func/IAdd.html#canAdd(org.eclipse.graphiti.features.context.IAddContext)">
canAdd</a> has to check the given context and therefore it decides if a business
object can be added.</li>
<li>The method
<a href="../../../javadoc/org/eclipse/graphiti/func/IAdd.html#add(org.eclipse.graphiti.features.context.IAddContext)">
add</a> finally has to create the pictogram structure described above and has
to establish the linkage to the business object. Additionally we have to create
graphics algorithms and place them at the appropriate location (get location
from given context). Additionally, the name of the EClass has to be set as the
text label’s value. </li>
</ul>
<p>You can see the complete implementation of the add feature here:</p>
<!-- Begin code ------------------------------------------------------------------------------- -->
<p>&nbsp;</p>
<div class="literallayout">
<div class="incode">
<p class="code"><span class="keyword">package </span>org.eclipse.graphiti.examples.tutorial.features;<br>&nbsp;<br>
<span class="keyword">public class</span> TutorialAddEClassFeature
<span class="keyword">extends </span>AbstractAddShapeFeature {<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant
<span class="string"><em>CLASS_TEXT_FOREGROUND</em></span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(51, 51, 153);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant
<span class="string"><em>CLASS_FOREGROUND</em></span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(255, 102, 0);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">private static final</span> IColorConstant
<span class="string"><em>CLASS_BACKGROUND</em></span> =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">new </span>ColorConstant(255, 204, 153);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>TutorialAddEClassFeature(IFeatureProvider
fp) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">super</span>(fp);<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>boolean canAdd(IAddContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">//
check if user wants to add a EClass</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if </span>(context.getNewObject()
<span class="keyword">instanceof </span>EClass) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// check if user wants to add to a diagram</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">if (</span>context.getTargetContainer()
<span class="keyword">instanceof </span>Diagram) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return true</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;return false</span>;<br>&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;
<span class="keyword">public </span>PictogramElement add(IAddContext context)
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; EClass addedClass = (EClass)
context.getNewObject();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Diagram
targetDiagram = (Diagram) context.getTargetContainer();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// CONTAINER SHAPE WITH ROUNDED RECTANGLE</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IPeCreateService peCreateService = Graphiti.getPeCreateService();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ContainerShape containerShape =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
peCreateService.createContainerShape(targetDiagram,
<span class="keyword">true</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// define a default size for the shape</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">int </span>width = 100;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">int </span>height = 50; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
IGaService gaService = Graphiti.getGaService();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
RoundedRectangle roundedRectangle =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createRoundedRectangle(containerShape, 5, 5);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setForeground(manageColor(<em class="string">CLASS_FOREGROUND</em>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setBackground(manageColor(<span class="string"><em>CLASS_BACKGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
roundedRectangle.setLineWidth(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(roundedRectangle,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
context.getX(), context.getY(), width, height);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// if added Class has no resource we add it to the
resource <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// of the diagram<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// in a real scenario the business model would have its own resource</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">&nbsp;if</span> (addedClass.eResource() ==
<span class="keyword">null</span>) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
getDiagram().eResource().getContents().add(addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(containerShape, addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// SHAPE WITH LINE</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create shape for line</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Shape shape = peCreateService.createShape(containerShape,
<span class="keyword">false</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Polyline polyline =<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.createPolyline(shape, <span class="keyword">new int</span>[] {
0, 20, width, 20 });<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
polyline.setForeground(manageColor(<span class="string"><em>CLASS_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
polyline.setLineWidth(2);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// SHAPE WITH TEXT</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create shape for text</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Shape shape = peCreateService.createShape(containerShape,
<span class="keyword">false</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create and set text graphics algorithm</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Text text = gaService.createDefaultText(getDiagram(), shape,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
addedClass.getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setForeground(manageColor(<span class="string"><em>CLASS_TEXT_FOREGROUND</em></span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setHorizontalAlignment(Orientation.<span class="string"><em>ALIGNMENT_CENTER</em></span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.setVerticalAlignment(Orientation.<span class="string"><em>ALIGNMENT_CENTER</em></span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
text.getFont().setBold(<span class="keyword">true</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
gaService.setLocationAndSize(text, 0, 0, width, 20);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="comment">// create link and wire it</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
link(shape, addedClass);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span class="keyword">return </span>containerShape;<br>&nbsp;&nbsp;&nbsp;
}<br>}<br>&nbsp; </p>
</div>
</div>
<p>&nbsp;</p>
<!-- End code ------------------------------------------------------------------------------- -->
<h2>Test: Add a EClass</h2>
<p class="Note">Note: if the project wizard for a &quot;<a href="example-projects.htm">New
Graphiti Sample Project</a>&quot; does not work correctly and you can not test the add
feature as described below, please continue with the next chapter and
<a href="create-feature.htm">provide create functionality</a>. That will allow to
test the add feature directly in the diagram.</p>
<p>Now we can start the editor again. It should be possible to drop an EClass from
the tree of the Graphiti &quot;Test&quot; project into the diagram Test-1. </p>
<p>&nbsp;</p>
<p><img alt="" height="302" src="visio/predefined-eclass.png" width="788"></p>
<p>&nbsp;</p>
<p><strong>Figure: Add PredefinedEClass to the editor</strong></p>
<p>&nbsp;</p>
<p>Without any further implementations it should be possible to move the EClass
shapes around, resize them, remove them (context menu) and even delete them.</p>
<p>&nbsp;</p>
</body>
</html>